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. QMessageBox is not positioned correctly when shown during startup

QMessageBox is not positioned correctly when shown during startup

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 6 Posters 4.2k Views 3 Watching
  • 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.
  • l3u_L Offline
    l3u_L Offline
    l3u_
    wrote on last edited by
    #1

    Hi :-)

    I have a program that takes one command line parameter (the file to load). If something goes wrong while loading the file, a QMessageBox is shown. It's not placed correctly (not centered on the MainWindow), most probably because the show() process is not finished yet when the load function is called.

    Here's a minimalistic example for producing the problem (at least on Linux/KDE):

    main.cpp:

    #include "MainWindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        MainWindow mainWindow;
        mainWindow.show();
        mainWindow.loadTournament();
        return app.exec();
    }
    

    MainWindow.h:

    #include <QMainWindow>
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow();
        void loadTournament();
    };
    

    MainWindow.cpp:

    #include "MainWindow.h"
    #include <QMessageBox>
    
    MainWindow::MainWindow()
    {
        resize(900, 700);
    }
    
    void MainWindow::loadTournament()
    {
        QMessageBox::critical(this, tr("foo"), tr("bar"), QMessageBox::Ok);
    }
    

    I tried to add QApplication::processEvents(); before the load function call, but it doesn't change anything.

    I also tried to add

    QStringList arguments = QCoreApplication::arguments();
    if (arguments.count() > 1) {
        loadTournament(arguments[1]);
    }
    

    to the end of the main window's constructor, but the behavior is exactly the same, also with a QApplication::processEvents(); before.

    I then tried to use a QTimer with the following code added to the end of the constructor:

    QTimer::singleShot(0, this, &MainWindow::checkLoadTournament);
    

    and

    void MainWindow::checkLoadTournament()
    {
        QStringList arguments = QCoreApplication::arguments();
        if (arguments.count() > 1) {
            loadTournament(arguments[1]);
        }
    }
    

    added. This also produces the very same wrong placement of the QMessageBox.

    If I increase the QTimer wait value (to e. g. 100 msecs), it works. But this seems a bit hacky to me, because I can't be sure if the main window is actually shown within this period of time.

    Is there a way to either know if the main window showing and placement is done and finished correctly and wait for this to be done before showing the QMessageBox or to place it to the right position before?

    Thanks in advance for all help!

    m.sueM Taz742T 2 Replies Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      Hi
      I had same issue so i used

      void MainWindow::showEvent ( QShowEvent* ev ) {
        QMainWindow::showEvent ( ev );
        emit MainWindowLoaded();
      }
      

      The other classes then use the MainWindowLoaded signal to know mainwin should be up now.

      Q_ASSERT( connect ( this, SIGNAL ( MainWindowLoaded() ), this, SLOT ( WindowLoaded() ),
      Qt::ConnectionType ( Qt::QueuedConnection | Qt::UniqueConnection ) ));

      This is not perfect as the event might be sent multiple times etc but worked fine for my use case.

      full sample here
      https://stackoverflow.com/questions/14356121/how-to-call-function-after-window-is-shown

      l3u_L 1 Reply Last reply
      2
      • l3u_L l3u_

        Hi :-)

        I have a program that takes one command line parameter (the file to load). If something goes wrong while loading the file, a QMessageBox is shown. It's not placed correctly (not centered on the MainWindow), most probably because the show() process is not finished yet when the load function is called.

        Here's a minimalistic example for producing the problem (at least on Linux/KDE):

        main.cpp:

        #include "MainWindow.h"
        #include <QApplication>
        
        int main(int argc, char *argv[])
        {
            QApplication app(argc, argv);
            MainWindow mainWindow;
            mainWindow.show();
            mainWindow.loadTournament();
            return app.exec();
        }
        

        MainWindow.h:

        #include <QMainWindow>
        
        class MainWindow : public QMainWindow
        {
            Q_OBJECT
        
        public:
            explicit MainWindow();
            void loadTournament();
        };
        

        MainWindow.cpp:

        #include "MainWindow.h"
        #include <QMessageBox>
        
        MainWindow::MainWindow()
        {
            resize(900, 700);
        }
        
        void MainWindow::loadTournament()
        {
            QMessageBox::critical(this, tr("foo"), tr("bar"), QMessageBox::Ok);
        }
        

        I tried to add QApplication::processEvents(); before the load function call, but it doesn't change anything.

        I also tried to add

        QStringList arguments = QCoreApplication::arguments();
        if (arguments.count() > 1) {
            loadTournament(arguments[1]);
        }
        

        to the end of the main window's constructor, but the behavior is exactly the same, also with a QApplication::processEvents(); before.

        I then tried to use a QTimer with the following code added to the end of the constructor:

        QTimer::singleShot(0, this, &MainWindow::checkLoadTournament);
        

        and

        void MainWindow::checkLoadTournament()
        {
            QStringList arguments = QCoreApplication::arguments();
            if (arguments.count() > 1) {
                loadTournament(arguments[1]);
            }
        }
        

        added. This also produces the very same wrong placement of the QMessageBox.

        If I increase the QTimer wait value (to e. g. 100 msecs), it works. But this seems a bit hacky to me, because I can't be sure if the main window is actually shown within this period of time.

        Is there a way to either know if the main window showing and placement is done and finished correctly and wait for this to be done before showing the QMessageBox or to place it to the right position before?

        Thanks in advance for all help!

        m.sueM Offline
        m.sueM Offline
        m.sue
        wrote on last edited by m.sue
        #3

        Hi @l3u_

        The zero length timer is the usual way to go. It should start when the system thinks it has nothing else to do. But paint events are always a bit tricky. If there are more then one in the queue, they get delayed and bundled into one call for efficiency. This "feature" may cause your problem.

        If it appeals to you you can try another hack: Call the timer QTimer::singleShot(0, this, &MainWindow::checkLoadTournament); at the end of your paintEvent, proteced by a flag that is will only be called once.

        EDIT: Oops, almost the same as above.

        -Michael.

        1 Reply Last reply
        1
        • mrjjM mrjj

          Hi
          I had same issue so i used

          void MainWindow::showEvent ( QShowEvent* ev ) {
            QMainWindow::showEvent ( ev );
            emit MainWindowLoaded();
          }
          

          The other classes then use the MainWindowLoaded signal to know mainwin should be up now.

          Q_ASSERT( connect ( this, SIGNAL ( MainWindowLoaded() ), this, SLOT ( WindowLoaded() ),
          Qt::ConnectionType ( Qt::QueuedConnection | Qt::UniqueConnection ) ));

          This is not perfect as the event might be sent multiple times etc but worked fine for my use case.

          full sample here
          https://stackoverflow.com/questions/14356121/how-to-call-function-after-window-is-shown

          l3u_L Offline
          l3u_L Offline
          l3u_
          wrote on last edited by
          #4

          @mrjj I also tried to put the code inside the MainWindow's showEvent at the end, but even this did not make the message box appear at the right position …

          mrjjM 1 Reply Last reply
          0
          • l3u_L l3u_

            Hi :-)

            I have a program that takes one command line parameter (the file to load). If something goes wrong while loading the file, a QMessageBox is shown. It's not placed correctly (not centered on the MainWindow), most probably because the show() process is not finished yet when the load function is called.

            Here's a minimalistic example for producing the problem (at least on Linux/KDE):

            main.cpp:

            #include "MainWindow.h"
            #include <QApplication>
            
            int main(int argc, char *argv[])
            {
                QApplication app(argc, argv);
                MainWindow mainWindow;
                mainWindow.show();
                mainWindow.loadTournament();
                return app.exec();
            }
            

            MainWindow.h:

            #include <QMainWindow>
            
            class MainWindow : public QMainWindow
            {
                Q_OBJECT
            
            public:
                explicit MainWindow();
                void loadTournament();
            };
            

            MainWindow.cpp:

            #include "MainWindow.h"
            #include <QMessageBox>
            
            MainWindow::MainWindow()
            {
                resize(900, 700);
            }
            
            void MainWindow::loadTournament()
            {
                QMessageBox::critical(this, tr("foo"), tr("bar"), QMessageBox::Ok);
            }
            

            I tried to add QApplication::processEvents(); before the load function call, but it doesn't change anything.

            I also tried to add

            QStringList arguments = QCoreApplication::arguments();
            if (arguments.count() > 1) {
                loadTournament(arguments[1]);
            }
            

            to the end of the main window's constructor, but the behavior is exactly the same, also with a QApplication::processEvents(); before.

            I then tried to use a QTimer with the following code added to the end of the constructor:

            QTimer::singleShot(0, this, &MainWindow::checkLoadTournament);
            

            and

            void MainWindow::checkLoadTournament()
            {
                QStringList arguments = QCoreApplication::arguments();
                if (arguments.count() > 1) {
                    loadTournament(arguments[1]);
                }
            }
            

            added. This also produces the very same wrong placement of the QMessageBox.

            If I increase the QTimer wait value (to e. g. 100 msecs), it works. But this seems a bit hacky to me, because I can't be sure if the main window is actually shown within this period of time.

            Is there a way to either know if the main window showing and placement is done and finished correctly and wait for this to be done before showing the QMessageBox or to place it to the right position before?

            Thanks in advance for all help!

            Taz742T Offline
            Taz742T Offline
            Taz742
            wrote on last edited by
            #5

            @l3u_ said in QMessageBox is not positioned correctly when shown during startup:

            void MainWindow::loadTournament()
            {
            QMessageBox::critical(this, tr("foo"), tr("bar"), QMessageBox::Ok);
            }

            try replace this = 0;
            QMessageBox::critical(0, tr("foo"), tr("bar"), QMessageBox::Ok);

            Do what you want.

            l3u_L 1 Reply Last reply
            0
            • l3u_L l3u_

              @mrjj I also tried to put the code inside the MainWindow's showEvent at the end, but even this did not make the message box appear at the right position …

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @l3u_
              hi
              but you do it directly in event func.
              Its not finished happening yet
              I do via eventloop and just tested
              with QMessageBox::critical does show centered.

              l3u_L 1 Reply Last reply
              1
              • Taz742T Taz742

                @l3u_ said in QMessageBox is not positioned correctly when shown during startup:

                void MainWindow::loadTournament()
                {
                QMessageBox::critical(this, tr("foo"), tr("bar"), QMessageBox::Ok);
                }

                try replace this = 0;
                QMessageBox::critical(0, tr("foo"), tr("bar"), QMessageBox::Ok);

                l3u_L Offline
                l3u_L Offline
                l3u_
                wrote on last edited by
                #7

                @Taz742 Well, setting 0 as parent causes (as I would expect it …) the message box to be displayed centered on the screen …

                1 Reply Last reply
                0
                • mrjjM mrjj

                  @l3u_
                  hi
                  but you do it directly in event func.
                  Its not finished happening yet
                  I do via eventloop and just tested
                  with QMessageBox::critical does show centered.

                  l3u_L Offline
                  l3u_L Offline
                  l3u_
                  wrote on last edited by
                  #8

                  @mrjj Okay, when doing it via a signal, I could know when the window is set up completely. But how could I do the actual function call? Using a timer that checks periodically if some variable is set to true by the slot called after the show event? I mean, I don't want to call the load function always when the window is shown, but only if it's requested on the command line!

                  mrjjM 1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Hi,

                    Just a quick note: never put any function all in a Q_ASSERT or a classic assert expression. The function will never be called in release mode. Store the result of the function and assert on that.

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    2
                    • l3u_L l3u_

                      @mrjj Okay, when doing it via a signal, I could know when the window is set up completely. But how could I do the actual function call? Using a timer that checks periodically if some variable is set to true by the slot called after the show event? I mean, I don't want to call the load function always when the window is shown, but only if it's requested on the command line!

                      mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @l3u_
                      Hi
                      Mine is like this

                      ctor..
                      Q_ASSERT( connect ( this, SIGNAL ( MainWindowLoaded() ), this, SLOT ( WindowLoaded() ),
                                            Qt::ConnectionType ( Qt::QueuedConnection | Qt::UniqueConnection ) ));
                      
                      void MainWindow::showEvent ( QShowEvent* ev ) {
                        QMainWindow::showEvent ( ev );
                        emit MainWindowLoaded();
                      }
                      
                      // the slot do thestuff
                      void MainWindow::WindowLoaded() {
                      real stuff
                      

                      However, as m.sue says, one shot timer is might just be cleaner for you :)

                      l3u_L 1 Reply Last reply
                      0
                      • mrjjM mrjj

                        @l3u_
                        Hi
                        Mine is like this

                        ctor..
                        Q_ASSERT( connect ( this, SIGNAL ( MainWindowLoaded() ), this, SLOT ( WindowLoaded() ),
                                              Qt::ConnectionType ( Qt::QueuedConnection | Qt::UniqueConnection ) ));
                        
                        void MainWindow::showEvent ( QShowEvent* ev ) {
                          QMainWindow::showEvent ( ev );
                          emit MainWindowLoaded();
                        }
                        
                        // the slot do thestuff
                        void MainWindow::WindowLoaded() {
                        real stuff
                        

                        However, as m.sue says, one shot timer is might just be cleaner for you :)

                        l3u_L Offline
                        l3u_L Offline
                        l3u_
                        wrote on last edited by
                        #11

                        @mrjj said in QMessageBox is not positioned correctly when shown during startup:

                        However, as m.sue says, one shot timer is might just be cleaner for you :)

                        I also think so, but what is the reason that the One-Shot-Timer with 0 delay does not change the result whereas the one with 100 ms delay causes the message box to be positionned correctly? Or asking the other way: what delay should I choose to be sure that the main window is always setup completely?

                        jsulmJ mrjjM 2 Replies Last reply
                        0
                        • l3u_L l3u_

                          @mrjj said in QMessageBox is not positioned correctly when shown during startup:

                          However, as m.sue says, one shot timer is might just be cleaner for you :)

                          I also think so, but what is the reason that the One-Shot-Timer with 0 delay does not change the result whereas the one with 100 ms delay causes the message box to be positionned correctly? Or asking the other way: what delay should I choose to be sure that the main window is always setup completely?

                          jsulmJ Offline
                          jsulmJ Offline
                          jsulm
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          @l3u_ In my opinion the timer solution is in this case not very clean. As you already noticed you do not know how long it will take. The solution from @mrjj is is much cleaner.

                          https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          0
                          • l3u_L l3u_

                            @mrjj said in QMessageBox is not positioned correctly when shown during startup:

                            However, as m.sue says, one shot timer is might just be cleaner for you :)

                            I also think so, but what is the reason that the One-Shot-Timer with 0 delay does not change the result whereas the one with 100 ms delay causes the message box to be positionned correctly? Or asking the other way: what delay should I choose to be sure that the main window is always setup completely?

                            mrjjM Offline
                            mrjjM Offline
                            mrjj
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @l3u_
                            Well you can time it and find a good value.
                            or make it large enough that it will always be enough.

                            1 Reply Last reply
                            0

                            • Login

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