Unsolved QComboBox::showPopup() override timing problem
-
I override http://doc.qt.io/qt-5/qcombobox.html#showPopup (called when user clicks the combo's dropdown button) to execute some code to populate the list of items shown dynamically, prior to displaying the list.
It seems this works well if the population code executed is "quick" but misbehaves if the code is "slow" by failing to actually show the popup after population.
Following code tested with Qt 5.7 under Linux. I cannot test under Windows, so I don't know if the issue is Qt widget or native combobox.
class JComboBox(QComboBox): # class variable for a new "popupAboutToBeShown" signal # Qt does not emit a signal when the dropdwon/popup of a combobox is about to be shown # we add this signal, which can be used for e.g. dynamically populating the items popupAboutToBeShown = QtCore.pyqtSignal(name='popupAboutToBeShown') # override of virtual function def showPopup(self): # emit the new signal self.popupAboutToBeShown.emit() # call the base method now to display the popup super().showPopup()
I do not believe the issue is to do with the use of signal/slot here, but that is how I do it. All single-threaded here, the
emit()
is indeed a direct, blocking function call to slot. [EDIT I just tried code below in direct override ofshowPopup()
instead of going via signal/slot to eliminate that, same behaviour.]self.combo = JCombBox() self.combo.setEditable(True) self.combo.popupAboutToBeShown.connect(populateCombo) def populateCombo(self) # In real life `items` would be populated by call to synchronous, non-Qt library function # which takes a little time to complete # Here we emulate this with a "sleep" and a fixed list # QThread.msleep(100) # this works QThread.msleep(500) # this misbehaves items = ["Item 1", "Item 2", "Item 3"] self.combo.clear() self.combo.addItems(items)
In my tests, after a delay of 100 millis the popup is shown with its new items. However, with a delay of 500 millis the popup does not get shown (the items are correctly populated, e.g. can be seen by using the down arrow key on the combo to move through them). Obviously your mileage may vary on the numbers for the delay.
Any comment on how long my
showPopup()
is allowed to take before something decides it's not going to show the popup/dropdown list?At this rate I'm thinking I won't be able to override
showPopup
to dynamically populate list (something which I have done successfully in native Windows code in the past) and will have to rewrite so that I have something like a...
button with an attached popup dialog instead to execute the code because I can't do it right via aQComboBox
, which is doable but would be a shame.... -
Hi
Tested on windows.
Seems to work as expected.
class ComboTest : public QComboBox { Q_OBJECT public: explicit ComboTest(QWidget* parent = nullptr); public slots: public: virtual void showPopup() override { clear(); for (int var = 0; var < 10000; ++var) { addItem("TEST" + QString::number(var)); } QComboBox::showPopup(); } };
Takes quite some time for it to open. but seems to do it every time.
-
@mrjj
Thank you for testing. But to test same as me, please replace with something likevirtual void showPopup() override { QThread::msleep(2000); clear(); for (int var = 0; var < 3; ++var) { addItem("TEST" + QString::number(var)); } QComboBox::showPopup(); }
If that still works for you, I guess it's something like Ubuntu desktop (Unity)/X11 which is interfering (or my Qt 5.7 if you're on later).
-
@JonB
Hi still works with msleep.
Im on Qt.5.11.1
update: installing 5.7 just to see.
will report back when its finished. -
@mrjj
Hmm, thank you for testing. I guess it must be either my Linux or my Qt 5.7 then....I'll leave this open for a while, in case e.g. someone wishes to test your code under Linux/Qt 5.7.
Meanwhile since I need to support my configuration I'm already doing it via a separate button to refresh combo list instead. I'll have to stick with that if I cannot resolve
showPopup()
.... -
@JonB
Works the same in Qt5.7
ill try on linux a later.