使用重载的 PySide 信号调用 Python 函数而不传递参数

Posted

技术标签:

【中文标题】使用重载的 PySide 信号调用 Python 函数而不传递参数【英文标题】:Call Python function with overloaded PySide signal without passing arguments 【发布时间】:2020-11-23 20:22:51 【问题描述】:

我正在尝试以不同的方式从线程工作者调用 PySide 应用程序中的相同函数。用test_sig = Signal((), (int,), (str,))重载PySide信号,提供三个槽(@Slot()@Slot(int)@Slot(str))给一个测试函数,然后发出每个信号(test_sig.emit()test_sig[int].emit(1)test_sig[str].emit('a'))适用于整数和字符串的情况。但是,无论我尝试什么,我都无法在没有传递参数的情况下调用测试函数。

从我的尝试看来,当信号过载时,发出test_sig.emit() 不会立即发出。仅当发出下一个定义的重载信号中的第一个(在我的情况下为[str])时,才会发出两次

我正在使用 Python 3.9 和 PySide==1.15.1。这是我的最小工作示例:

import sys
from PySide2.QtCore import QRunnable, QObject, QThreadPool, Slot, Signal
from PySide2.QtWidgets import QApplication, QMainWindow


# Signals class
class WorkerSignals(QObject):
    test_sig = Signal((), (str,), (int,))
    finished = Signal()


# Test worker
class Worker(QRunnable):
    def __init__(self):
        super().__init__()
        self.signals = WorkerSignals()

    @Slot()
    def run(self):
        self.signals.test_sig.emit()  # Trying to call function with no args
        self.signals.test_sig[int].emit(1)  # Call function with int
        self.signals.test_sig[str].emit('a')  # Call function with str
        self.signals.finished.emit()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.threadpool = QThreadPool()
        self.run_test()

    def run_test(self):
        worker = Worker()
        worker.signals.test_sig.connect(self.test_func)  # I suspect this might be what I'm doing wrong
        worker.signals.test_sig[int].connect(self.test_func)
        worker.signals.test_sig[str].connect(self.test_func)
        worker.signals.finished.connect(self.test_finished)
        self.threadpool.start(worker)

    @Slot()
    @Slot(int)
    @Slot(str)
    def test_func(self, arg=None):
        test_result = 'Test reached'
        if arg:
            test_result += f', arg received and is a type(arg).'
        else:
            test_result += ' and no arg received.'
        print(test_result)

    @Slot()
    def test_finished(self):
        self.close()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    sys.exit(app.exec_())

其终端输出为:

Test reached, arg received and is a <class 'int'>.
Test reached, arg received and is a <class 'str'>.
Test reached, arg received and is a <class 'str'>.

我发现的唯一解决方法是使用test_sig = Signal((int,), (str,)) 重载信号,使用test_sig.emit(None) 发射而不连接test_sig.connect() 信号,这会导致以下终端输出:

Test reached and no arg received.
Test reached, arg received and is a <class 'int'>.
Test reached, arg received and is a <class 'str'>.

【问题讨论】:

【参考方案1】:

这显然是一个错误。这样Signal 不允许在没有参数的情况下建立过载信号,而且它不会消除先前信息的缓冲区。

另一方面,在pyqt5 中,观察到了预期的行为,因此我们可以指出这不是qt 错误,而只是pyside2。

我创建了PYSIDE-1427 错误。

【讨论】:

以上是关于使用重载的 PySide 信号调用 Python 函数而不传递参数的主要内容,如果未能解决你的问题,请参考以下文章

PySide2 使用 QProgressBar 作为信号参数

将 QML 信号连接到 PySide2 插槽

单独文件中的 PySide 信号

使用 Qt Designer 在 PySide2 中实现信号/插槽时出错

PySide 中未处理的信号

PySide (Qt) 信号未到达我的插槽