理解pyqt中的connectSlotsByName()有问题?
我不太明白connectSlotsByName()这个方法,它主要在pyuic4中使用。对于一个PyQt文件中只有一个类的情况,这个方法还好用,因为我们可以用self,它会和一个对象关联。但当我们尝试从不同的文件中使用多个类时,就会出现问题,这时候就需要用到connectSlotsByName()。我遇到了一些奇怪的情况。
我创建了一个堆叠窗口。
我在上面放了第一个窗口,它有一个叫“下一步 >”的按钮。
点击“下一步”后,它会隐藏当前窗口,并添加另一个窗口,这个窗口有一个“点击我”的按钮。
这里的问题是,第二个窗口中的“点击我”按钮的点击事件没有被捕捉到。这是我原始问题的一个简单示例。请帮帮我。
这是文件1(包含父堆叠窗口和它的第一页)。点击“下一步”后,它会添加第二页,第二页有“点击我”按钮,位于文件2中。
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_())
这是文件2
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 个回答
你不需要调用 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”,这样可以避免和 widget2
中的按钮混淆)。
一个更好的问题是:“为什么不直接使用新式的信号和槽呢?”它们要简单得多,而且不需要什么奇怪的命名规则:
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_())
首先,这里有一个最简单的工作示例:
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_对象名_信号名”。
注意,如果我在示例中省略了@QtCore.pyqtSlot(),那么这个槽会对每个合适的重载执行一次(在这个例子中会执行两次)。
你确实需要直接调用connectSlotsByNames,因为在使用QT的C++时没有moc会为你处理这个,而你又不使用uic和.ui文件。如果你想隐式连接槽(我总是这样做,除了那些直接在.ui中连接的槽),最好使用更符合Python风格的语法:button.clicked.connect(self._mySlot)。
另外,可以看看这个链接:https://riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html#connecting-slots-by-name