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
QtWS25 Last Chance

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 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?

    JonBJ 1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 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
      • mrjjM Offline
        mrjjM Offline
        mrjj
        Lifetime Qt Champion
        wrote on 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

          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?

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on 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 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
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on 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
              • Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on 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 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..

                  Chris KawaC 1 Reply Last reply
                  0
                  • T TUStudi

                    @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..

                    Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on 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

                    • Login

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