PyQt (or just QT). How to get QComboBox to fire a signal whenever it is set to a value (even if unchanged)

bvz picture bvz · Oct 19, 2010 · Viewed 23k times · Source

I am using PyQt4, but this is general enough that it could just apply to QT.

I have a series of QComboBoxes that I fill from left to right (i.e. selecting an item in the leftmost will populate the next one. Selecting an item in that one will populate the next, and so on)

I am having difficulty getting my signals to fire under all situations (i.e. regardless of whether the current index changes or not AND regardless of whether the item is set by the user or set programatically).

More detail:

I rely on the signals of the first QCombox to fire whenever an item is selected so that I can populate the next QCombobox in the gui. I then rely on THAT QCombobox to emit a signal so that I can populate the next one. And so on.

I want to pre-select an item in each QCombobox based on the user's last interaction with the gui.

I have a unique function per QCombobox that is responsible for populating and pre-selecting just that QCombobox. The code looks something like this:

comboBox1.blockSignals(True)
comboBox1.clear()
comboBox1.addItems(sorted(itemList))
comboBox1.blockSignals(False)
comboBox1.setCurrentIndex(intLastSavedState1)

where intLastSavedState1 is an integer that is derived from the text that was last selected by the user the last time they had used the app. I had hoped that the last line of this function would fire a signal that would cause the next combo box's function to load and pre-select an item (comboBox2). And that action would then cause the next comboBox's function to activate and it would cascade to the next and the next. But it is not working across all cases.

I have tried two versions of the signals:

self.connect(comboBox1, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_comboBox2)

and

self.connect(comboBox1, QtCore.SIGNAL("activated(const QString&)"), self.load_comboBox2)

In the first case, the signal will fire only if the intLastSavedState1 is different than whatever is currently selected in the combo box. This causes an issue if the user had last selected item 0 from that list. In this case QT does not recognize my script setting the the current index to 0 as being a change (since after loading the box it appears to think it is already on index 0), and so the signal does not fire.

In the second case, the signal will fire regardless of what is currently selected in the combo box... but only if activated by the user. It will not fire when my script tries to set the current index programatically.

These appear to be my only two options regarding the signals. So... is there another way of pre-selecting items in a QCombobox that will trigger a signal each and every time?

Answer

bvz picture bvz · Oct 19, 2010

Well... sometimes just the act of asking a question can lead you to a (partial) answer.

I have a work-around but I am still interested in hearing if someone has a better idea.

I am now programatically setting the index of the QCombobox to -1 immediately after loading it up. Then, when I programatically set the actual index based on the user's history, it will always be considered a change (i.e. it will never be -1) and the signal will fire

using: currentIndexChanged(const QString&)

So my code looks like this now:

comboBox1.blockSignals(True)
comboBox1.clear()
comboBox1.addItems(sorted(itemList))
comboBox1.setCurrentIndex(-1)
comboBox1.blockSignals(False)
comboBox1.setCurrentIndex(intLastSavedState1)

and my signal looks like this:

self.connect(comboBox1, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.load_comboBox2)

This functions... does anyone have a better idea?

Thanks agian.