5

I have a function which has default keyword arguments. I'm having trouble implementing this as I keep getting an error that if my signal has two arguments then I need to pass both arguments. Is there any way around this?

class Controller(QWidget):
    trigger = pyqtSignal(str, str)
    def __init__(self):
        self.trigger.connect(self.myfunc)

    @pyqtSlot(str, str)
    def function(argument, optional_argument=''):
         do something

c = Controller()
c.trigger.emit('Hello', 'World') # This works
c.trigger.emit('Hello')  # This fails and says I need 2 arguments
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
aoh
  • 1,090
  • 2
  • 13
  • 25
  • I don't believe this is possible, sadly, even though Qt in C++ supports this natively. – Alex Huszagh Nov 01 '18 at 20:08
  • 4
    @AlexanderHuszagh yes it is possible in python, in C++ the MOC does the dirty work of creating 2 signals with 2 signatures, but in python both signatures must be clearly indicated. :-) – eyllanesc Nov 01 '18 at 20:32

1 Answers1

14

You must make the connection pointing to signature in the connection besides overloading the types that the signal supports:

import sys
from PyQt5 import QtCore


class Controller(QtCore.QObject):
    trigger = QtCore.pyqtSignal([str], [str, str])

    def __init__(self):
        super(Controller, self).__init__()
        self.trigger[str].connect(self.function)
        self.trigger[str, str].connect(self.function)

    @QtCore.pyqtSlot(str)
    @QtCore.pyqtSlot(str, str)
    def function(self, argument,  optional_argument=''):
        print(argument, optional_argument)


def main():
    app = QtCore.QCoreApplication(sys.argv)
    c = Controller()
    c.trigger[str].emit('Hello')
    c.trigger[str, str].emit('Hello', 'World')
    QtCore.QTimer.singleShot(100, QtCore.QCoreApplication.quit)
    sys.exit(app.exec_())


if __name__ == "__main__":
     main()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • If instead of `def function(self, argument, optional_argument='')`, it was `def function(self, *args)`, how would the `pyqtSlot(...)` decorator look please (if that is possible)? – SamG101 May 16 '21 at 16:37
  • @SamG101 The big question: have you tried? – eyllanesc May 16 '21 at 16:44
  • Using pyqtSlot() with one argument like `pyqtSlot(str)` chops off other arguments I'd like to use, but using `ARGS = [str]*100; @pyqtSlot(*ARGS)` and then defining the function causes an error if I only use 20 arguments for example, so I was wondering if there was a different approach I should take. I am now looking at wrapping the pyqtSlot inside a newly defined decorator, to see if I can change the behavior this way. (Btw I'm invoking the slot from QML not a `pyqtSignal`). – SamG101 May 16 '21 at 16:48
  • @SamG101 Why is it necessary to use multiple types? Why don't you use some container like a `list` or `dict`? I will not continue with the discussion because you do not give much detail so if you want more help then create a post where you give more details and provide an MRE. – eyllanesc May 16 '21 at 16:53