为了账号安全,请及时绑定邮箱和手机立即绑定

如何断言 PyQt5 信号的身份?

如何断言 PyQt5 信号的身份?

慕哥9229398 2021-11-09 20:19:16
我想断言 PyQt5 信号的身份。具体来说,我想检查clicked来自给定QPushButton对象的信号是否与存储在名为 的变量中的信号相同signal。以下代码段说明了这种情况:from PyQt5.QtWidgets import QApplication, QPushButtonapp = QApplication([])widget = QPushButton()signal = widget.clickedwidget.clicked == signalOut[1]: Falsewidget.clicked is signalOut[2]: Falseid(widget.clicked) == id(signal)Out[3]: False如图所示,分别涉及==、is和的三个比较id()都产生False,即它们不能断言左手和右手参数的同一性。有没有办法断言widget.clicked并signal引用相同的信号?
查看完整描述

2 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

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


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

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


一、使用sender()方法

如果插槽属于 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 方法


查看完整回答
反对 回复 2021-11-09
?
胡子哥哥

TA贡献1825条经验 获得超6个赞

尝试一下:


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

//img1.sycdn.imooc.com//618a676b0001e53604160160.jpg

查看完整回答
反对 回复 2021-11-09
  • 2 回答
  • 0 关注
  • 181 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信