Children QWidgets always on top of parent



  • Hi !

    I got a main window (QMainWindow) with some children (QWidget). Those children widgets are set with the Qt::Window flag (so they stand by themselves on the desktop). However, when the main window gets the focus (e.g. by clicking on it on the desktop), all children stay on top of the main window.

    I would like the main window to appear in front of its children when it gets the focus. I tried different window flags setup but none of them worked.


  • Qt Champions 2016

    Hi, and welcome
    What flags did u use on the children?
    you can try raise() on mainwindow but if u used
    Qt::WindowStaysOnTopHint on children, it might now work.



  • I use the following piece of code to detach children widgets from the mainwindow.

    widget->setWindowFlags( Qt::Window );
    widget->setAttribute( Qt::WA_DeleteOnClose );
    widget->show();
    

    I also tried to use the "raise" method on the mainwindow but the children don't let their parent move to the foreground.


  • Moderators

    Instead of overriding child behavior one by one (window flag and deletion policy) how about not making it a child in the first place?



  • The main window holds the application data and the children widgets operate on these data. The lifetime of the application data and the lifetime of the children widgets are both handled by the main window. By doing this, it is not possible to have a widget pointing to the application data before it has been created or after it has been destroyed since both share the same lifetime.

    However, it seems the parent/child mechanism is responsible for the memory management AND the windows z-ordering.



  • Same problem,

    QWidget *w = new QWidget(this); 
    w->setWindowFlags(Qt::Window);
    w->setAttribute(Qt::WA_DeleteOnClose); 
    w->show();
    

    any advice?


  • Moderators

    Same advice: how about not making it a child?



  • @Tom.C-Dev said:

    The main window holds the application data and the children widgets operate on these data. The lifetime of the application data and the lifetime of the children widgets are both handled by the main window.

    same problem.


  • Moderators

    So just delete the window when the data is destroyed. If you want the window to go away when mainwindow is destroyed you can link them like this:

    QWidget *w = new QWidget(); 
    w->show();
    connect(this, &QMainWindow::destroyed, w, &QWidget::deleteLater);
    


  • Ok, thanks for reply.



  • @Chris-Kawa said:

    QWidget *w = new QWidget();
    w->show();
    connect(this, &QMainWindow::destroyed, w, &QWidget::deleteLater);

    doesn't work, after close main window widget stays.
    Any ideas why?


  • Moderators

    doesn't work

    It works fine. Just not as you think it does.
    By default the application event loop exits when last top level window is closed ( see quitOnLastWindowClosed property).

    The main window is destroyed only after the event loop quits (as the main function scope ends). But the event loop does not quit since there's another top level window. You can force the main winodw to be destroyed when it closes, but then you can't put it on the stack.

    Here's a complete example:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QMainWindow* mainWindow = new QMainWindow();
        mainWindow->setAttribute(Qt::WA_DeleteOnClose);
    
        QWidget* otherWidget = new QWidget();
        QObject::connect(mainWindow, &QMainWindow::destroyed, otherWidget, &QWidget::deleteLater);
    
        mainWindow->show();
        otherWidget->show();
    
        return a.exec();
    }
    

  • Qt Champions 2016

    @Chris-Kawa said:

    The main window is destroyed only after the event loop quits (as the main function scope ends). But the event loop does not quit since there's another top level window. You can force the main winodw to be destroyed when it closes, but then you can't put it on the stack.

    Sorry for interjecting, couldn't one call the close slot on all the child widgets and still use the stack? I mean, instead of subscribing to the destroyed signal, possibly something like this?

    class Controller : public QObject
    {
         Q_OBJECT
    
    signals:
        void closing();
    
    protected:
        virtual bool eventFilter(QObject * watched, QEvent * event)
        {
            if (event->type() == QEvent::Close)
                emit closing();
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        Controller ctrl;
    
        QMainWindow mainWindow;
        mainWindow.installEventFilter(&ctrl);
    
        QWidget otherWidget;
        QObject::connect(&ctrl, SIGNAL(closing()), &otherWidget, SLOT(close()));
    
        mainWindow.show();
        otherWidget.show();
    
        return QApplication::exec();
    }
    

  • Moderators

    @kshegunov Yup, would work too. Personally I try to trim classes when possible. Creating a specialized one when the same can be done in a one time 2 lines of connects/attribute settings seems too "Javish" to me :P
    You would also need a separate header/cpp for the Controller cause you can't put Q_OBJECT in a .cpp file. Not worth the effort IMO.

    But yeah, both solutions work fine and the choice is a matter of preference as to where to put responsibilities.


  • Qt Champions 2016

    @Chris-Kawa said:

    Creating a specialized one when the same can be done in a one time 2 lines of connects/attribute settings seems too "Javish" to me :P

    Right, I agree in principle, however I'd make two points:

    1. Usually people derive from QMainWindow and use it as a controller, then the whole creating a separate class will not be needed, as an override of closeEvent is going to be sufficient.
    2. Ordinarily, I'd have a controller class to initialize my forms anyway (I tend not to derive from the widget classes), so in this case my proposal could also work.

    In any case, I'm just putting it as an option. ;)



  • Thanks for solutions, but seems "doesn't work" for me.
    As I understand "Child" widgets always in main and create with QMainWindow, but i need something like:
    MainWindow->button->clicked->tcpsocket(getSomeData)->MainWindow->readData->createWidgetWithSomeData.


  • Qt Champions 2016

    @Xardas
    Maybe there's a misunderstanding, no one said that creating the widgets in main() is the only way. You can create them anywhere in the code. I believe Chris' suggestion is your best bet. As an example:

    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
        // ... some more code
    
    signals:
        void closed();
    
    private slots:
        void showDataWidget(QByteArray);
    
    protected:
        virtual void closeEvent(QCloseEvent *);
    };
    
    void MainWindow::showDataWidget(QByteArray data)
    {
        // Create the widget
        QWidget * dataWidget = new QWidget(); //< NO PARENT!
        dataWidget->setAttribute(Qt::WA_DeleteOnClose); //< Closing the window will free the memory
    
        // ... Fill up the widget's data ...
        
        QObject::connect(this, SIGNAL(closed()), dataWidget, SLOT(deleteLater()));    //< Connect the clean up routine
    }
    
    void MainWindow::closeEvent(QCloseEvent * event)
    {
        emit closed();
        QMainWindow::closeEvent(event);
    }
    

    This should be easy to adapt to your case.

    Kind regards.



  • @kshegunov
    Yes, misunderstanding. Thanks, work perfectly.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.