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. Using QTimer::singleShot correctly for updating messages on GUI

Using QTimer::singleShot correctly for updating messages on GUI

Scheduled Pinned Locked Moved Solved General and Desktop
qtimerqlabelqtcreator
8 Posts 5 Posters 2.6k 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.
  • T Offline
    T Offline
    TUStudi
    wrote on 16 Oct 2020, 12:59 last edited by
    #1

    Hi,

    I am creating a GUI application and I do not want to use the status bar or MessageBox for printing info messages to the user. Instead, I am using a QLabel (that can be seen better in the GUI). Whenever I want to print a message for the user, I am using this function (assuiming that "ui->devices" is my QLabel which should print the message):

    void Gui::setStatus(QString statusMessage)
    {
            ui->devices->setText(statusMessage);
            ui->devices->setWordWrap(true);
            QTimer::singleShot(3000, this, [this]{ui->devices->clear();});
    }
    

    So in my case, I am scanning for Bluetooth devices and everytime a Device is found, this function is called with a message like "Found the following device: ..."

    I am using 3 seconds as the waiting time until the message dissapears, but it is clear that if several devices are found within a short time, the message for the respective device will not be displayed on the GUI for a full 3 seconds. The problem is that I expect the very last message to be displayed for exactly 3 seconds, because after that there are no more messages. So for example the device "Test" is the last device that is found, then I expect the message "Found the following device: Test" to appear on the GUI for exactly 3 seconds. Usually it doesn't and sometimes it disappears after less than 2 or 1 second. What exactly could the problem be?

    J 1 Reply Last reply 16 Oct 2020, 13:23
    0
    • C Offline
      C Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 16 Oct 2020, 22:07 last edited by
      #6

      What others already said in a nutshell :

      class Gui 
      {
         ...
         QTimer timer;
      };
      
      Gui::Gui(...)
      {
          ...
          timer.setSingleShot(true); //makes it trigger only once per start() call
          connect(&timer, &QTimer::timeout, this, [&](){  ui->devices->clear(); });
      }
      
      void Gui::setStatus(const QString& statusMessage)
      {
          ui->devices->setText(statusMessage);
          ui->devices->setWordWrap(true);
          timer.start(3000); //this will restart the timer if it was already started
      }
      
      1 Reply Last reply
      5
      • M Offline
        M Offline
        mrjj
        Lifetime Qt Champion
        wrote on 16 Oct 2020, 13:23 last edited by
        #2

        Hi
        The issue is that you start multiple timers regardless if one is in progress already.
        You could use a QTimer instance instead of singleShot and use
        https://doc.qt.io/qt-5/qtimer.html#remainingTime-prop
        to see if a clear is in progress if it is, then restart so any text set, always get full 3 seconds.

        1 Reply Last reply
        5
        • T TUStudi
          16 Oct 2020, 12:59

          Hi,

          I am creating a GUI application and I do not want to use the status bar or MessageBox for printing info messages to the user. Instead, I am using a QLabel (that can be seen better in the GUI). Whenever I want to print a message for the user, I am using this function (assuiming that "ui->devices" is my QLabel which should print the message):

          void Gui::setStatus(QString statusMessage)
          {
                  ui->devices->setText(statusMessage);
                  ui->devices->setWordWrap(true);
                  QTimer::singleShot(3000, this, [this]{ui->devices->clear();});
          }
          

          So in my case, I am scanning for Bluetooth devices and everytime a Device is found, this function is called with a message like "Found the following device: ..."

          I am using 3 seconds as the waiting time until the message dissapears, but it is clear that if several devices are found within a short time, the message for the respective device will not be displayed on the GUI for a full 3 seconds. The problem is that I expect the very last message to be displayed for exactly 3 seconds, because after that there are no more messages. So for example the device "Test" is the last device that is found, then I expect the message "Found the following device: Test" to appear on the GUI for exactly 3 seconds. Usually it doesn't and sometimes it disappears after less than 2 or 1 second. What exactly could the problem be?

          J Offline
          J Offline
          JonB
          wrote on 16 Oct 2020, 13:23 last edited by
          #3

          @TUStudi
          You are creating multiple single-shot timers. They are distinct, not the same one. So whenever, say, the first-created one fires, it will clear whatever last message happens to be shown.

          In a word, to achieve this you must:

          • either cancel any previous, pending single-shot you created whenever you start a new one.
          • or use a repeating timer (e.g. could be every second) and do your own seconds counting, so that you only clear when 3 seconds have elapsed since the last time you showed the message.
          1 Reply Last reply
          4
          • T Offline
            T Offline
            TUStudi
            wrote on 16 Oct 2020, 13:43 last edited by
            #4

            @mrjj thank you. I want teh messages to de displayed in real time, so if 3 devices are discovered within 2 seconds, I ant the messages for the first and secodn devices to be overwritten so that the message for the third device is printed at the same time when this device is discovered. So with your solution I assume, every message will last 3 seconds, right? So for example the message for the 3. device is printed after 6 seconds, although it has been discovered e.g. after 2 seconds?

            @JonB : Thank you too. So cancelling the previous, pending single-shot is a good idea for me. But how can this be done, because I have no object, on which I can call stop() (because QTimer:singleShot is static I guess). So, maybe by using setSingleShot? If yes, how can this be used, because in the documentation, when I click on that function, i am navigated to a (wrong) place: setSingleShot

            1 Reply Last reply
            0
            • C Offline
              C Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on 16 Oct 2020, 13:56 last edited by
              #5

              @TUStudi said in Using QTimer::singleShot correctly for updating messages on GUI:

              because I have no object, on which I can call stop() (because QTimer:singleShot is static I guess).

              Then don't use the static method but a QTimer object.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              1 Reply Last reply
              2
              • C Offline
                C Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on 16 Oct 2020, 22:07 last edited by
                #6

                What others already said in a nutshell :

                class Gui 
                {
                   ...
                   QTimer timer;
                };
                
                Gui::Gui(...)
                {
                    ...
                    timer.setSingleShot(true); //makes it trigger only once per start() call
                    connect(&timer, &QTimer::timeout, this, [&](){  ui->devices->clear(); });
                }
                
                void Gui::setStatus(const QString& statusMessage)
                {
                    ui->devices->setText(statusMessage);
                    ui->devices->setWordWrap(true);
                    timer.start(3000); //this will restart the timer if it was already started
                }
                
                1 Reply Last reply
                5
                • T Offline
                  T Offline
                  TUStudi
                  wrote on 17 Oct 2020, 12:50 last edited by
                  #7

                  @Chris-Kawa Thank you very much, that worked for me (I actually have 6 QLabels, so I now have 6 timer and so on, but this wokrs).

                  Just one more issue (I think, it is not worth it to create an extra thread for that).

                  My QLabels have the sizePolicy horizontal: preferred and vertical: fixed and a vertical length of 20.
                  When a text is displayed, the QLabel expands so that the elements above the QLabel are also moved upwards and after the text disappears, they go back to their initial place. This also happens if the QLabel has a size of 30 or 40 (which is very large), although only one line is displayed in the QLabel. Any idea why this happens? The elements above the QLabels also have the fixed vertical sizepolicy..

                  C 1 Reply Last reply 17 Oct 2020, 14:07
                  0
                  • T TUStudi
                    17 Oct 2020, 12:50

                    @Chris-Kawa Thank you very much, that worked for me (I actually have 6 QLabels, so I now have 6 timer and so on, but this wokrs).

                    Just one more issue (I think, it is not worth it to create an extra thread for that).

                    My QLabels have the sizePolicy horizontal: preferred and vertical: fixed and a vertical length of 20.
                    When a text is displayed, the QLabel expands so that the elements above the QLabel are also moved upwards and after the text disappears, they go back to their initial place. This also happens if the QLabel has a size of 30 or 40 (which is very large), although only one line is displayed in the QLabel. Any idea why this happens? The elements above the QLabels also have the fixed vertical sizepolicy..

                    C Offline
                    C Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on 17 Oct 2020, 14:07 last edited by
                    #8

                    @TUStudi said:

                    I actually have 6 QLabels, so I now have 6 timer and so on

                    Derive a class from QLabel and add that functionality to it. Don't write the same code 6 times!

                    My QLabels have the sizePolicy horizontal: preferred and vertical: fixed and a vertical length of 20.
                    When a text is displayed, the QLabel expands so that the elements above the QLabel are also moved upwards and after the text disappears, they go back to their initial place.

                    Fixed size policy means that widget uses its sizeHint() as the size. If you change the text the size hint also changes, so label grows/shrinks.

                    1 Reply Last reply
                    3

                    1/8

                    16 Oct 2020, 12:59

                    • Login

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