Qt::Popup window behaviour
-
I have a
QPushButtonwith an associatedQWidgetwindow, which pops up temporarily (when the button is clicked) to allow user to interact with some widgets on it. The bare essentials are:class PushButtonWithPopup : public QPushButton { Q_OBJECT public: PushButtonWithPopup(QWidget *parent = nullptr); private: QWidget _popup; private slots: void doPopup(); }; PushButtonWithPopup::PushButtonWithPopup(QWidget *parent /*= nullptr*/) : QPushButton(parent) { // popup window flags (popup with no frame) _popup.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); // connect button click to execute the popup connect(this, &QPushButton::clicked, this, &PushButtonWithPopup::doPopup); } /*slot*/ void PushButtonWithPopup::doPopup() { // show the popup _popup.show(); }-
This works splendiferously. When I click anywhere outside the popup it goes away, which is just want I want. But now I'm thinking to myself: https://doc.qt.io/qt-5/qt.html#WindowType-enum for
Qt::Popupdoesn't actually say it will dismiss on click-outside, so is it supposed to do what I see it doing? Am I unable to see the wood for the trees, what's actually going on? -
The click outside which dismisses it --- say, on another widget where its assocaited
QPushButtonlives --- gets "eaten" to dismiss the popup. I am finding I would actually prefer it if that click caused the popup to dismiss and then proceeded as usual to do its action, instead of being consumed. For example, if I click on some checkbox outside the popup, after the popup disappears I'd like that checkbox to toggle as usual. How would I go about achieving this, where is my click getting eaten?
-
-
Hi,
- AFAIK, yes that's what is expected
- I am currently not sure how you could implement that.
-
Hi,
- AFAIK, yes that's what is expected
- I am currently not sure how you could implement that.
@SGaist
Firstly, thank you for answering a question with an answer, not another question ;-)Secondly I have some strange Qt behaviour to report on this. I'd really appreciate if you/someone could comment/clarify what might be going on...
This relates just to my Question #1, how a popup window gets destroyed or not.
In my own case, the
QWidgetwithsetWindowFlags(Qt::Popup)is a member variable allocated on the stack, the class hasQWidget _popup;as shown. Consequently I do not expect to leak, andvalgrindreports no leak. So far, so good.However, a learned colleague here ( @mrjj) allocates these on the heap, so he would have
QWidget *_popupand go_popup = new QWidget. He now wonders whether he is consequently leaking? So I changed my stuff over to investigate, and come up with "inexplicable" results:For my existing popup, I change to:
QWidget *_popup; _popup = new QWidget; connect(_popup, &QObject::destroyed, []() { qDebug() << "Destroyed"; }); _popup->setWindowFlags(Qt::Popup); ... _popup->show();valgrind(which works for me, Linux) does not report this as a leak on program exit. Yet I do not ever see the "Destroyed" message onQObject::destroyed.- I now create an extra
QWidget *_popup2. Inewit,connect()it, but do not setQt::Popup. I test, and sure enoughvalgrinddoes report leak. - I now add just
_popup2->setWindowFlags(Qt::Popup);, so it has popup flag too. I do notpopup2->show()it any time. Nowvalgrinddoes not report it leaking; yet "Destroyed" message onQObject::destroyedis still not called.
Summary:
-
Putting
Qt::Popupattribute on anewed widget (without parent) causes it not to leak, even if it is never shown. However,QObject::destroyedis never called. -
If we assume for a moment that it is being deleted/destroyed somehow, behind-the-scenes code seems to know to delete it if it was
newed onto the heap but not (at least, doesn't go wrong) if it is on the stack.
Very, very simple, minimal:
#include <QApplication> #include <QWidget> int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w; // valgrind: next line *DOES* leak QWidget *w1 = new QWidget; // valgrind: next line does *NOT* leak, because of the line below it // and yet if you `connect(w2, &QObject::destroyed)` that does not get called QWidget *w2 = new QWidget; w2->setWindowFlags(Qt::Popup); w.show(); return a.exec(); }Explanation, please?
-
AFAIK, the Popup window flag has no influence with regard to any memory management (and it would not make sense as well).
Do you have suppression files for Valgrind concerning Qt ?
-
AFAIK, the Popup window flag has no influence with regard to any memory management (and it would not make sense as well).
Do you have suppression files for Valgrind concerning Qt ?
@SGaist said in Qt::Popup window behaviour:
AFAIK, the Popup window flag has no influence with regard to any memory management (and it would not make sense as well).
Hence my question. Nonetheless, the code above behaves as I have documented. Qt 5.12.2, Ubuntu 19.04.
I have an absolutely vanilla install of Ubuntu valgrind, 3.14.0. I assume there is nothing Qt about it..
Do you have the opportunity to test that 10 line code yourself? I would also summon @mrjj and request he test under Linux/Windows, since he is the one who is dynamically allocating (my own code the popup widget is on the stack) and would be affected.
-
I have a
QPushButtonwith an associatedQWidgetwindow, which pops up temporarily (when the button is clicked) to allow user to interact with some widgets on it. The bare essentials are:class PushButtonWithPopup : public QPushButton { Q_OBJECT public: PushButtonWithPopup(QWidget *parent = nullptr); private: QWidget _popup; private slots: void doPopup(); }; PushButtonWithPopup::PushButtonWithPopup(QWidget *parent /*= nullptr*/) : QPushButton(parent) { // popup window flags (popup with no frame) _popup.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); // connect button click to execute the popup connect(this, &QPushButton::clicked, this, &PushButtonWithPopup::doPopup); } /*slot*/ void PushButtonWithPopup::doPopup() { // show the popup _popup.show(); }-
This works splendiferously. When I click anywhere outside the popup it goes away, which is just want I want. But now I'm thinking to myself: https://doc.qt.io/qt-5/qt.html#WindowType-enum for
Qt::Popupdoesn't actually say it will dismiss on click-outside, so is it supposed to do what I see it doing? Am I unable to see the wood for the trees, what's actually going on? -
The click outside which dismisses it --- say, on another widget where its assocaited
QPushButtonlives --- gets "eaten" to dismiss the popup. I am finding I would actually prefer it if that click caused the popup to dismiss and then proceeded as usual to do its action, instead of being consumed. For example, if I click on some checkbox outside the popup, after the popup disappears I'd like that checkbox to toggle as usual. How would I go about achieving this, where is my click getting eaten?
@JonB , regarding question 2, A time consuming way to do it would be to track the position of widgets and cursor clicks, but would work I think?
-
-
@JonB , regarding question 2, A time consuming way to do it would be to track the position of widgets and cursor clicks, but would work I think?
@MEMekaniske
I can't afford to do that, I would need a generic solution. I am guessing I would need to know where Qt code "eats" this and do something about it, perhaps in someeventFilter?At the moment I want to resolve what is going on in #1, before I even think of addressing #2!
-
@MEMekaniske
I can't afford to do that, I would need a generic solution. I am guessing I would need to know where Qt code "eats" this and do something about it, perhaps in someeventFilter?At the moment I want to resolve what is going on in #1, before I even think of addressing #2!
@JonB I understand.
Eventfilter would probably do :) HoverMove might be a friend!
-
@JonB I understand.
Eventfilter would probably do :) HoverMove might be a friend!
@MEMekaniske
In trying to investigate #1 yesterday, I had a look through woboq. I believe I came across code forQt::Popupflag (list of popped up widgets created from it), which did something likeaccepta mouse event when a popup was visible, and dismiss the popup. I would need to have a look for that again as the best way forward, I think.Meanwhile, however, I am going on strike! Until I have an explanation for the valgrind non-leak-on-
newed-Qt::Popup-flag behaviour, I am judging this area as "black magic" and hence too scary to tamper with... -
STOP PRESS
[Including for @SGaist, @mrjj's attention.]
I revisited my 10 line program apparently showing leak on plainnew QWidgetbut not onnew QWidget; setWindowFlags(Qt::Popup);.- If I remove the "test" non-
Popupwidget and only have thePopupwidget then valgrind does report thePopupas a leak. - If I reverse the order so that the
Popupwidget isnew-ed first and the non-Popupisnew-ed next, then valgrind does report thePopupwidget as leaking but the non-Popupwidget is not reported as leaking.
For whatever reason, this reveals that valgrind sometimes only reports certain leaks but not others [has anyone else encountered this behaviour?]. This is "disappointing", but at least makes sense, showing nothing special about
Popup.So going back to @mrjj's situation. I do not leak because my
Popupwidget is on the stack. In his situation henews on the heap, and I conclude that he does need to delete thePopupwindow.Problem #1 at least apparently resolved!
- If I remove the "test" non-