Problem understanding connectSlotsByName () in pyqt?

I could not understand the connectSlotsByName () method, which is mainly used by pyuic4. As long as the class is not single in the PyQt file, this is normal, since we can use self, which will be associated with one object in all. But when we try to use different classes from different files, the problem arises and the need to use connectSlotsByName (). That's what I met, which is strange ..

I created a complex widget.

  • I posted my first widget on it. has a "Next>" button.

  • Clicking next hides the current widget and adds another widget that has a "click me" button.

The problem here is that the click event for the "click me" button is not recorded in the second. This is a minimal example that I can give for my original problem. Please help me..

This is file # 1 .. (which has a child stitch and first page). When you click next, it adds a second page with a 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 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") 

Although in both widgets (I mean pages)

 QtCore.QMetaObject.connectSlotsByName(self.page) 

the clicked signal in the second dialog is not processed. Thanks in advance. Maybe a beginner question ..

+4
source share
4 answers

Firstly, here is a 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 try to connect slots by name, you must specify the names for the slots, and then someone (moc, uic, or you, by calling connectSlotsByName) must connect them. The correct name for this slot is "on_PyQtObjectName_PyQtSignalName".

Note that if I omit @ QtCore.pyqtSlot () in the example, the slot will be executed once for each corresponding overload (twice in this case).

You need to call connectSlotsByNames directly, because there is no mok that does this for you when you use QT in C ++ and you do not use the uic and .ui file. If you want to connect slots implicitly (I always do this, with the exception of slots connected directly to .ui), you'd better use the more python syntax: button.clicked.connect (self._mySlot).

And look at http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#connecting-slots-by-name

+3
source

You do not need to call connectSlotsByName() , just delete these lines.

In file2 call to QtCore.QMetaObject.connectSlotsByName(self.page) tries to do this:

 QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self.on_pushButton_clicked()) 

This will not work for you, because the slot self.on_pushBotton_clicked() not defined. I find it easiest to create your own connections in PyQt ... I recommend removing calls to connectSlotsByName from your two classes ... you don't need this.

In addition, your wdiget1 class should set the name of this pushButton (something else is desirable, then "pushButton" to avoid confusion with the button in widget2).

+2
source

The best question is: "Why not just use new style signals and slots?" They are much simpler and do not 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_()) 
+2
source

Thank you so much for your reply. But after a very long time hitting my head against the wall, I found a solution.

The problem was ..

 self.obj=test_reuse_stacked1.widget2() self.obj.createWidget2(self) 

instead of obj ..

+1
source

Source: https://habr.com/ru/post/1304357/


All Articles