【问题标题】:pyqt auto connect signalpyqt自动连接信号
【发布时间】:2013-12-31 22:30:27
【问题描述】:

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

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

非常感谢

【问题讨论】:

  • 尝试从与self 不同的对象发出信号,并将对该对象的引用放入self。我只能猜测,但我认为connectSlotsByName() 不会将self 视为要连接的对象。

标签: python pyqt4 signals-slots


【解决方案1】:

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

【讨论】:

  • 谢谢,现在我可以创建一个 qtimer,它会发出带有自动连接功能的信号。这个功能对我很有用,因为我正在使用 Qt 设计器插件功能。
【解决方案2】:

我对文档进行了一些调查。 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

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

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() 不太可能在该问题中发挥作用。 所以,我把它移到了可能更合适的地方,即使这个问题有点老了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-11
    • 2013-07-14
    • 2016-11-03
    • 2011-05-08
    • 1970-01-01
    • 2018-12-31
    • 2011-08-07
    相关资源
    最近更新 更多