Qt::Popup window behaviour
-
wrote on 5 Jun 2020, 15:43 last edited by JonB 6 May 2020, 15:45
I have a
QPushButton
with an associatedQWidget
window, 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::Popup
doesn'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
QPushButton
lives --- 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.
wrote on 6 Jun 2020, 08:26 last edited by JonB 6 Aug 2020, 08:28@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
QWidget
withsetWindowFlags(Qt::Popup)
is a member variable allocated on the stack, the class hasQWidget _popup;
as shown. Consequently I do not expect to leak, andvalgrind
reports no leak. So far, so good.However, a learned colleague here ( @mrjj) allocates these on the heap, so he would have
QWidget *_popup
and 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
. Inew
it,connect()
it, but do not setQt::Popup
. I test, and sure enoughvalgrind
does report leak. - I now add just
_popup2->setWindowFlags(Qt::Popup);
, so it has popup flag too. I do notpopup2->show()
it any time. Nowvalgrind
does not report it leaking; yet "Destroyed" message onQObject::destroyed
is still not called.
Summary:
-
Putting
Qt::Popup
attribute on anew
ed widget (without parent) causes it not to leak, even if it is never shown. However,QObject::destroyed
is 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
new
ed 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 ?
wrote on 8 Jun 2020, 07:06 last edited by JonB 6 Aug 2020, 07:10@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
QPushButton
with an associatedQWidget
window, 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::Popup
doesn'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
QPushButton
lives --- 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?
wrote on 8 Jun 2020, 07:13 last edited by@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?
wrote on 8 Jun 2020, 07:17 last edited by JonB 6 Aug 2020, 07:18@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!
wrote on 8 Jun 2020, 07:29 last edited by@JonB I understand.
Eventfilter would probably do :) HoverMove might be a friend!
-
@JonB I understand.
Eventfilter would probably do :) HoverMove might be a friend!
wrote on 8 Jun 2020, 07:49 last edited by@MEMekaniske
In trying to investigate #1 yesterday, I had a look through woboq. I believe I came across code forQt::Popup
flag (list of popped up widgets created from it), which did something likeaccept
a 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-
new
ed-Qt::Popup
-flag behaviour, I am judging this area as "black magic" and hence too scary to tamper with... -
wrote on 8 Jun 2020, 08:44 last edited by JonB 6 Aug 2020, 09:01
STOP PRESS
[Including for @SGaist, @mrjj's attention.]
I revisited my 10 line program apparently showing leak on plainnew QWidget
but not onnew QWidget; setWindowFlags(Qt::Popup);
.- If I remove the "test" non-
Popup
widget and only have thePopup
widget then valgrind does report thePopup
as a leak. - If I reverse the order so that the
Popup
widget isnew
-ed first and the non-Popup
isnew
-ed next, then valgrind does report thePopup
widget as leaking but the non-Popup
widget 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
Popup
widget is on the stack. In his situation henew
s on the heap, and I conclude that he does need to delete thePopup
window.Problem #1 at least apparently resolved!
- If I remove the "test" non-
1/10