How to perform action when QCalendarWidget popup closes? - python

I am using a QDateEdit widget with QDateEdit.setCalendarPopup(True). I am trying to connect a slot to the event when the calendar popup closes. See my example below for my attempts so far, found in MyCalendarWidget. None of my attempts so far have worked. What can I do to perform an action every time the calendar widget popup closes, not only when the date is changed?
from PyQt4 import QtGui, QtCore
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args):
super(MainWindow,self).__init__(*args)
self._date = QtGui.QDateEdit()
self._date.setCalendarPopup(True)
self._date.setCalendarWidget(MyCalendarWidget())
self.setCentralWidget(self._date)
class App(QtGui.QApplication):
def __init__(self, *args):
super(App,self).__init__(*args)
self.main = MainWindow()
self.connect(self, QtCore.SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
def byebye( self ):
self.exit(0)
class MyCalendarWidget(QtGui.QCalendarWidget):
def __init__(self, parent=None):
print("mycal initialized")
super(MyCalendarWidget, self).__init__(parent)
self.installEventFilter(self)
self._many = 2
self._many2 = 2
def focusInEvent(self, event):
print('-'*self._many + 'focus in')
if self._many == 2:
self._many = 4
else:
self._many = 2
super(MyCalendarWidget, self).focusInEvent(event)
def focusOutEvent(self, event):
print('-'*self._many2+'focus out')
if self._many2 == 2:
self._many2 = 4
else:
self._many2 = 2
super(MyCalendarWidget, self).focusOutEvent(event)
def closeEvent(self, event):
print('close')
super(MyCalendarWidget, self).closeEvent(event)
def mouseReleaseEvent(self, event):
print('mouse')
super(MyCalendarWidget, self).mouseReleaseEvent(event)
def main(args):
global app
app = App(args)
app.exec_()
if __name__ == "__main__":
main(sys.argv)

Figured it out - turns out I need to use the clicked signal in QCalendarWidget. This removes the need to sub-class QCalendarWidget as well.
from PyQt4 import QtGui, QtCore
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args):
super(MainWindow,self).__init__(*args)
self._date = QtGui.QDateEdit()
self._date.setCalendarPopup(True)
calendar = self._date.calendarWidget()
calendar.clicked.connect(self._clicked)
self.setCentralWidget(self._date)
def _clicked(self, date):
print('clicked')
class App(QtGui.QApplication):
def __init__(self, *args):
super(App,self).__init__(*args)
self.main = MainWindow()
self.connect(self, QtCore.SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
def byebye( self ):
self.exit(0)
def main(args):
global app
app = App(args)
app.exec_()
if __name__ == "__main__":
main(sys.argv)

Related

How can i capture a mouse clicks onto the main Window in a child class

I would like to capture mouse clicks onto the MainWindow in a child class of the application.
I've tried the following but without success:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from abc import ABCMeta, abstractmethod
class BaseView(object):
def __init__(self,parent, page=None):
self.parent = parent
self.page = page
#abstractmethod
def preprare_view(self):
pass
#abstractmethod
def clean_up_view(self):
pass
class FooView(BaseView):
def __init__(self, parent, page):
super(FooView, self).__init__(parent, page)
self.parent = parent
def mousePressEvent(self, QMouseEvent):
print(parent.QMouseEvent.pos())
def mouseReleaseEvent(self, QMouseEvent):
cursor = QtGui.QCursor()
print(parent.cursor.pos())
class Example(QtWidgets.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.foo = "fooview"
self.Foo = FooView(self,self.foo)
qbtn = QtWidgets.QPushButton('Quit', self)
qbtn.resize(qbtn.sizeHint())
qbtn.move(50, 50)
self.setGeometry(0, 0, 1024, 768)
self.setWindowTitle('Quit button')
self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint)
self.show()
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I'm wondering how I can capture the mouse clicks in the FooView child class - is that even possible?
There is terminology that the OP uses that is confusing, for example FooView is a child class of BaseView but that has nothing to do with Qt so it is irrelevant for this case so I will omit that class and show the example of how another class can obtain information about the click event of a widget.
The logic is to create a class that inherits from QObject and apply an event filter to the other widget, then override the eventFilter method where the events of the widget are obtained.
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class MouseObserver(QtCore.QObject):
def __init__(self, widget):
super(MouseObserver, self).__init__(widget)
self._widget = widget
self.widget.installEventFilter(self)
#property
def widget(self):
return self._widget
def eventFilter(self, obj, event):
if obj is self.widget:
if event.type() == QtCore.QEvent.MouseButtonPress:
print(event.pos(), QtGui.QCursor.pos())
elif event.type() == QtCore.QEvent.MouseButtonRelease:
print(event.pos(), QtGui.QCursor.pos())
return super(MouseObserver, self).eventFilter(obj, event)
class Example(QtWidgets.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.observer = MouseObserver(self)
qbtn = QtWidgets.QPushButton("Quit", self)
qbtn.resize(qbtn.sizeHint())
qbtn.move(50, 50)
self.setGeometry(0, 0, 1024, 768)
self.setWindowTitle("Quit button")
self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint)
self.show()
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Python PyQt5 Add List Item from another Py-File

when clicking a button in the PyQt5 Ui iam starting a mitmproxy. When the proxy is started, i try to change a listWidget with Data from the Proxy.
main.py
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
from MainWindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.pushButton.clicked.connect(self.Start)
def Start(self):
x = threading.Thread(target=self.StartMITM)
x.start()
def StartMITM(self):
os.system("mitmweb -s mitmproxy.py -q --no-web-open-browser")
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
mitmproxy.py - this is the error part
from mitmproxy import http
from main import MainWindow
def response(flow):
MainWindow.listWidget.addItem(flow.request.pretty_url)
Can I connect to the Widgets from another File?
It has 2 independent processes: The GUI and the mitmproxy script. And communicating both processes does not imply importing modules since you would be creating another widget, also objects should not be accessed through classes (I recommend you check your basic python notes).
In this the solution is to use some Inter process communication (IPC), in this case you can use Qt Remote Objects (QtRO):
main.py
from functools import cached_property
from PyQt5 import QtCore, QtRemoteObjects, QtWidgets
class Bridge(QtCore.QObject):
messageChanged = QtCore.pyqtSignal(str)
#QtCore.pyqtSlot(str)
def add_message(self, message):
self.messageChanged.emit(message)
class MitmwebManager(QtCore.QObject):
logChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
# self.process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self.process.readyReadStandardOutput.connect(self.handle_log)
self.process.setProgram("mitmweb")
#cached_property
def process(self):
return QtCore.QProcess()
def start(self, arguments):
self.process.setArguments(arguments)
self.process.start()
def stop(self):
self.process.kill()
def handle_log(self):
data = self.process.readAllStandardOutput()
codec = QtCore.QTextCodec.codecForName("UTF-8")
message = codec.toUnicode(data)
self.logChanged.emit(message)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.button = QtWidgets.QPushButton("Start", checkable=True)
self.listwidget = QtWidgets.QListWidget()
self.logview = QtWidgets.QPlainTextEdit(readOnly=True)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(self.button, 0, 0, 1, 2)
lay.addWidget(self.listwidget, 1, 0)
lay.addWidget(self.logview, 1, 1)
self.register_node = QtRemoteObjects.QRemoteObjectRegistryHost(
QtCore.QUrl("local:registry")
)
self.source_node = QtRemoteObjects.QRemoteObjectHost(
QtCore.QUrl("local:replica"), QtCore.QUrl("local:registry")
)
self.source_node.enableRemoting(self.bridge, "bridge")
self.button.toggled.connect(self.handle_toggled)
self.mitmweb.logChanged.connect(self.handle_log_changed)
self.bridge.messageChanged.connect(self.handle_message_changed)
self.resize(640, 480)
#cached_property
def mitmweb(self):
return MitmwebManager()
#cached_property
def bridge(self):
return Bridge()
def handle_toggled(self, checked):
if checked:
self.mitmweb.start(["-s", "script.py", "--no-web-open-browser"])
self.button.setText("Stop")
else:
self.mitmweb.stop()
self.button.setText("Start")
def handle_log_changed(self, message):
self.logview.insertPlainText(message)
def closeEvent(self, event):
super().closeEvent(event)
self.mitmweb.stop()
def handle_message_changed(self, message):
item = QtWidgets.QListWidgetItem(message)
self.listwidget.addItem(item)
def main():
app = QtWidgets.QApplication([])
view = MainWindow()
view.show()
app.exec_()
if __name__ == "__main__":
main()
script.py
from mitmproxy import http
from PyQt5 import QtCore, QtRemoteObjects
class Bridge(QtCore.QObject):
def __init__(self, bridge, parent=None):
super().__init__(parent)
self._message = ""
self._bridge = bridge
self.bridge.initialized.connect(self.handle_initialized)
#property
def bridge(self):
return self._bridge
#property
def message(self):
return self._message
def send_message(self, message):
self._message = message
#QtCore.pyqtSlot()
def handle_initialized(self):
self.bridge.add_message(self._message)
QtCore.QTimer.singleShot(0, QtCore.QCoreApplication.quit)
def send_qt(message):
qt_app = QtCore.QCoreApplication([])
replica_node = QtRemoteObjects.QRemoteObjectNode(QtCore.QUrl("local:registry"))
replica_bridge = replica_node.acquireDynamic("bridge")
bridge = Bridge(replica_bridge)
bridge.send_message(message)
qt_app.exec_()
def response(flow):
send_qt(flow.request.pretty_url)

Pyqt5 QMDIarea subclass with a custom signal on close

I need to create a custom signal on Qmdisubwindow close. In other word, when I closed any subwindow, a signal is emitted with the name of that window being closed. Below is my trail, but seems not right. Error occurs as:
a subwindow already created without calling
add subwindow option is not working
closable action is not working
Hope you can show me how to fix it.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MyMdi(QMdiSubWindow):
sigClosed = pyqtSignal(str)
def __init__(self, parent=None):
super(MyMdi, self).__init__(parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
name = name
self.sigClosed.emit('{} is close'.format(name))
QMdiSubWindow.closeEvent(self, event)
class MainWindow(QMainWindow):
count = 0
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.mdi = MyMdi()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
file.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI demo")
# my signal
self.mdi.sigClosed.connect(self.windowclosed)
#pyqtSlot(str)
def windowclosed(self, text):
print(text)
def windowaction(self, q):
if q.text() == "New":
MainWindow.count = MainWindow.count+1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()
def main():
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You have an initial error: a QMdiSubWindow must be inside a QMdiArea but there is none in your code.
On the other hand, the idea of subclassing is good but you have several drawbacks:
You are not using it initially since there is no QMdiArea, if you execute the QAction then your application will be closed because a QMdiSubWindow does not have any method called addSubWindow.
The QMdiSubWindow does not have an attribute called name, you must use windowTitle.
class MdiSubWindow(QMdiSubWindow):
sigClosed = pyqtSignal(str)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
self.sigClosed.emit(self.windowTitle())
QMdiSubWindow.closeEvent(self, event)
class MainWindow(QMainWindow):
count = 0
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
file.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI demo")
#pyqtSlot(str)
def windowclosed(self, text):
print(text)
def windowaction(self, q):
if q.text() == "New":
MainWindow.count = MainWindow.count + 1
sub = MdiSubWindow()
sub.setWidget(QTextEdit())
sub.setAttribute(Qt.WA_DeleteOnClose)
sub.setWindowTitle("subwindow" + str(MainWindow.count))
sub.sigClosed.connect(self.windowclosed)
self.mdi.addSubWindow(sub)
sub.show()

error when close with effect fade window pyqt5

I have a bit when try change new window UI with effect fade. I added effect on closeEvent of mainwindow but it doen't work.
This is my code:
library used:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic
load ui
uifile_1 = 'home.ui'
form_1, base_1 = uic.loadUiType(uifile_1)
uifile_2 = 'plate.ui'
form_2, base_2 = uic.loadUiType(uifile_2)
Class Home page:
class HomePage(base_1, form_1):
def __init__(self):
super(base_1,self).__init__()
self.setupUi(self)
#add button for click next page
self.btn_start = QPushButton(self)
self.btn_start.clicked.connect(self.change)
self._heightMask = self.height()
self.animation = QPropertyAnimation(self, b"heightPercentage")
self.animation.setDuration(1000)
self.animation.setStartValue(self.height())
self.animation.setEndValue(-1)
self.animation.finished.connect(self.close)
self.isStarted = False
def change(self):
self.plate = PlatePage()
self.plate.show()
self.close()
#pyqtProperty(int)
def heightMask(self):
return self._heightMask
#heightMask.setter
def heightPercentage(self, value):
self._heightMask = value
rect = QRect(0, 0, self.width(), self.heightMask)
self.setMask(QRegion(rect))
def closeEvent(self, event):
if not self.isStarted:
self.animation.start()
self.isStarted = True
event.ignore()
else:
self.closeEvent(self, event)
Class Plate Page
class PlatePage(base_2, form_2):
def __init__(self):
super(base_2, self).__init__()
self.setupUi(self)
self.show()
Please have a look and give me some solution.
Thank You
Try it:
from PyQt5.QtCore import QPropertyAnimation, QThread
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
self.resize(400, 400)
layout = QVBoxLayout(self)
layout.addWidget(QPushButton('Button', self))
self.animation = QPropertyAnimation(self, b'windowOpacity')
self.animation.setDuration(1000)
self.isStarted = False
self.doShow()
def doShow(self):
try:
self.animation.finished.disconnect(self.close)
except:
pass
self.animation.stop()
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.start()
def closeEvent(self, event):
if not self.isStarted:
self.animation.stop()
self.animation.finished.connect(self.close)
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.animation.start()
self.isStarted = True
event.ignore()
else:
event.accept()
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

pyQt Hover event with Svg image

I've been working on this for some time now and I can't figure out what I'm doing wrong. I hope someone here can help.
I'm trying to get hover events to work when I mouse over an Svg item that's in a QGraphicsScene. Here's the code that I've been playing with.
#!/usr/bin/python
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSvg import *
class Main(QWidget):
def __init__(self):
super(Main, self).__init__()
hbox = QHBoxLayout()
self.setLayout(hbox)
self.view = MyView(self)
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
hbox.addWidget(self.view)
class MyView(QGraphicsView):
def __init__(self, parent):
super(MyView, self).__init__(parent)
self.parent = parent
def mousePressEvent(self, event):
super(MyView, self).mousePressEvent(event)
test = MySvg()
self.parent.scene.addItem(test.image)
class MySvg(QGraphicsSvgItem):
def __init__(self):
super(MySvg, self).__init__()
self.image = QGraphicsSvgItem('ubuntu.svg')
self.image.setFlags(QGraphicsItem.ItemIsSelectable|
QGraphicsItem.ItemIsMovable)
self.setAcceptsHoverEvents(True)
def hoverEnterEvent(self, event):
print 'Enter'
def hoverLeaveEvent(self, event):
print 'Leave'
def hoverMoveEvent(self, event):
print 'Moving'
def runMain():
app = QApplication(sys.argv)
ex = Main()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
runMain()
Hope someone can help.
You are monitoring hover events for MySvg but you are adding another QGraphicsSvgItem to the view that is just an instance (MySvg.image) in MySvg. Your MySvg is not even in the view. Try like this:
#!/usr/bin/python
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSvg import *
class Main(QWidget):
def __init__(self):
super(Main, self).__init__()
hbox = QHBoxLayout()
self.setLayout(hbox)
self.view = MyView(self)
self.scene = QGraphicsScene()
self.view.setScene(self.scene)
hbox.addWidget(self.view)
class MyView(QGraphicsView):
def __init__(self, parent):
super(MyView, self).__init__(parent)
self.parent = parent
def mousePressEvent(self, event):
super(MyView, self).mousePressEvent(event)
test = MySvg()
self.parent.scene.addItem(test)
class MySvg(QGraphicsSvgItem):
def __init__(self):
super(MySvg, self).__init__('ubuntu.svg')
self.setFlags(QGraphicsItem.ItemIsSelectable|
QGraphicsItem.ItemIsMovable)
self.setAcceptsHoverEvents(True)
def hoverEnterEvent(self, event):
print 'Enter'
def hoverLeaveEvent(self, event):
print 'Leave'
def hoverMoveEvent(self, event):
print 'Moving'
def runMain():
app = QApplication(sys.argv)
ex = Main()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
runMain()

Categories

Resources