Reputation: 225
I want to trigger a function of a different class on press of a button. Something like this example How to emit custom Events to the Event Loop in PyQt.
But I also want to pass a parameter to that function everytime the button is clicked. How do I achieve that?
Upvotes: 0
Views: 584
Reputation: 244202
If you want to add additional arguments you can use functools.partial:
main.py
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_())
That logic can also be implemented in the library:
globalobject.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)
main.py
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_())
If you want to send arguments through the dispatchEvent method then you should use the following:
globalobject.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)
main.py
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_())
Upvotes: 2