Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Is it possible to force update everything for a QWidget without actually show it on the screen ?



  • As the topic said, is there a way to perform all updates for a toplevel QWidget, including it's geometry, backing store, and transient parent window, ... , but without actually show it on the screen? (e.g. do everything that QWidget::show() does, without calling the Windows API ShowWindow() )? I've tried Qt::WA_DontShowOnScreen but it seems to miss something to do, like updateTransientParent.


  • Lifetime Qt Champion

    Hi,

    Can you explain what result you would like to achieve ?



  • I need to integrate a QAxWidget as a floating tool panel into my main UI framework, and I make a custom tool panel window frame for the axWidget, then I call axWidget's setParent(windowFrame, Qt::FramelessWindowHint | Qt::Tool) and write some code to keep it's geometry within the windowFrame (for some reason I have to make the axWidget a toplevel window). The axWidget's parent may change from a windowFrame to a new one, and the original windowFrame may be destroyed before the axWidget is shown to the new one. As a result, after axWidget's parent change, if the original windowFrame is destroyed before axWidget is shown, a call to axWidget's show() will never take effect. It seems that the record of transcientParent of axWidget's platform window is not updated while calling axWidget's setParent. I take axWidget only as an example but the problem may exist on any toplevel window.


  • Lifetime Qt Champion

    Maybe @hskoglund may have an idea about that matter. I haven't use QAxWidget at all yet.



  • It doesn't matter about the QAxWidget. The problem looks happen on any top level window that has a transient parent. Consider this segment of code:

    	QApplication app(argc, argv);
    	auto widgetA = new QWidget, widgetB = new QWidget;
    	widgetA->setWindowTitle("widgetA");
    	widgetB->setWindowTitle("widgetB");
    	widgetA->show();
    	widgetB->show();
    	auto pushButton = new QPushButton("pushButton");
    	pushButton->setParent(widgetA, Qt::Tool);
    	pushButton->show();
    	QObject::connect(pushButton, &QPushButton::clicked, [=]()
    	{
    		pushButton->setParent(widgetB, Qt::Tool);
    		delete widgetA;
    		pushButton->show();
    	});
    	return app.exec();
    

    When the pushButton is clicked, I change pushButton's parent to widgetB and then delete widgetA, the pushButton is supposed not to be destroyed and show normally as a tool window, right? But it doesn't. Is it a QT-BUG or am I missing something?



  • Hi, using delete on the widget is a bit too abrupt for Qt, better is to use deleteLater, it will accomplish the transfer of ownership in an orderly manner, so something like this:

    ...
    QObject::connect(pushButton, &QPushButton::clicked, [=]()
    {
        pushButton->setParent(widgetB, Qt::Tool);
        widgetA->deleteLater();
        pushButton->show();
    });
    


  • It's ok to call deleteLater() for the example above, but what if the pushButton also needs to show later by receiving some other signals? For example:

    QObject::connect(pushButton, &QPushButton::clicked, [=]()
    {
        pushButton->setParent(widgetB, Qt::Tool);
        widgetA->deleteLater();
        QTimer::singleShot(1000, [=]() { pushButton->show(); });
    });
    

    The pushButton still fail to show. I think maybe it's a better idea to immediately update the transient parent of a toplevel window during the call of its setParent(), instead of update it in the next call of show().



  • Yeah, you need to "anchor" the pushButton to the new QWidget before deleting the old parent QWidget, I usually do a show()/hide() to keep the pushButton happy, e.g. in your case:

    QObject::connect(pushButton, &QPushButton::clicked, [=]()
    {
        pushButton->setParent(widgetB, Qt::Tool);
        widgetA->deleteLater();
        pushButton->show(); pushButton->hide();
        QTimer::singleShot(1000, [=]() { pushButton->show(); });
    });
    

    (Those show()/calls() will not be visible for the user, only needed for keeping the pushButton alive.)



  • Hmm... it may be a workaround for my case. However, the show() and hide() operations are not totally invisible for the user. When I debug the code and step over the first pushButton->show(), taking a break before the pushButton->hide(), I still see a not painted tool window showing there. I guess there might be a very short flash while running on some low performace machines. I'm wondering whether there is something better like ensureReparented(), which is similar to ensurePolished() for getting geometry, font, palette, ... before the widget is shown.
    Anyway, your workaround is acceptable for me at present. Thank you!


Log in to reply