理解pyqt中的connectSlotsByName()有什么问题?

时间:2010-03-17 13:10:18

标签: python qt pyqt

我无法理解pyuic4主要使用的connectSlotsByName()方法。到目前为止,这个类在PyQt文件中是单一的,因为我们可以使用self,它将与整个单个对象相关联。但是当我们尝试使用来自不同文件的各种类时,问题和使用connectSlotsByName()的需要出现了..这就是我遇到的奇怪的事情。

我创建了一个堆叠小部件..

  • 我把第一个小部件放在上面..它 有一个名为“下一步>”的按钮。

  • 点击下一步,它会隐藏当前 小部件并添加另一个具有“单击我”按钮的小部件..

这里的问题是没有捕获第二个“点击我”按钮的点击事件..这是我可以为我的原始问题提供的最小例子..请帮助我..

这是文件No.1 ..(具有父级堆叠小部件,它是第一页)。点击下一步,它会添加第二页,其中包含file2中的“clickme”按钮。

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_()) 

这是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")

虽然在两个小部件中(我的意思是页面)

QtCore.QMetaObject.connectSlotsByName(self.page)

第二个对话框中的单击信号未得到处理。在此先感谢..可能是一个初学者问题..

6 个答案:

答案 0 :(得分:4)

首先,这是最小的工作示例:

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_())

当您尝试按名称连接插槽时,必须为插槽指定正确的名称,然后某人(moc,uic或您通过调用connectSlotsByName)必须连接它们。这样一个插槽的正确名称是:“on_PyQtObjectName_PyQtSignalName”。

注意,如果我在示例中省略了@ QtCore.pyqtSlot(),则每次适当的重载都会执行一次插槽(在这种情况下为两次)。

您需要直接调用connectSlotsByNames,因为没有moc,当您在C ++中使用QT时,它会为您执行此操作,并且您不使用uic和.ui文件。如果你想隐式连接插槽(我总是这样做,除了插槽,直接连接在.ui中),你最好使用更多的pytonish语法:button.clicked.connect(self._mySlot)。

并查看http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#connecting-slots-by-name

答案 1 :(得分:2)

您无需致电connectSlotsByName(),只需删除这些行。

file2中,调用QtCore.QMetaObject.connectSlotsByName(self.page)会尝试执行此操作:

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

由于未定义self.on_pushBotton_clicked()插槽,因此无法使用。 我发现在PyQt中创建自己的连接是最简单的...我建议从这两个类中删除对connectSlotsByName的调用...你不需要它。

另外,你的wdiget1类应设置它的pushButton名称(最好是“pushButton”之外的其他名称,以避免与widget2中的按钮混淆。)

答案 2 :(得分:2)

更好的问题是“为什么不使用新式信号和插槽?”。它们更简单,不需要任何奇怪的命名约定:

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_())

答案 3 :(得分:1)

非常感谢jcoon的回复..但是经过很长一段时间,我的头靠在墙上,我找到了解决方案..

问题是......

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

而不是obj ..

答案 4 :(得分:0)

这是@MarkVisser的QT4代码已更新为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_())

答案 5 :(得分:0)

另一个最小工作示例,使用 Qt for Python 又名 PySide2/6
主要成分:

  • 连接小部件必须有 .setObjectName
  • 连接函数必须用 @QtCore.Slot() 修饰
  • 两个对象(函数和小部件)都必须是传递对象的成员(此处为 self
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_()

我真的不能再小了?