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. QProgressDialog does not take input unless the progress value changes
Forum Updated to NodeBB v4.3 + New Features

QProgressDialog does not take input unless the progress value changes

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 6 Posters 953 Views 2 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.
  • Christian EhrlicherC Offline
    Christian EhrlicherC Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by
    #5

    When you block the event loop - how should the ui be redrawn? Use the canceld() signal and don't block the event loop...

    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
    3
    • S Offline
      S Offline
      SimonSchroeder
      wrote on last edited by
      #6

      At some point the mouse events need to be processed. For this the event loop needs to run. It is very likely that you are blocking the event loop. There might be some weird behavior when calling setValue with a different progress that uses some direct connection to update the progress bar and also somehow processes the mouse event.

      As a quick test you can call QApplication::processEvents() right before your call to wasCanceled() to see if this solves your problem. If it does you are definitely blocking the event loop. However, don't use this trick as your final solution. Your current loop will take about 100 times longer if you do this. It is not worth to slow down your actual processing by 100x just to have a nice UI.

      Instead, then your solution should be to use a separate worker thread. You are not allowed to call any UI functions from the worker thread: no call to wasCanceled and no call to setValue. Instead you need to use signals and slots to connect these function calls.

      1 Reply Last reply
      1
      • J JanLaloux

        I have a classic QProgressDialog and while the processing proceeds the method "wasCanceled()" is regularly called to check if the user pressed the Cancel button. This works, but as long as the progress value is not changed the Clear button is completly unreactive. You can click on it but wasCanceled() will return false. Only when the progress value changes the click on the button is captured. Unfortunately, in this case it is not possible to increasing the update of the progress value.

        I tried this when checking for cancelation:

        progress->setValue( progress->value() ); 
        canceled = progress->wasCanceled();
        

        but that does not help, still got false as return value.

        My fix for the moment is:

        int value = progress->value();
        progress->setValue( value+1 );
        progress->setValue( value );
        canceled = progress->wasCanceled();
        

        and this works. But this is ugly of course.
        Is there another solution to this?

        andrewmorganA Offline
        andrewmorganA Offline
        andrewmorgan
        wrote on last edited by
        #7

        @JanLaloux You’re right! Manually incrementing and resetting the progress value is not ideal. A cleaner approach could be calling QCoreApplication::processEvents() inside your loop to allow UI events (like button clicks) to be processed without artificially changing the progress value. You might also try setAutoReset(false) or setMinimumDuration(0) to see if it improves responsiveness.

        JonBJ 1 Reply Last reply
        0
        • andrewmorganA andrewmorgan

          @JanLaloux You’re right! Manually incrementing and resetting the progress value is not ideal. A cleaner approach could be calling QCoreApplication::processEvents() inside your loop to allow UI events (like button clicks) to be processed without artificially changing the progress value. You might also try setAutoReset(false) or setMinimumDuration(0) to see if it improves responsiveness.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #8

          @andrewmorgan
          It would not be ideal to call processEvents(). It would be better to allow the main event loop to run and raise and act on the canceled() signal, as previously written.

          Pl45m4P 1 Reply Last reply
          2
          • J Offline
            J Offline
            JanLaloux
            wrote on last edited by
            #9

            Thanks all for the valuable input!

            @SimonSchroeder: the test with QApplication::processEvents() is positive, the problem goes away.
            BUT: the implementation is as documented for the QProgressDialog Class for the modal operation:
            "Compared to a modeless QProgressDialog, a modal QProgressDialog is simpler to use for the programmer. Do the operation in a loop, call setValue() at intervals, and check for cancellation with wasCanceled(). "
            So with the functions, not the signals.
            And since it is the intention that the user cannot do anything than either wait for the operation to finish, or to cancel it, this seems to me correct for the modal operation?

            Christian EhrlicherC 1 Reply Last reply
            0
            • JonBJ JonB

              @andrewmorgan
              It would not be ideal to call processEvents(). It would be better to allow the main event loop to run and raise and act on the canceled() signal, as previously written.

              Pl45m4P Offline
              Pl45m4P Offline
              Pl45m4
              wrote on last edited by
              #10

              @JonB said in QProgressDialog does not take input unless the progress value changes:

              It would not be ideal to call processEvents()

              The only valid use case for processEvent() to update the progress of QProgressDialog/ QProgressBar is when using it in combination with tasks that run in main.cpp before the event loop is even started or like everything QSplashScreen related...


              If debugging is the process of removing software bugs, then programming must be the process of putting them in.

              ~E. W. Dijkstra

              1 Reply Last reply
              0
              • J JanLaloux

                Thanks all for the valuable input!

                @SimonSchroeder: the test with QApplication::processEvents() is positive, the problem goes away.
                BUT: the implementation is as documented for the QProgressDialog Class for the modal operation:
                "Compared to a modeless QProgressDialog, a modal QProgressDialog is simpler to use for the programmer. Do the operation in a loop, call setValue() at intervals, and check for cancellation with wasCanceled(). "
                So with the functions, not the signals.
                And since it is the intention that the user cannot do anything than either wait for the operation to finish, or to cancel it, this seems to me correct for the modal operation?

                Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #11

                @JanLaloux said in QProgressDialog does not take input unless the progress value changes:

                Compared to a modeless QProgressDialog, a modal QProgressDialog is simpler to use for the programmer. Do the operation in a loop, call setValue() at intervals, and check for cancellation with wasCanceled(). "
                So with the functions, not the signals.

                We should adjust the documentation... blocking the event loop is a bad idea.

                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
                0
                • S Offline
                  S Offline
                  SimonSchroeder
                  wrote on last edited by
                  #12

                  Usually you'll see a pulsing inside the progress bar. If you depend on calling setValue this will not be smooth. It'll always look like your application is hanging. And if you call setValue too often (i.e. often enough for the progress bar to be smooth) it will significantly slow down your actual work. Also, in the former case Windows might report "Not responding" (especially when clicking "Cancel").

                  We were looking for an easy solution (in our case to just do little changes to our existing code) to fix this problem. What we came up with you can find here: https://github.com/SimonSchroeder/QtThreadHelper. It's a simple header-only library where you can easily create a worker thread using just a lambda and a helper function guiThread to just call setValue inside the GUI thread right from your worker thread. You should still connect the canceled signal to react to this.

                  JonBJ 1 Reply Last reply
                  2
                  • S SimonSchroeder

                    Usually you'll see a pulsing inside the progress bar. If you depend on calling setValue this will not be smooth. It'll always look like your application is hanging. And if you call setValue too often (i.e. often enough for the progress bar to be smooth) it will significantly slow down your actual work. Also, in the former case Windows might report "Not responding" (especially when clicking "Cancel").

                    We were looking for an easy solution (in our case to just do little changes to our existing code) to fix this problem. What we came up with you can find here: https://github.com/SimonSchroeder/QtThreadHelper. It's a simple header-only library where you can easily create a worker thread using just a lambda and a helper function guiThread to just call setValue inside the GUI thread right from your worker thread. You should still connect the canceled signal to react to this.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by
                    #13

                    @SimonSchroeder
                    All very impressive! Nicely written up --- does your company give you time to write that up and publish it, or did you do that in your own time?

                    S 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @SimonSchroeder
                      All very impressive! Nicely written up --- does your company give you time to write that up and publish it, or did you do that in your own time?

                      S Offline
                      S Offline
                      SimonSchroeder
                      wrote on last edited by
                      #14

                      @JonB, thank you! It does not happen very often, but this I could write on company time. We need the documentation anyways.

                      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