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.6k 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.
  • 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