pyqt自动连接信号

时间:2013-12-13 07:59:33

标签: python pyqt4 signals-slots

我想使用自动连接功能。我正在使用这个例子:

http://www.eurion.net/python-snippets/snippet/Connecting%20signals%20and%20slots.html

它可以工作,但我想创建自己的信号和自己的插槽,这个例子使用内置信号。

例如,这是一个带有自定义插槽的自定义信号,但不起作用:

import sys
from PyQt4 import QtGui, QtCore

class SignalsAndSlots(QtGui.QWidget):

    testSignal = QtCore.pyqtSignal(str,name='testSignal')  



    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setObjectName('testObject')
        self.label = QtGui.QLabel(self)

        QtCore.QMetaObject.connectSlotsByName(self)
        self.emitSignal()


    def emitSignal(self):
        self.testSignal.emit('message')  

    @QtCore.pyqtSlot(str,name='on_testObject_testSignal')     
    def autoSlot(self,msg):
        self.label.setText(msg)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    gui = SignalsAndSlots()
    gui.show()
    app.exec_()

非常感谢

2 个答案:

答案 0 :(得分:2)

Ber是对的。这就是pyqt documentation所说的:

QMetaObject.connectSlotsByName 以递归方式搜索给定对象的所有子对象 [...]

以下是自定义信号的简单示例:

import sys
from PyQt4 import QtGui, QtCore

class CustomButton(QtGui.QPushButton):
    custom_clicked = QtCore.pyqtSignal(str, name='customClicked')
    def mousePressEvent(self, event):
        self.custom_clicked.emit("Clicked!")

class SignalsAndSlots(QtGui.QWidget):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        layout = QtGui.QHBoxLayout(self)
        self.custom_button = CustomButton("Press Me", self)
        self.custom_button.setObjectName('customButton')
        self.label = QtGui.QLabel("Nothing...", parent=self)
        layout.addWidget(self.custom_button)
        layout.addWidget(self.label)
        QtCore.QMetaObject.connectSlotsByName(self)

    @QtCore.pyqtSlot(str, name='on_customButton_customClicked')     
    def autoSlot(self, msg):
        self.label.setText(msg)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    gui = SignalsAndSlots()
    gui.show()
    app.exec_()

但我认为你应该考虑不使用对象名称。新式信号连接更简洁。这是相同的应用程序:

import sys
from PyQt4 import QtGui, QtCore

class CustomButton(QtGui.QPushButton):
    custom_clicked = QtCore.pyqtSignal(str)
    def mousePressEvent(self, event):
        self.custom_clicked.emit("Clicked!")

class SignalsAndSlots(QtGui.QWidget):

    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        layout = QtGui.QHBoxLayout(self)
        self.custom_button = CustomButton("Press Me", self)
        self.custom_button.setObjectName('customButton')
        self.label = QtGui.QLabel("Nothing...", parent=self)
        layout.addWidget(self.custom_button)
        layout.addWidget(self.label)
        self.custom_button.custom_clicked.connect(self.on_clicked)

    def on_clicked(self, msg):
        self.label.setText(msg)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    gui = SignalsAndSlots()
    gui.show()
    app.exec_()

答案 1 :(得分:0)

我对文档进行了一些调查。的 QtCore.QMetaObject.connectSlotsByName()

为此,我制作了一个MCVE来收集无法正常运行和正常运行的东西:

#!/usr/bin/python3

import sys
from PyQt5.QtCore import QT_VERSION_STR
from PyQt5.QtCore import QMetaObject, pyqtSlot
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QWidget

class MainWindow(QMainWindow):
  def __init__(self):
    QMainWindow.__init__(self)
    # build GUI
    qMain = QWidget()
    qVBox = QVBoxLayout()
    qBtnPreview1 = QPushButton("Preview 1")
    qBtnPreview1.setObjectName("preview1")
    qVBox.addWidget(qBtnPreview1)
    qBtnPreview2 = QPushButton("Preview 2")
    qBtnPreview2.setObjectName("preview2")
    qVBox.addWidget(qBtnPreview2)
    qBtnPreview3 = QPushButton("Preview 3")
    qBtnPreview3.setObjectName("preview3")
    qVBox.addWidget(qBtnPreview3)
    qBtnPreview4 = QPushButton("Preview 4")
    qBtnPreview4.setObjectName("preview4")
    qVBox.addWidget(qBtnPreview4)
    qBtnPreview5 = QPushButton("Preview 5")
    qBtnPreview5.setObjectName("preview5")
    qVBox.addWidget(qBtnPreview5)
    qBtnPreview6 = QPushButton("Preview 6")
    qBtnPreview6.setObjectName("preview6")
    qVBox.addWidget(qBtnPreview6)
    qMain.setLayout(qVBox)
    self.setCentralWidget(qMain)
    # install signal handlers
    qBtnPreview1.clicked.connect(lambda: print("preview1 clicked."))
    qBtnPreview2.clicked.connect(lambda: print("preview2 clicked."))
    qBtnPreview3.clicked.connect(lambda: print("preview3 clicked."))
    qBtnPreview4.clicked.connect(lambda: print("preview4 clicked."))
    qBtnPreview5.clicked.connect(lambda: print("preview5 clicked."))
    qBtnPreview6.clicked.connect(lambda: print("preview6 clicked."))
    QMetaObject.connectSlotsByName(self)

  @pyqtSlot()
  def preview1(self):
    print("MainWindow.preview1() called.")
  
  @pyqtSlot()
  def preview2_clicked(self):
    print("MainWindow.preview2_clicked() called.")
  
  @pyqtSlot()
  def on_preview3(self):
    print("MainWindow.on_preview3() called.")

  @pyqtSlot()
  def on_preview4_clicked(self):
    print("MainWindow.on_preview4_clicked() called.")
  
  @pyqtSlot(name='on_preview5_clicked')
  def preview5_clicked(self):
    print("MainWindow.preview5_clicked() called.")

  def on_preview6_clicked(self):
    print("MainWindow.on_preview6_clicked() called.")
    
if __name__ == '__main__':
  print("Qt Version: {}".format(QT_VERSION_STR))
  app = QApplication(sys.argv)
  # build GUI
  qWinMain = MainWindow()
  qWinMain.show()
  # runtime loop
  sys.exit(app.exec_())

输出:

$ ./testQMetaObjectConnectSlotsByName.py 
Qt Version: 5.9.3

snapshot of testQMetaObjectConnectSlotsByName.py

单击六个按钮中的每个按钮后,我得到:

preview1 clicked.
preview2 clicked.
preview3 clicked.
preview4 clicked.
MainWindow.on_preview4_clicked() called.
preview5 clicked.
MainWindow.preview5_clicked() called.
preview6 clicked.
MainWindow.on_preview6_clicked() called.
MainWindow.on_preview6_clicked() called.

观察:

  1. MainWindow.preview1()MainWindow.preview2_clicked()MainWindow.on_preview3()未连接。它们不遵循QtCore.QMetaObject.connectSlotsByName()的必需约定。

  2. MainWindow.on_preview4_clicked()通过名称连接-正确遵循所需的名称约定。

  3. MainWindow.preview5_clicked()也已连接–通过@pyqtSlot(name='on_preview5_clicked')给出所需的名称。

  4. MainWindow.on_preview6_clicked()也已连接-即使未明确将其标记为插槽。 (但是,由于某种原因,它可能会被两次调用。)

  5. 显式连接在任何情况下都可以工作,并且对我来说更可靠。

更多读数:


实际上,这是我对另一个问题(SO: How to display two images in each Qlabel PyQt5)的回答,直到我意识到QtCore.QMetaObject.connectSlotsByName()不太可能在该问题中起作用。 因此,我将其移至此处,即使问题有些陈旧,也可能更合适。