首页 > 解决方案 > 使用参数 PyQt 调用不同类的函数

问题描述

我想在按下按钮时触发不同类的功能。像这个例子如何在 PyQt 中向事件循环发出自定义事件

但我也想在每次单击按钮时向该函数传递一个参数。我该如何做到这一点?

标签: pythonpython-3.xpyqtpyqt5

解决方案


如果要添加其他参数,可以使用 functools.partial:

主文件

from PyQt5 import QtCore, QtWidgets
from globalobject import GlobalObject

import functools


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        button = QtWidgets.QPushButton(text="Press me", clicked=self.on_clicked)
        self.setCentralWidget(button)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        GlobalObject().dispatchEvent("hello")


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        wrapper = functools.partial(self.foo, "foo", bar="baz")
        GlobalObject().addEventListener("hello", wrapper)
        self._label = QtWidgets.QLabel()
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self._label)

    def foo(self, foo, bar=None):
        print(foo, bar)
        self._label.setText(foo)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w1 = MainWindow()
    w2 = Widget()
    w1.show()
    w2.show()
    sys.exit(app.exec_())

该逻辑也可以在库中实现:

全局对象.py

from PyQt5 import QtCore
import functools


@functools.lru_cache()
class GlobalObject(QtCore.QObject):
    def __init__(self):
        super().__init__()
        self._events = {}

    def addEventListener(self, name, func, *, args=(), kwargs=None):
        kwargs = kwargs or {}
        if name not in self._events:
            self._events[name] = []
        self._events[name].append((func, args, kwargs))

    def dispatchEvent(self, name):
        functions = self._events.get(name, [])
        for func, args, kwargs in functions:
            wrapper = func
            wrapper = functools.partial(func, *args, **kwargs)
            QtCore.QTimer.singleShot(0, wrapper)

主文件

from PyQt5 import QtCore, QtWidgets
from globalobject import GlobalObject


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        button = QtWidgets.QPushButton(text="Press me", clicked=self.on_clicked)
        self.setCentralWidget(button)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        GlobalObject().dispatchEvent("hello")


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        GlobalObject().addEventListener(
            "hello", self.foo, args=("foo",), kwargs={"bar": "baz"}
        )
        self._label = QtWidgets.QLabel()
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self._label)

    def foo(self, foo, bar=None):
        print(foo, bar)
        self._label.setText(foo)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w1 = MainWindow()
    w2 = Widget()
    w1.show()
    w2.show()
    sys.exit(app.exec_())

更新:

如果您想通过 dispatchEvent 方法发送参数,那么您应该使用以下内容:

全局对象.py

from PyQt5 import QtCore
import functools


@functools.lru_cache()
class GlobalObject(QtCore.QObject):
    def __init__(self):
        super().__init__()
        self._events = {}

    def addEventListener(self, name, func):
        if name not in self._events:
            self._events[name] = []
        self._events[name].append(func)

    def dispatchEvent(self, name, *, args=(), kwargs=None):
        kwargs = kwargs or {}
        functions = self._events.get(name, [])
        for func in functions:
            wrapper = func
            wrapper = functools.partial(func, *args, **kwargs)
            QtCore.QTimer.singleShot(0, wrapper)

主文件

from PyQt5 import QtCore, QtWidgets
from globalobject import GlobalObject


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        button = QtWidgets.QPushButton(text="Press me", clicked=self.on_clicked)
        self.setCentralWidget(button)
        self.counter = 0

    @QtCore.pyqtSlot()
    def on_clicked(self):
        self.counter += 1
        GlobalObject().dispatchEvent("hello", args=(self.counter,))


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        GlobalObject().addEventListener("hello", self.foo)
        self._label = QtWidgets.QLabel()
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self._label)

    def foo(self, x):
        print(x)
        self._label.setNum(x)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w1 = MainWindow()
    w2 = Widget()
    w1.show()
    w2.show()
    sys.exit(app.exec_())

推荐阅读