【问题标题】:How do I assert the identity of a PyQt5 signal?如何断言 PyQt5 信号的身份?
【发布时间】:2019-07-09 18:24:03
【问题描述】:

我处于想要断言 PyQt5 信号身份的情况。具体来说,我想检查来自给定QPushButton 对象的clicked 信号是否与存储在名为signal 的变量中的信号相同。下面的 sn -p 说明了这种情况:

from PyQt5.QtWidgets import QApplication, QPushButton

app = QApplication([])
widget = QPushButton()
signal = widget.clicked

widget.clicked == signal
Out[1]: False

widget.clicked is signal
Out[2]: False

id(widget.clicked) == id(signal)
Out[3]: False

如图所示,分别涉及==isid() 的三个比较都产生False,即它们无法断言左侧参数和右侧参数的身份。

有什么方法可以断言widget.clickedsignal 引用的是同一个信号?

【问题讨论】:

  • 连接按钮的clicked 信号时,插槽将接收来自该按钮的所有点击,而不是一次特定的点击。所以不清楚你所说的“相同的信号”是什么意思。您究竟打算如何处理代码中其他地方的 signal 变量?

标签: python pyqt pyqt5 qt-signals


【解决方案1】:

每次调用它时都会创建作为实体的信号,因为它们代表不同的连接:

In [1]: import sys

In [2]: from PyQt5 import QtWidgets

In [3]: app = QtWidgets.QApplication(sys.argv)

In [4]: button = QtWidgets.QPushButton()

In [5]: id(button.clicked)
Out[5]: 140150155639464

In [6]: id(button.clicked)
Out[6]: 140150154507528

In [7]: id(button.clicked)
Out[7]: 140150155640184

In [8]: id(button.clicked)
Out[8]: 140150155640504

In [9]: id(button.clicked)
Out[9]: 140150154510128

In [10]: id(button.clicked)
Out[10]: 140149427454320

因此,如果你在同一个信号和槽之间连接 100 次,当信号发出时,槽会被调用 100 次:

import sys
from PyQt5 import QtCore, QtWidgets

def foo():
    print("clicked")

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    button = QtWidgets.QPushButton("Press me")
    button.show()
    for _ in range(10):
        button.clicked.connect(foo)
    # the click is emulated
    QtCore.QTimer.singleShot(1000, lambda: button.animateClick(500))
    QtCore.QTimer.singleShot(2000, app.quit)
    sys.exit(app.exec_())

输出:

clicked
clicked
clicked
clicked
clicked
clicked
clicked
clicked
clicked
clicked

因此,不可能直接解决您的问题,但我认为您的目标是区分哪个对象发出了调用插槽的信号,因为您可能有多个对象连接到同一个插槽,并且如果有解决方案:

1。使用sender()方法

如果 slot 属于一个 QObject(或从 QObject 派生的类作为小部件),那么您可以使用 sender 方法获取发出信号的对象。

import sys
from PyQt5 import QtCore, QtWidgets

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.button_1 = QtWidgets.QPushButton("button 1")
        self.button_1.clicked.connect(self.foo)
        self.button_2 = QtWidgets.QPushButton("button 2")
        self.button_2.clicked.connect(self.foo)
        self.button_3 = QtWidgets.QPushButton("button 3")
        self.button_3.clicked.connect(self.foo)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.button_1)
        lay.addWidget(self.button_2)
        lay.addWidget(self.button_3)

    @QtCore.pyqtSlot()
    def foo(self):
        button = self.sender()
        if button is self.button_1:
            print("button_1")
        elif button is self.button_2:
            print("button_2")
        elif button is self.button_3:
            print("button_3")

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

2。将对象作为附加参数传递

2.1 拉姆达函数
import sys
from PyQt5 import QtCore, QtWidgets

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.button_1 = QtWidgets.QPushButton("button 1")
        self.button_1.clicked.connect(lambda *args, b=self.button_1 : self.foo(b))
        self.button_2 = QtWidgets.QPushButton("button 2")
        self.button_2.clicked.connect(lambda *args, b=self.button_2 : self.foo(b))
        self.button_3 = QtWidgets.QPushButton("button 3")
        self.button_3.clicked.connect(lambda *args, b=self.button_3 : self.foo(b))

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.button_1)
        lay.addWidget(self.button_2)
        lay.addWidget(self.button_3)

    def foo(self, button):
        if button is self.button_1:
            print("button_1")
        elif button is self.button_2:
            print("button_2")
        elif button is self.button_3:
            print("button_3")

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())
2.1 functools.partial函数
import sys
from PyQt5 import QtCore, QtWidgets
from functools import partial

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.button_1 = QtWidgets.QPushButton("button 1")
        self.button_1.clicked.connect(partial(self.foo, self.button_1))
        self.button_2 = QtWidgets.QPushButton("button 2")
        self.button_2.clicked.connect(partial(self.foo, self.button_2))
        self.button_3 = QtWidgets.QPushButton("button 3")
        self.button_3.clicked.connect(partial(self.foo, self.button_3))

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.button_1)
        lay.addWidget(self.button_2)
        lay.addWidget(self.button_3)

    def foo(self, button):
        if button is self.button_1:
            print("button_1")
        elif button is self.button_2:
            print("button_2")
        elif button is self.button_3:
            print("button_3")

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

就我而言,如果可以使用,我更喜欢使用 sender,然后是 functools.partial,最后是 lambda 方法

【讨论】:

    【解决方案2】:

    试试看:

    import sys
    from PyQt5.QtWidgets import QApplication, QPushButton
    
    app = QApplication([])
    
    def clickButton(w):
        # Check what you clicked here.                        # <-----
        return print(w.text())
    
    widget  = QPushButton('Button 1')
    widget.clicked.connect(lambda : clickButton(widget))
    
    widget2 = QPushButton('Button 2')
    widget2.clicked.connect(lambda : clickButton(widget2))
    
    widget.setGeometry(300, 150, 100, 100)
    widget.show()
    
    widget2.setGeometry(450, 150, 100, 100)
    widget2.show()
    
    sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 2013-01-23
      • 2020-08-17
      • 1970-01-01
      • 2020-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多