Pavel M.
Pavel M.

Reputation: 610

PySide *any* method call - SIGNALs and SLOTs

I am trying to create simple, universal method call for my PySide GUI library:

class GUI(QApplication):
    def __init__(self, *args, **kwargs):
        super(GUI, self).__init__()
        self.gui_signal = Signal()
        self.gui_signal.connect(self.method_call)

Slot to get object, method and call object.method with args:

    @Slot()
    def method_call(self, obj, method_name, *args, **kwargs):
        method = getattr(obj, method_name)
        if method:
            return method(*args, **kwargs)
        else:
            return None

This should emit that tricky slot:

    def anymethod(self, obj, method_name, *args, **kwargs):
        self.gui_signal.emit(obj, method_name, *args, **kwargs)

This is some another working thread, which for example, updates progressbar

class MyApp(object):
    ...

    def update_progress(self):
        perc = (self.done * 100) / self.total
        self.gui.anymethod(self.progressBar, 'setValue', int(perc))

I see this approach doesn't work and args are passed wrong way. What should I do to fix?

Upvotes: 1

Views: 633

Answers (1)

eyllanesc
eyllanesc

Reputation: 243937

The signals should not be defined as members of the class but as attributes of the class. On the other hand you must indicate the signature, and lastly, the dictionaries do not support so you have to transform *args, **kwargs into a tuple.

from PySide import QtCore, QtGui

class GUI(QtGui.QApplication):
    gui_signal = QtCore.Signal(object, str, tuple)

    def __init__(self, *args, **kwargs):
        super(GUI, self).__init__([])
        self.gui_signal.connect(self.method_call)

    @QtCore.Slot(object, str, tuple)
    def method_call(self, obj, method_name, data):
        if hasattr(obj, method_name):
            method = getattr(obj, method_name)
            args, kwargs = data
            if hasattr(method, '__call__'):
                method(*args, **kwargs)

    def anymethod(self, obj, method_name, *args, **kwargs):
        self.gui_signal.emit(obj, method_name, (args, kwargs))

class MyApp(object):
    def __init__(self):
        self.gui = GUI()

        self.progressBar = QtGui.QProgressBar(maximum=100)
        self.progressBar.show()

        self.total = 200
        self.done = 100
        QtCore.QTimer.singleShot(300, self.update_progress)

    def update_progress(self):
        perc = (self.done * 100) / self.total
        self.gui.anymethod(self.progressBar, 'setValue', int(perc))

    def run(self):
        return self.gui.exec_()

if __name__ == '__main__':
    import sys
    app = MyApp()
    sys.exit(app.run())

Upvotes: 1

Related Questions