Either I don't understand completely how Qt's event propagation works or something, but I cannot understand why exactly closeEvent is not being called both for QPushButton-derived class and for QWidget-derived one itself.
Shouldn't wid.closeEvent() trigger closeEvents of all children widgets?
#!/bin/env python
# -*- coding: utf-8 -*-
import sys, os
from Qt.QtCore import *
from Qt.QtWidgets import *
from Qt.QtGui import *
class butt(QPushButton):
def __init__(self, parent, name='Button'):
super(self.__class__, self).__init__(parent)
self.name = name
def closeEvent(self, e):
print('butt closeevent')
e.accept()
class wid(QWidget):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.initUI()
def initUI(self):
#self.setAttribute(Qt.WA_DeleteOnClose)
self.vl = QVBoxLayout(self)
self.button = butt(self)
self.button.setText('test1')
self.vl.addWidget(self.button)
self.button.clicked.connect(QCoreApplication.quit)
def closeEvent(self, e):
print('wid closeevent')
e.accept()
def show():
app = QApplication(sys.argv)
win = QMainWindow()
widget = wid(win)
win.setCentralWidget(widget)
win.show()
app.exec_()
if __name__ == "__main__":
show()
I'm expecting to see 2 lines
wid closeevent
butt closeevent
as an output, but I see nothing. Why closeEvent it not being called for them?
In the following examples when you press the button visually you will observe the same behavior: the window will close, but we see the difference, in the first one it is called closeEvent(), and in the second one it is not.
Example1:
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("button closeEvent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
button = Button(text="Press me")
button.clicked.connect(button.close)
button.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Example2:
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("button closeEvent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
button = Button(text="Press me")
button.clicked.connect(QtCore.QCoreApplication.quit)
button.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Why do not you call closeEvent when you call QCoreApplication::quit?
Because this method is used to exit the event loop of Qt, and if there is no event loop the events(QCloseEvent) do not work.
When a widget is closed, the children widget is not closed, that is, only if a widget is closed, only its own closeEvent will be called. So if you want the closeevent of the widget to be called, call your method close.
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def __init__(self, name="Button", parent=None):
super(Button, self).__init__(parent)
self.m_name = name
def closeEvent(self, event):
print("button closeEvent")
event.accept()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.initUI()
def initUI(self):
vl = QtWidgets.QVBoxLayout(self)
button = Button()
button.setText("test1")
vl.addWidget(button)
button.clicked.connect(self.close)
def closeEvent(self, event):
print("Widget closeevent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow()
widget = Widget()
w.setCentralWidget(widget)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
In the previous example depending on how you interact with the widget you will get the following behavior:
If you press the button the widget will close so it will be called closeEvent, and will not call the closeEvent of the button because even your child is not closing it.
If you press the "X" button in the window it will not be called the closeEvent of the widget but the QMainWindow, the explanation is the same as the previous one.
Conclusions:
Each type of event has its own workflow, some events are only received by the widget and not by the children, while others send the information to the children.
The close method uses the event loop to notify that the widget is to be closed, but QCoreApplication::quit() terminates the event loop.
Update:
why wid.closeEvent is not called when user pressing "X" button on Qt window? Aren't main window supposed to call closeEvent on all it's children widgets and then destroy them properly?
No, one thing is the closing of a widget and another thing is the destruction of the widget, it can be destroyed without closing and closing the window does not involve destroying the object.
As already pointed out closing a window does not imply deleting it, there may be other windows open, but if the last QApplication window is closed by default the eventloop that implies the destruction of the widget will be terminated which does not necessarily imply calling the close method.
To be understood, let's use the following code:
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("closeEvent Button")
super(Button, self).closeEvent(event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button_quit = Button(
text="quit",
clicked=QtCore.QCoreApplication.quit
)
button_close = Button(
text="close",
clicked=self.close
)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button_quit)
lay.addWidget(button_close)
def closeEvent(self, event):
print("closeEvent Widget")
super(Widget, self).closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
There are 2 buttons, in the case of the first button that calls QCoreApplication::quit() that will end the eventloop so all the widgets will be destroyed, and in that case no closeEvent will be called, in the case of the second button it will be call near the window so it will call its closeEvent but not the closeEvents of its children.
my actual problem is that I have saveUI() func in closeEvent, and it's not being called upon widgets hierarchical destruction on window close
If you want the closeEvent method to be called hierarchically then you must call the close method manually since Qt does not design it that way. In the next part there is an example:
from PyQt5 import QtCore, QtGui, QtWidgets
class PushButton(QtWidgets.QPushButton):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent PushButton")
super(PushButton, self).closeEvent(event)
class LineEdit(QtWidgets.QLineEdit):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent LineEdit")
super(LineEdit, self).closeEvent(event)
class ComboBox(QtWidgets.QComboBox):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent ComboBox")
super(ComboBox, self).closeEvent(event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button_close = PushButton(text="close", clicked=self.close)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button_close)
lay.addWidget(LineEdit())
lay.addWidget(ComboBox())
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent Widget")
super(Widget, self).closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Related
I am trying to implement a QMainWindow with centralWidget and dockWidget. When the user resize the dock widget I want resizeEvent to be called for the dock widget and some values to be returned. I have implemented the resizeEvent for the complete QMainWindow and it is working fine. How can i call resizeEvent for the dockWidget which is a Qwidget without making another class which will inherit from Qwidget and implement the resizeEvent there and afterwards to create an object in QMainwindow. The first given example is working just fine.
class ui(QMainWindow):
def __init__(self):
super().__init__()
self.bottom_dock_widget = DockWidget('Results')
self.addDockWidget(Qt.BottomDockWidgetArea, self.bottom_dock_widget)
self.resize(500, 500)
def resizeEvent(self, event):
print('mainWindow')
self.update()
class DockWidget(QDockWidget):
def __init__(self, name, image_view):
super().__init__()
self.setWindowTitle(name)
def resizeEvent(self, event):
print('in Dock')
self.update()
Is there a way to be able to implement the example like this:
class ui(QMainWindow):
def __init__(self):
super().__init__()
self.bottom_dock_widget = QDockWidget('Results')
self.addDockWidget(Qt.BottomDockWidgetArea, self.bottom_dock_widget)
self.resize(500, 500)
but to be able to call resizeEvent only for the dock widget
def resizeEvent(self, event):
print('dock')
self.update()
like on c++ with the scope
def bottom_dock_widget :: resizeEvent(self):
If you want to hear the resize event of a widget it is not necessary to override the resizeEvent() method since it is enough to install an event filter analyzed the QEvent::Resize event
import sys
from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtWidgets import QApplication, QDockWidget, QMainWindow
class UI(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.bottom_dock_widget = QDockWidget("Results")
self.bottom_dock_widget.installEventFilter(self)
self.addDockWidget(Qt.BottomDockWidgetArea, self.bottom_dock_widget)
self.resize(500, 500)
def eventFilter(self, obj, event):
if obj is self.bottom_dock_widget and event.type() == QEvent.Resize:
print("dock")
return super().eventFilter(obj, event)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = UI()
w.show()
sys.exit(app.exec_())
I am new to PyQt. I designed a form in QtDeveloper which have three controls. One push button, one combo box and one line edit. The name of the line edit widget in my ui form is myLineEdit. I want to know which Qwidget got focus (QLineEdit or QComboBox). I implement the code obtained from internet. When the code run, a separate line edit is created and it works fine. But I want to give the focusInEvent to myLineEdit widget created in the .ui form. My code is given. Please help.
class MyLineEdit(QtGui.QLineEdit):
def __init__(self, parent=None):
super(MyLineEdit, self).__init__(parent)
def focusInEvent(self, event):
print 'focus in event'
self.clear()
QLineEdit.focusInEvent(self, QFocusEvent(QEvent.FocusIn))
class MainWindow(QtGui.QMainWindow,Ui_MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.myLineEdit = MyLineEdit(self)
You must implement the eventFilter method and enable this property to the widgets that are needed with:
{your widget}.installEventFilter(self)
The eventFilter method has as information the object and type of event.
Example
import sys
from PyQt5 import uic
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import QApplication, QWidget
uiFile = "widget.ui" # Enter file here.
Ui_Widget, _ = uic.loadUiType(uiFile)
class Widget(QWidget, Ui_Widget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
self.setupUi(self)
self.lineEdit.installEventFilter(self)
self.pushButton.installEventFilter(self)
self.comboBox.installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == QEvent.FocusIn:
if obj == self.lineEdit:
print("lineedit")
elif obj == self.pushButton:
print("pushbutton")
elif obj == self.comboBox:
print("combobox")
return super(Widget, self).eventFilter(obj, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Ouput:
lineedit
pushbutton
combobox
pushbutton
lineedit
I'm using Python 2.7 and PyQT4.
I want to hide a modal QDialog instance and later on show it again. However, when dialog.setVisible(false) is called (e.g., using QTimer), the dialog.exec_() call returns (with QDialog.Rejected return value).
However, according to http://pyqt.sourceforge.net/Docs/PyQt4/qdialog.html#exec, the _exec() call should block until the user closes the dialog.
Is there a way to hide the dialog without _exec() returning?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from PyQt4 import QtGui, QtCore
class MyDialog(QtGui.QDialog):
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
def closeEvent(self, QCloseEvent):
print "Close Event"
def hideEvent(self, QHideEvent):
print "Hide Event"
class MyWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle("Main Window")
button = QtGui.QPushButton("Press me", self)
button.clicked.connect(self.run_dialog)
def run_dialog(self):
self.dialog = MyDialog(self)
self.dialog.setModal(True)
self.dialog.show()
QtCore.QTimer.singleShot(1000, self.hide_dialog)
status = self.dialog.exec_()
print "Dialog exited with status {}".format(status), "::", QtGui.QDialog.Accepted, QtGui.QDialog.Rejected
def hide_dialog(self):
self.dialog.setVisible(False)
# self.dialog.setHidden(True)
if __name__ == '__main__':
app = QtGui.QApplication([])
w = MyWindow()
w.show()
sys.exit(app.exec_())
PS1: This code prints the following output:
Hide Event
Dialog exited with status 0 :: 1 0
(the close event is not called).
PS2: For context, I'm trying to implement a SystemTrayIcon that allows to hide and restore a QMainWindow (this part is fine) and possibly its modal QDialog without closing the dialog.
Thanks!
You can bypass the normal behaviour of QDialog.setVisible (which implicitly closes the dialog), by calling the base-class method instead:
def hide_dialog(self):
# self.dialog.setVisible(False)
QtGui.QWidget.setVisible(self.dialog, False)
However, it might be preferrable to connect to the dialog's finished() signal, rather than using exec(), and explicitly reject() the dialog in its closeEvent.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from PyQt4 import QtGui, QtCore
class MyDialog(QtGui.QDialog):
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
layout = QtGui.QHBoxLayout(self)
for title, slot in ('Ok', self.accept), ('Cancel', self.reject):
button = QtGui.QPushButton(title)
button.clicked.connect(slot)
layout.addWidget(button)
def closeEvent(self, QCloseEvent):
print "Close Event"
self.reject()
def hideEvent(self, QHideEvent):
print "Hide Event"
class MyWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle("Main Window")
button = QtGui.QPushButton("Press me", self)
button.clicked.connect(self.run_dialog)
def run_dialog(self):
self.dialog = MyDialog(self)
self.dialog.finished.connect(self.dialog_finished)
self.dialog.setModal(True)
self.dialog.show()
QtCore.QTimer.singleShot(3000, self.dialog.hide)
def dialog_finished(self, status):
print "Dialog exited with status:", status
if __name__ == '__main__':
app = QtGui.QApplication([])
w = MyWindow()
w.show()
sys.exit(app.exec_())
In case anyone is interested, the following code provides a quick-and-dirty way to circunvent the problem for me, although it does not really answer the question.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Extension of the QDialog class so that exec_() does not exit when hidden.
Dialogs inheriting will only exit exec_() via close(), reject() or accept()
"""
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class HideableQDialog(QDialog):
def __init__(self, *args, **kwargs):
super(HideableQDialog, self).__init__(*args, **kwargs)
self._mutex = QMutex()
self._is_finished = False
self._finished_condition = QWaitCondition()
self.finished.connect(self._finish_dialog)
def _finish_dialog(self):
self._is_finished = True
self._finished_condition.wakeOne()
def close(self):
super(HideableQDialog, self).close()
self._finish_dialog()
def reject(self):
super(HideableQDialog, self).reject()
self._finish_dialog()
def accept(self):
super(HideableQDialog, self).accept()
self._finish_dialog()
def exec_(self):
status = super(HideableQDialog, self).exec_()
self._mutex.lock()
condition_succedeed = False
while not condition_succedeed and not self._is_finished:
condition_succedeed = self._finished_condition.wait(self._mutex, 10)
QApplication.processEvents()
self._mutex.unlock()
First of all, similar questions have been answered before, yet I need some help with this one.
I have a window which contains one button (Class First) and I want on pressed, a second blank window to be appeared (Class Second).
I fiddled with the code copied from this question: PyQT on click open new window, and I wrote this code:
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import sys
import design1, design2
class Second(QtGui.QMainWindow, design2.Ui_MainWindow):
def __init__(self, parent=None):
super(Second, self).__init__(parent)
self.setupUi(self)
class First(QtGui.QMainWindow, design1.Ui_MainWindow):
def __init__(self, parent=None):
super(First, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.dialog = Second(self)
def on_pushButton_clicked(self):
self.dialog.exec_()
def main():
app = QtGui.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
but on_pressed, this error message appears:
AttributeError: 'Second' object has no attribute 'exec_'
(design1 and design2 have been derived from the Qt designer.)
Any thought would be appreciated.
Here I'm using the show method.
Here is a working example (derived from yours):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import sys
class Second(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Second, self).__init__(parent)
class First(QtGui.QMainWindow):
def __init__(self, parent=None):
super(First, self).__init__(parent)
self.pushButton = QtGui.QPushButton("click me")
self.setCentralWidget(self.pushButton)
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.dialog = Second(self)
def on_pushButton_clicked(self):
self.dialog.show()
def main():
app = QtGui.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If you need a new window every time you click the button, you can change the code that the dialog is created inside the on_pushButton_clicked method, like so:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import sys
class Second(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Second, self).__init__(parent)
class First(QtGui.QMainWindow):
def __init__(self, parent=None):
super(First, self).__init__(parent)
self.pushButton = QtGui.QPushButton("click me")
self.setCentralWidget(self.pushButton)
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.dialogs = list()
def on_pushButton_clicked(self):
dialog = Second(self)
self.dialogs.append(dialog)
dialog.show()
def main():
app = QtGui.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I couldn't understand the connectSlotsByName() method which is predominently used by pyuic4.. As far the class is single in a PyQt file it's ok since we can use self which will be associated with a single object throughout.. But when we try to use various classes from different files the problem and the need to use connectSlotsByName() arises.. Here's what i encountered which is weird..
I created a stacked widget..
I placed my first widget on it.. It
has a button called "Next >".
On clicking next it hides the current
widget and adds another widget which has the "click me" button..
The problem here is the click event for "click me" button in second is not captured.. It's a minimal example that i can give for my original problem.. Please help me..
This is file No.1..(which has the parent stacked widget and it's first page). On clicking next it adds the second page which has "clickme" button in file2..
from PyQt4 import QtCore, QtGui
import file2
class Ui_StackedWidget(QtGui.QStackedWidget):
def __init__(self,parent=None):
QtGui.QStackedWidget.__init__(self,parent)
self.setObjectName("self")
self.resize(484, 370)
self.setWindowTitle(QtGui.QApplication.translate("self", "stacked widget", None, QtGui.QApplication.UnicodeUTF8))
self.createWidget1()
def createWidget1(self):
self.page=QtGui.QWidget()
self.page.setObjectName("widget1")
self.pushButton=QtGui.QPushButton(self.page)
self.pushButton.setGeometry(QtCore.QRect(150, 230, 91, 31))
self.pushButton.setText(QtGui.QApplication.translate("self", "Next >", None, QtGui.QApplication.UnicodeUTF8))
self.addWidget(self.page)
QtCore.QMetaObject.connectSlotsByName(self.page)
QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.showWidget2)
def showWidget2(self):
self.page.hide()
obj=file2.widget2()
obj.createWidget2(self)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
ui = Ui_StackedWidget()
ui.show()
sys.exit(app.exec_())
Here's file2
from PyQt4 import QtGui,QtCore
class widget2():
def createWidget2(self,parent):
self.page = QtGui.QWidget()
self.page.setObjectName("page")
self.parent=parent
self.groupBox = QtGui.QGroupBox(self.page)
self.groupBox.setGeometry(QtCore.QRect(30, 20, 421, 311))
self.groupBox.setObjectName("groupBox")
self.groupBox.setTitle(QtGui.QApplication.translate("self", "TestGroupBox", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton = QtGui.QPushButton(self.groupBox)
self.pushButton.setGeometry(QtCore.QRect(150, 120, 92, 28))
self.pushButton.setObjectName("pushButton")
self.pushButton.setText(QtGui.QApplication.translate("self", "Click Me", None, QtGui.QApplication.UnicodeUTF8))
self.parent.addWidget(self.page)
self.parent.setCurrentWidget(self.page)
QtCore.QMetaObject.connectSlotsByName(self.page)
QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.printMessage)
def printMessage(self):
print("Hai")
Though in both the widgets(i mean pages)
QtCore.QMetaObject.connectSlotsByName(self.page)
the clicked signal in second dialog isn't getting processed. Thanks in advance.. Might be a beginner question..
A better question is "Why not just use new-style signals and slots?". They're much simpler and don't require any weird naming conventions:
from sys import argv, exit
from PyQt4 import QtCore, QtGui
class MyWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self._layout = QtGui.QVBoxLayout()
self.setLayout(self._layout)
self._button = QtGui.QPushButton()
self._button.setText('Click NOW!')
self._layout.addWidget(self._button)
self._button.clicked.connect(self._printMessage)
#QtCore.pyqtSlot()
def _printMessage(self):
print("Hai")
if __name__ == "__main__":
app = QtGui.QApplication(argv)
main = MyWidget()
main.show()
exit(app.exec_())
At first, here is the minimal working example:
from sys import argv, exit
from PyQt4 import QtCore, QtGui
class widget2(QtGui.QWidget):
def __init__(self, args):
self.app = MainApp(args)
QtGui.QWidget.__init__(self)
self.setObjectName('I')
self._layout = QtGui.QVBoxLayout(self)
self.setLayout(self._layout)
self.pushButtoninWidget2 = QtGui.QPushButton(self)
self.pushButtoninWidget2.setObjectName("pushButtoninWidget2")
self.pushButtoninWidget2.setText('Click NOW!')
self._layout.addWidget(self.pushButtoninWidget2)
QtCore.QMetaObject.connectSlotsByName(self)
#QtCore.pyqtSlot()
def on_pushButtoninWidget2_clicked(self):
print("Hai")
class MainApp(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self, args)
if __name__ == "__main__":
main = widget2(argv)
main.show()
exit(main.app.exec_())
When you trying to connect slots by name, you must give proper names to the slots and then someone (moc, uic, or you by calling connectSlotsByName) must connect them. Proper name for such a slot is: "on_PyQtObjectName_PyQtSignalName".
Note, that, if I'd omitted #QtCore.pyqtSlot() in the example, slot would be executed once for every appropriate overload (twice in this case).
You DO need to call connectSlotsByNames directly, cause there is no moc, which do it for you when you use QT in C++, and you do not use uic and .ui file. If you want to connect slots implicitly (I'm always doing so, except slots, connected directly in .ui), you'd better use more pytonish syntaxe: button.clicked.connect(self._mySlot).
And take a look at https://riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html#connecting-slots-by-name
You do not need to call connectSlotsByName(), just remove those lines.
In file2, calling QtCore.QMetaObject.connectSlotsByName(self.page) tries to do this:
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self.on_pushButton_clicked())
That will not work for you since self.on_pushBotton_clicked() slot is not defined.
I find it is easiest to create your own connections in PyQt... I recommend removing the calls to connectSlotsByName from your both classes... you do not need it.
Also, your wdiget1 class should set the name of it's pushButton (preferably something other then "pushButton" to avoid confusion with the button in widget2).
Thank you so much jcoon for your reply.. But after a very long time banging my head against the wall i found the solution..
The problem was..
self.obj=test_reuse_stacked1.widget2()
self.obj.createWidget2(self)
instead of obj..
Here is #MarkVisser's QT4 code updated to QT5:
from sys import argv, exit
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class MyWidget(QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self._layout = QtWidgets.QVBoxLayout()
self.setLayout(self._layout)
self._button = QtWidgets.QPushButton()
self._button.setText('Click NOW!')
self._layout.addWidget(self._button)
self._button.clicked.connect(self._print_message)
#QtCore.pyqtSlot()
def _print_message(self):
print("Hai")
if __name__ == "__main__":
app = QApplication(argv)
main = MyWidget()
main.show()
exit(app.exec_())
Another minimal working example with Qt for Python aka PySide2/6.
Key ingredients:
widget to connect MUST have .setObjectName
function to connect MUST be decorated with #QtCore.Slot()
both objects (function AND widget) MUST be members of passed object (self here)
from PySide2 import QtCore, QtWidgets
# or from PySide6 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self):
super(Widget, self).__init__()
layout = QtWidgets.QVBoxLayout(self)
self.button = QtWidgets.QPushButton(self)
self.button.setObjectName('button')
self.button.setText('Click Me!')
layout.addWidget(self.button)
QtCore.QMetaObject.connectSlotsByName(self)
#QtCore.Slot()
def on_button_clicked(self):
print(f'Hai from {self.sender()}')
if __name__ == '__main__':
app = QtWidgets.QApplication([])
main = Widget()
main.show()
app.exec_()
I couldn't get mit any smaller really 🤔