Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QMainWindow can't appear in front of child QWidget
QtWS25 Last Chance

QMainWindow can't appear in front of child QWidget

Scheduled Pinned Locked Moved Solved General and Desktop
qmainwindowqwidget
15 Posts 5 Posters 6.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    skebanga
    wrote on 8 Apr 2016, 14:52 last edited by
    #1

    I have a desktop application with a single QMainWindow.

    The user can being up multiple supplementary windows (derived from QWidget)

    Closing a supplementary window has no effect on the rest of the application.

    However, closing the QMainWindow should close all other windows and shut down the application.

    As such, when creating my new supplementary windows I pass my QMainWindow as parent

    void MainWindow::onShowPlotClick()
    {
        PlotWindow* plot_window = new PlotWindow(this);
        ....
        plot_window->show();
    }
    

    In my PlotWindow constructor I set window flags

    PlotWindow::PlotWindow(QWidget* parent)
        : QWidget(parent)
    {
        setWindowFlags(windowFlags() | Qt::Window);
    
        QVBoxLayout* layout = new QVBoxLayout;
        setLayout(layout);
        ....
    }
    

    This all works well, and has the desired effect of closing my QMainWindow also closes all supplementary windows.

    However, it is not possible to bring my QMainWindow in front of it's child QWidgets

    As you can see in this screenshot, the QMainWindow has focus, but is hidden behind the plot windows.

    img1

    And in this screenshot you can see that each plot window can float above the other, it's just the QMainWindow which can't.

    img2

    If I set the parent of my PlotWindow to nullptr, then i can bring QMainWindow above it.

    void MainWindow::onShowPlotClick()
    {
        PlotWindow* plot_window = new PlotWindow(nullptr);
        ....
        plot_window->show();
    }
    

    Here you can see QMainWindow can come to the front:

    img3

    but now I've lost the ability to close all child windows when QMainWindow closes. Here you can see I've closed QMainWindow and the PlotWindow stays visible

    img4

    1 Reply Last reply
    0
    • C Offline
      C Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 8 Apr 2016, 16:54 last edited by Chris Kawa 4 Aug 2016, 16:55
      #2

      This is standard behavior. It is intended that child windows don't get obscured by their parents.

      The solution is not to set the parent as you did. With an extra line of code you can still have windows destroyed when the main window goes away:

      QWidget* foo = new QWidget;
      connect(mainWindow, &MainWindow::destroyed, foo, &QWidget::deleteLater);
      foo->show();
      

      There's just a little problem here. By default the application loop exits when the last window is closed. With the above, closing main window will no longer exit the loop (as there are other windows opened). This means that the main window won't be destroyed when it's closed and so the children won't be either (until you manually close all the windows).
      An easy fix for this is to create the main window on the heap and set an attribute for it, so it would look something like this:

      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          MainWindow* mainWindow = new MainWindow;
          mainWindow->setAttribute(Qt::WA_DeleteOnClose);
          mainWindow->show();
      
          QWidget* foo = new QWidget;
          QObject::connect(mainWindow, &MainWindow::destroyed, foo, &QWidget::deleteLater);
          foo->show();
      
          return a.exec();
      }
      
      J 1 Reply Last reply 9 Apr 2016, 00:45
      2
      • S Offline
        S Offline
        skebanga
        wrote on 8 Apr 2016, 19:15 last edited by
        #3

        Awesome, thanks!!

        1 Reply Last reply
        0
        • C Chris Kawa
          8 Apr 2016, 16:54

          This is standard behavior. It is intended that child windows don't get obscured by their parents.

          The solution is not to set the parent as you did. With an extra line of code you can still have windows destroyed when the main window goes away:

          QWidget* foo = new QWidget;
          connect(mainWindow, &MainWindow::destroyed, foo, &QWidget::deleteLater);
          foo->show();
          

          There's just a little problem here. By default the application loop exits when the last window is closed. With the above, closing main window will no longer exit the loop (as there are other windows opened). This means that the main window won't be destroyed when it's closed and so the children won't be either (until you manually close all the windows).
          An easy fix for this is to create the main window on the heap and set an attribute for it, so it would look something like this:

          int main(int argc, char *argv[])
          {
              QApplication a(argc, argv);
          
              MainWindow* mainWindow = new MainWindow;
              mainWindow->setAttribute(Qt::WA_DeleteOnClose);
              mainWindow->show();
          
              QWidget* foo = new QWidget;
              QObject::connect(mainWindow, &MainWindow::destroyed, foo, &QWidget::deleteLater);
              foo->show();
          
              return a.exec();
          }
          
          J Offline
          J Offline
          JKSH
          Moderators
          wrote on 9 Apr 2016, 00:45 last edited by
          #4

          @Chris-Kawa said:

          With an extra line of code you can still have windows destroyed when the main window goes away:

          QWidget* foo = new QWidget;
          connect(mainWindow, &MainWindow::destroyed, foo, &QWidget::deleteLater);
          foo->show();
          

          Alternatively, instead of connecting every single supplementary window, you can simply quit the application when the main window is destroyed:

          connect(mainWindow, &MainWindow::destroyed, qApp, &QApplication::quit);
          

          This will automatically close all windows.

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          K 1 Reply Last reply 9 Apr 2016, 09:54
          1
          • J JKSH
            9 Apr 2016, 00:45

            @Chris-Kawa said:

            With an extra line of code you can still have windows destroyed when the main window goes away:

            QWidget* foo = new QWidget;
            connect(mainWindow, &MainWindow::destroyed, foo, &QWidget::deleteLater);
            foo->show();
            

            Alternatively, instead of connecting every single supplementary window, you can simply quit the application when the main window is destroyed:

            connect(mainWindow, &MainWindow::destroyed, qApp, &QApplication::quit);
            

            This will automatically close all windows.

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 9 Apr 2016, 09:54 last edited by
            #5

            @JKSH

            This will automatically close all windows.

            But will it free the memory associated with each of them?

            Read and abide by the Qt Code of Conduct

            J 1 Reply Last reply 9 Apr 2016, 12:03
            0
            • K kshegunov
              9 Apr 2016, 09:54

              @JKSH

              This will automatically close all windows.

              But will it free the memory associated with each of them?

              J Offline
              J Offline
              JKSH
              Moderators
              wrote on 9 Apr 2016, 12:03 last edited by
              #6

              @kshegunov said:

              @JKSH

              This will automatically close all windows.

              But will it free the memory associated with each of them?

              Hmm... not directly, I guess.

              I know that there's an ongoing debate about whether or not it's appropriate to let the OS reclaim some unfreed memory upon program shutdown. I'm in the camp that thinks this is OK.

              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

              K S 2 Replies Last reply 10 Apr 2016, 16:53
              0
              • J JKSH
                9 Apr 2016, 12:03

                @kshegunov said:

                @JKSH

                This will automatically close all windows.

                But will it free the memory associated with each of them?

                Hmm... not directly, I guess.

                I know that there's an ongoing debate about whether or not it's appropriate to let the OS reclaim some unfreed memory upon program shutdown. I'm in the camp that thinks this is OK.

                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 10 Apr 2016, 16:53 last edited by
                #7

                @JKSH

                I know that there's an ongoing debate ... I'm in the camp that thinks this is OK

                I don't know of such debate, but I suppose I'd be on the side opposite to yours. However, I'll grant you, it should be okay either way.

                Read and abide by the Qt Code of Conduct

                W 1 Reply Last reply 24 Apr 2016, 14:57
                0
                • C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 10 Apr 2016, 20:06 last edited by
                  #8

                  This could probably be cleaned up very easily with something like this (haven't tested):

                  ...
                  a.exec();
                  qDeleteAll(a.topLevelWidgets());
                  

                  assuming all the windows, including main window, are created on the heap and have no parents.

                  J 1 Reply Last reply 24 Apr 2016, 11:47
                  0
                  • J JKSH
                    9 Apr 2016, 12:03

                    @kshegunov said:

                    @JKSH

                    This will automatically close all windows.

                    But will it free the memory associated with each of them?

                    Hmm... not directly, I guess.

                    I know that there's an ongoing debate about whether or not it's appropriate to let the OS reclaim some unfreed memory upon program shutdown. I'm in the camp that thinks this is OK.

                    S Offline
                    S Offline
                    skebanga
                    wrote on 12 Apr 2016, 20:25 last edited by
                    #9

                    @JKSH said:

                    But will it free the memory associated with each of them?

                    Hmm... not directly, I guess.

                    I know that there's an ongoing debate about whether or not it's appropriate to let the OS reclaim some unfreed memory upon program shutdown. I'm in the camp that thinks this is OK.

                    This won't work for me, as I have various RAII style classes which save settings to disk, etc in their destructors.

                    If the containing window's destructor doesn't get called, then these classes won't destruct, and the settings won't get saved.

                    Some windows are opened and closed during the app's lifetime - so I also don't want to wait until application shutdown to reclaim memory.

                    Thanks for the input though - it is appreciated, even if it doesn't fit my needs on this particular occasion exactly!

                    1 Reply Last reply
                    0
                    • C Chris Kawa
                      10 Apr 2016, 20:06

                      This could probably be cleaned up very easily with something like this (haven't tested):

                      ...
                      a.exec();
                      qDeleteAll(a.topLevelWidgets());
                      

                      assuming all the windows, including main window, are created on the heap and have no parents.

                      J Offline
                      J Offline
                      JKSH
                      Moderators
                      wrote on 24 Apr 2016, 11:47 last edited by
                      #10

                      @Chris-Kawa said:

                      This could probably be cleaned up very easily with something like this (haven't tested):

                      ...
                      a.exec();
                      qDeleteAll(a.topLevelWidgets());
                      

                      assuming all the windows, including main window, are created on the heap and have no parents.

                      I just discovered that direct deletions can cause QComboBox (and possibly other complex widgets) to crash.

                      I think part of the reason is that the QComboBox instantiates a QComboBoxPrivateContainer, which also becomes a top-level widget. There's probably a double-deletion somewhere if we use a direct deletion instead of deleteLater() (I haven't dug too deep to find out).

                      So, manually deleting widgets after the event loop ends is a no-go :-/

                      @skebanga said:

                      Thanks for the input though - it is appreciated, even if it doesn't fit my needs on this particular occasion exactly!

                      No worries, that's what discussions are for :-) All the best with your project!

                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                      K 1 Reply Last reply 24 Apr 2016, 14:44
                      0
                      • J JKSH
                        24 Apr 2016, 11:47

                        @Chris-Kawa said:

                        This could probably be cleaned up very easily with something like this (haven't tested):

                        ...
                        a.exec();
                        qDeleteAll(a.topLevelWidgets());
                        

                        assuming all the windows, including main window, are created on the heap and have no parents.

                        I just discovered that direct deletions can cause QComboBox (and possibly other complex widgets) to crash.

                        I think part of the reason is that the QComboBox instantiates a QComboBoxPrivateContainer, which also becomes a top-level widget. There's probably a double-deletion somewhere if we use a direct deletion instead of deleteLater() (I haven't dug too deep to find out).

                        So, manually deleting widgets after the event loop ends is a no-go :-/

                        @skebanga said:

                        Thanks for the input though - it is appreciated, even if it doesn't fit my needs on this particular occasion exactly!

                        No worries, that's what discussions are for :-) All the best with your project!

                        K Offline
                        K Offline
                        kshegunov
                        Moderators
                        wrote on 24 Apr 2016, 14:44 last edited by kshegunov
                        #11

                        @JKSH said:

                        I just discovered that direct deletions can cause QComboBox (and possibly other complex widgets) to crash.

                        I think part of the reason is that the QComboBox instantiates a QComboBoxPrivateContainer, which also becomes a top-level widget.

                        This is certainly curious. Maybe I can ask something ... suppose you create a widget on the stack and don't give it a parent. And after the constructor runs you add it to a layout (which I believe should take the ownership of said widget away). Does this widget count as top-level, and does it acquire a native handle (i.e. it is a native widget)? I should think not, or am I in error? Am I correct in assuming that its alien/native status is undefined until QWidget::create is run?

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        0
                        • K kshegunov
                          10 Apr 2016, 16:53

                          @JKSH

                          I know that there's an ongoing debate ... I'm in the camp that thinks this is OK

                          I don't know of such debate, but I suppose I'd be on the side opposite to yours. However, I'll grant you, it should be okay either way.

                          W Offline
                          W Offline
                          Wurgl
                          wrote on 24 Apr 2016, 14:57 last edited by
                          #12

                          @kshegunov It does not matter. What if an application crashes? Who cleans up the memory in that case? Who closes the file descriptors? Who closes all network connections? Who frees up file locks or locks of devices like a serial device, an USB-port …?

                          Guess? It is easy!

                          It is the operating system. It is always the operating system, yo do not have to free all resources before exiting the application.

                          If the operating system would not, your computer/smartphone/whatever would get filled up with chunk after a few crashes and would refuse to start new applications due to lack of memory or due to locked files ...

                          And no! MS-DOS was not an operating system. MS-DOS was some kind of runtime library, since it did not clean up those resources, at least not all.

                          So do not waste your time with such discussions.

                          K 1 Reply Last reply 24 Apr 2016, 15:25
                          0
                          • W Wurgl
                            24 Apr 2016, 14:57

                            @kshegunov It does not matter. What if an application crashes? Who cleans up the memory in that case? Who closes the file descriptors? Who closes all network connections? Who frees up file locks or locks of devices like a serial device, an USB-port …?

                            Guess? It is easy!

                            It is the operating system. It is always the operating system, yo do not have to free all resources before exiting the application.

                            If the operating system would not, your computer/smartphone/whatever would get filled up with chunk after a few crashes and would refuse to start new applications due to lack of memory or due to locked files ...

                            And no! MS-DOS was not an operating system. MS-DOS was some kind of runtime library, since it did not clean up those resources, at least not all.

                            So do not waste your time with such discussions.

                            K Offline
                            K Offline
                            kshegunov
                            Moderators
                            wrote on 24 Apr 2016, 15:25 last edited by
                            #13

                            @Wurgl

                            It does not matter.

                            It does, and it's proven in the OP's final post, where he notes he has clean-up code running in the destructors of his objects.

                            What if an application crashes?

                            Then the application has a bug and that needs to be addressed.

                            Who cleans up the memory in that case? Who closes the file descriptors? Who closes all network connections? Who frees up file locks or locks of devices like a serial device, an USB-port …?

                            The programmer should do that. Some OS-es do it as a safety net to leave things consistent, but certainly not all and certainly not always!

                            yo do not have to free all resources before exiting the application.

                            This claim is a bit presumptuous, to put it mildly. And if you ask me it is a lazy, and not very smart thing to do. No one referenced MSDOS at any of the posts, but if you had ever used some code that uses global resources, you'd know that it's a good idea to clean up your mess, especially if someone is trying to shut you down forcefully!

                            What do you think happens if an application crashes (or is terminated) while holding a reference to a global mutex? Do you think the OS knows that the global mutex must be unlocked? Suppose it's a real-time sensitive program used for air traffic meteorological information, so what do we do then? (I had such a case where someone writing the controlling UI decided it's a good idea to terminate me forcefully) Are we saying "well, wait a bit until I restart the OS"? It can make all the difference in the world if the pilot is flying through a storm, you should think about it next time you board.

                            Read and abide by the Qt Code of Conduct

                            W 1 Reply Last reply 24 Apr 2016, 16:15
                            0
                            • K kshegunov
                              24 Apr 2016, 15:25

                              @Wurgl

                              It does not matter.

                              It does, and it's proven in the OP's final post, where he notes he has clean-up code running in the destructors of his objects.

                              What if an application crashes?

                              Then the application has a bug and that needs to be addressed.

                              Who cleans up the memory in that case? Who closes the file descriptors? Who closes all network connections? Who frees up file locks or locks of devices like a serial device, an USB-port …?

                              The programmer should do that. Some OS-es do it as a safety net to leave things consistent, but certainly not all and certainly not always!

                              yo do not have to free all resources before exiting the application.

                              This claim is a bit presumptuous, to put it mildly. And if you ask me it is a lazy, and not very smart thing to do. No one referenced MSDOS at any of the posts, but if you had ever used some code that uses global resources, you'd know that it's a good idea to clean up your mess, especially if someone is trying to shut you down forcefully!

                              What do you think happens if an application crashes (or is terminated) while holding a reference to a global mutex? Do you think the OS knows that the global mutex must be unlocked? Suppose it's a real-time sensitive program used for air traffic meteorological information, so what do we do then? (I had such a case where someone writing the controlling UI decided it's a good idea to terminate me forcefully) Are we saying "well, wait a bit until I restart the OS"? It can make all the difference in the world if the pilot is flying through a storm, you should think about it next time you board.

                              W Offline
                              W Offline
                              Wurgl
                              wrote on 24 Apr 2016, 16:15 last edited by
                              #14

                              @kshegunov Yes, there are cases where the application crashed caused by some cleanup code which gets called within exit() (which is still the application and not the OS itself).

                              And yes, globally shared things like Shared Memory, Semaphores, Named Pipes and such are not cleaned up, but those are intended to be used by multiple processes to communicate. They cannot be cleaned, because they are not owned exclusive by a program.

                              I mentioned DOS, because of history. Back in DOS-times you had to clean up everything before exiting, otherwise you had to reboot the machine very often. That time I hacked a few Terminate-and-Stay-Resident programs, it was a hell!

                              1 Reply Last reply
                              0
                              • S Offline
                                S Offline
                                skebanga
                                wrote on 24 Apr 2016, 16:30 last edited by
                                #15

                                IMO it's a code smell to rely on the OS to clean up for you.

                                We run all of our unit tests through valgrind as part of our build process, so that a memory leak breaks the build.

                                QT leaves a ridiculous amount of memory lying around, which of course kicks off valgrind.

                                We've got a huge suppressions file which we have to install for every GUI related unit test, and the sheer number of suppressions makes valgrind run slower, so has resulted in longer build times.

                                So yeah, in my opinion, it would be nice if QT didn't do that.

                                1 Reply Last reply
                                1

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved