alisianoi
alisianoi

Reputation: 2363

PyQt5: one signal comes instead of two as per documentation

I have been reading the section "Connecting Slots By Name" on this PyQt5 documentation page which basically describes new signals and slots functionality. This piece caught my eye:

For example the QtGui.QSpinBox class has the following signals:

void valueChanged(int i);
void valueChanged(const QString &text);

When the value of the spin box changes both of these signals will be emitted.

So I sketched up the following script to test this double call behaviour:

#!/usr/bin/env python3

from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QMainWindow, QSpinBox

class Test(QMainWindow):

    def __init__(self):
        super().__init__()

        self.spb = QSpinBox()
        self.spb.valueChanged.connect(self.onValueChanged)
        self.setCentralWidget(self.spb)

    def onValueChanged(self, x):
        print("QSpinBox: value changed! " + str(x))

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    t = Test()
    t.show()

    sys.exit(app.exec_())

And it looks to me like only one signal is coming through. What am I missing? Please note that I am a complete PyQt noob.

Upvotes: 1

Views: 197

Answers (2)

cdonts
cdonts

Reputation: 9599

Also note that the documentation is talking about slots by name, so you should first add a name to your spinbox.

self.spb.setObjectName("spb")

Then, connect all the slots:

QtCore.QMetaObject.connectSlotsByName(self)

And finally create the slot using the on_widgetName_signalName form.

def on_spb_valueChanged(self, x):
    print("QSpinBox: value changed! " + str(x))

It will be called twice now.

Use the pyqtSlot decorator to indicate which signal you want to receive.

@QtCore.pyqtSlot(int)
def on_spb_valueChanged(self, x):

Or...

@QtCore.pyqtSlot(str)
def on_spb_valueChanged(self, x):

Hope it helps.

Upvotes: 2

ekhumoro
ekhumoro

Reputation: 120598

You only connected to one of the two signal overloads.

Since you also didn't specify which overload you wanted, a default will be selected - which in this case will be valueChanged(int).

To explicitly select both overloads, you would need to do:

    self.spb.valueChanged[int].connect(self.onValueChanged)
    self.spb.valueChanged[str].connect(self.onValueChanged)
    ...

def onValueChanged(self, x):
    print("QSpinBox: value changed! ", x, type(x))

Upvotes: 2

Related Questions