Как я могу подтвердить идентичность сигнала PyQt5? - PullRequest
0 голосов
/ 15 февраля 2019

Я нахожусь в ситуации, когда я хочу подтвердить идентичность сигнала PyQt5.В частности, я хочу проверить, идентичен ли сигнал clicked от данного объекта QPushButton сигналу, который хранится в переменной с именем signal.Следующий фрагмент иллюстрирует ситуацию:

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

Как показано, три сравнения, включающие ==, is и id() соответственно, все производят False, то есть они не в состоянии утверждать идентичностьлевый и правый аргумент.

Можно ли утверждать, что widget.clicked и signal ссылаются на один и тот же сигнал?

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Сигналы как объекты создаются каждый раз, когда вы вызываете его, поскольку они представляют другое соединение:

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() метода

Если слот принадлежит 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 function
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_())

В моем случае я предпочитаю использовать отправителя, если я могу его использовать,затем functools.partial и, наконец, лямбда-методы

0 голосов
/ 15 февраля 2019

Попробуйте:

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

enter image description here

...