Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Updating QProgressBars running on thread with values from main
Forum Updated to NodeBB v4.3 + New Features

Updating QProgressBars running on thread with values from main

Scheduled Pinned Locked Moved Unsolved Qt for Python
9 Posts 4 Posters 2.7k Views 1 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.
  • T Offline
    T Offline
    TheAlmeida
    wrote on last edited by TheAlmeida
    #1

    Hi, I am not well versed in programming and I am pretty new to Python and QT, so I am sorry if I will present my question wrong and I would be glad to try and elaborate on it in a different way.

    What I would like to do is change the value of the progress bars on my GUI (that is running on a thread). This value would be calculated outside the thread, in the "main code".

    Although I can change the value of the progressbars on initialization what I would really like to be able to do is change them dinamically.

    val = 0
    
    class Ui(QtWidgets.QMainWindow):
        def __init__(self):
            super(Ui, self).__init__()
            uic.loadUi('PBL3_designer.ui', self) 
    
            self.progbar1= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar1')
            self.progbar2= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar2')
            self.progbar3= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar3')
    
        # Function to update prog bars
        def updateProgressBar(self):
            self.prog_bar_cinza1.setValue(val)
            self.prog_bar_cinza2.setValue(val*2)
            self.prog_bar_cores1.setValue(val*3)
    
    def interface():
        app = QtWidgets.QApplication(sys.argv)
        ex = Ui()
        app.exec_()
    
    
    # MAIN
    # Starting the thread
    t = threading.Thread(target=interface)
    t.daemon = True
    t.start()
    time.sleep(1)
    

    How how I be able to call updateProgressBar() from outside the thread?

    I've tried JonB's solution but I am not sure I am placing it right (at the moment it is defined outside the Ui class) I get the error AttributeError: type object 'QMainWindow' has no attribute 'instance'

    The full code I am running right now to try and change the prog bars is as follows:

    import PyQt5.QtWidgets
    from PyQt5 import QtWidgets, uic
    import pbl3_rc
    import sys
    import time
    import threading
    import typing
    
    
    val = 0
    
    class Ui(QtWidgets.QMainWindow):
        def __init__(self):
            super(Ui, self).__init__()
            uic.loadUi('PBL3_designer.ui', self) 
    
            self.progbar1= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar1')
            self.progbar2= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar2')
            self.progbar3= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar3')
    
        # Function to update prog bars
        def updateProgressBar(self):
            self.progbar1.setValue(val)
            self.progbar2.setValue(val*2)
            self.progbar3.setValue(val*3)
    
    # JonB's solution
    def findMainWindow() -> typing.Union[QtWidgets.QMainWindow, None]:
        app = QtWidgets.QMainWindow.instance()
        for widget in app.topLevelWidgets():
            if isinstance(widget, QtWidgets.QMainWindow):
                return widget
        return None
    
    
    def interface():
        app = QtWidgets.QApplication(sys.argv)
        ex = Ui()
        app.exec_()
    
    
    # MAIN
    # Starting the thread
    t = threading.Thread(target=interface)
    t.daemon = True
    t.start()
    time.sleep(1)
    
    # Trying to find Main Window
    gui = findMainWindow()
    for i in range(5):
        val += 1
        # Trying to update prog bar value
        gui.updateProgressBar()
    
    while True:
        ();
    

    Thank you for reading :)

    jsulmJ JonBJ 2 Replies Last reply
    0
    • T TheAlmeida

      Hi, I am not well versed in programming and I am pretty new to Python and QT, so I am sorry if I will present my question wrong and I would be glad to try and elaborate on it in a different way.

      What I would like to do is change the value of the progress bars on my GUI (that is running on a thread). This value would be calculated outside the thread, in the "main code".

      Although I can change the value of the progressbars on initialization what I would really like to be able to do is change them dinamically.

      val = 0
      
      class Ui(QtWidgets.QMainWindow):
          def __init__(self):
              super(Ui, self).__init__()
              uic.loadUi('PBL3_designer.ui', self) 
      
              self.progbar1= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar1')
              self.progbar2= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar2')
              self.progbar3= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar3')
      
          # Function to update prog bars
          def updateProgressBar(self):
              self.prog_bar_cinza1.setValue(val)
              self.prog_bar_cinza2.setValue(val*2)
              self.prog_bar_cores1.setValue(val*3)
      
      def interface():
          app = QtWidgets.QApplication(sys.argv)
          ex = Ui()
          app.exec_()
      
      
      # MAIN
      # Starting the thread
      t = threading.Thread(target=interface)
      t.daemon = True
      t.start()
      time.sleep(1)
      

      How how I be able to call updateProgressBar() from outside the thread?

      I've tried JonB's solution but I am not sure I am placing it right (at the moment it is defined outside the Ui class) I get the error AttributeError: type object 'QMainWindow' has no attribute 'instance'

      The full code I am running right now to try and change the prog bars is as follows:

      import PyQt5.QtWidgets
      from PyQt5 import QtWidgets, uic
      import pbl3_rc
      import sys
      import time
      import threading
      import typing
      
      
      val = 0
      
      class Ui(QtWidgets.QMainWindow):
          def __init__(self):
              super(Ui, self).__init__()
              uic.loadUi('PBL3_designer.ui', self) 
      
              self.progbar1= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar1')
              self.progbar2= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar2')
              self.progbar3= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar3')
      
          # Function to update prog bars
          def updateProgressBar(self):
              self.progbar1.setValue(val)
              self.progbar2.setValue(val*2)
              self.progbar3.setValue(val*3)
      
      # JonB's solution
      def findMainWindow() -> typing.Union[QtWidgets.QMainWindow, None]:
          app = QtWidgets.QMainWindow.instance()
          for widget in app.topLevelWidgets():
              if isinstance(widget, QtWidgets.QMainWindow):
                  return widget
          return None
      
      
      def interface():
          app = QtWidgets.QApplication(sys.argv)
          ex = Ui()
          app.exec_()
      
      
      # MAIN
      # Starting the thread
      t = threading.Thread(target=interface)
      t.daemon = True
      t.start()
      time.sleep(1)
      
      # Trying to find Main Window
      gui = findMainWindow()
      for i in range(5):
          val += 1
          # Trying to update prog bar value
          gui.updateProgressBar()
      
      while True:
          ();
      

      Thank you for reading :)

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

      @TheAlmeida said in Updating QProgressBars running on thread with values from main:

      How how I be able to call updateProgressBar() from outside the thread?

      Using https://doc.qt.io/qt-5/signalsandslots.html
      The thread calculating the values will emit a signal and pass current value as signal parameter. This signal will be connected to a slot in your GUI thread in your UI class. In this slot you will update the progress bar.

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

      T 1 Reply Last reply
      3
      • T TheAlmeida

        Hi, I am not well versed in programming and I am pretty new to Python and QT, so I am sorry if I will present my question wrong and I would be glad to try and elaborate on it in a different way.

        What I would like to do is change the value of the progress bars on my GUI (that is running on a thread). This value would be calculated outside the thread, in the "main code".

        Although I can change the value of the progressbars on initialization what I would really like to be able to do is change them dinamically.

        val = 0
        
        class Ui(QtWidgets.QMainWindow):
            def __init__(self):
                super(Ui, self).__init__()
                uic.loadUi('PBL3_designer.ui', self) 
        
                self.progbar1= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar1')
                self.progbar2= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar2')
                self.progbar3= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar3')
        
            # Function to update prog bars
            def updateProgressBar(self):
                self.prog_bar_cinza1.setValue(val)
                self.prog_bar_cinza2.setValue(val*2)
                self.prog_bar_cores1.setValue(val*3)
        
        def interface():
            app = QtWidgets.QApplication(sys.argv)
            ex = Ui()
            app.exec_()
        
        
        # MAIN
        # Starting the thread
        t = threading.Thread(target=interface)
        t.daemon = True
        t.start()
        time.sleep(1)
        

        How how I be able to call updateProgressBar() from outside the thread?

        I've tried JonB's solution but I am not sure I am placing it right (at the moment it is defined outside the Ui class) I get the error AttributeError: type object 'QMainWindow' has no attribute 'instance'

        The full code I am running right now to try and change the prog bars is as follows:

        import PyQt5.QtWidgets
        from PyQt5 import QtWidgets, uic
        import pbl3_rc
        import sys
        import time
        import threading
        import typing
        
        
        val = 0
        
        class Ui(QtWidgets.QMainWindow):
            def __init__(self):
                super(Ui, self).__init__()
                uic.loadUi('PBL3_designer.ui', self) 
        
                self.progbar1= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar1')
                self.progbar2= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar2')
                self.progbar3= self.findChild(PyQt5.QtWidgets.QProgressBar, 'progbar3')
        
            # Function to update prog bars
            def updateProgressBar(self):
                self.progbar1.setValue(val)
                self.progbar2.setValue(val*2)
                self.progbar3.setValue(val*3)
        
        # JonB's solution
        def findMainWindow() -> typing.Union[QtWidgets.QMainWindow, None]:
            app = QtWidgets.QMainWindow.instance()
            for widget in app.topLevelWidgets():
                if isinstance(widget, QtWidgets.QMainWindow):
                    return widget
            return None
        
        
        def interface():
            app = QtWidgets.QApplication(sys.argv)
            ex = Ui()
            app.exec_()
        
        
        # MAIN
        # Starting the thread
        t = threading.Thread(target=interface)
        t.daemon = True
        t.start()
        time.sleep(1)
        
        # Trying to find Main Window
        gui = findMainWindow()
        for i in range(5):
            val += 1
            # Trying to update prog bar value
            gui.updateProgressBar()
        
        while True:
            ();
        

        Thank you for reading :)

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

        @TheAlmeida
        I am @JonB, the author of that findMainWindow() Python function. You have copied it correctly, but you are not using it in the right place/way.

        However, you have no need of it here.

        • Make updateProgressBar() accept val as a parameter.
        • If your flavor of PyQt/PySide requires it, mark that method as a slot.
        • In your thread define a signal, which takes val as a parameter.
        • And there emit() the signal, with a suitable value for val, as progress is made through the "calculation".
        • Somewhere --- probably in your MainWindow, which has visibility of both the signal and the slot objects --- use connect() to connect the signal to the slot.

        The thread emits a signal with a value parameter at suitable times. The connect() causes the slot to be called with that parameter, which it uses to update the progress bar correspondingly.

        T 1 Reply Last reply
        3
        • JonBJ JonB

          @TheAlmeida
          I am @JonB, the author of that findMainWindow() Python function. You have copied it correctly, but you are not using it in the right place/way.

          However, you have no need of it here.

          • Make updateProgressBar() accept val as a parameter.
          • If your flavor of PyQt/PySide requires it, mark that method as a slot.
          • In your thread define a signal, which takes val as a parameter.
          • And there emit() the signal, with a suitable value for val, as progress is made through the "calculation".
          • Somewhere --- probably in your MainWindow, which has visibility of both the signal and the slot objects --- use connect() to connect the signal to the slot.

          The thread emits a signal with a value parameter at suitable times. The connect() causes the slot to be called with that parameter, which it uses to update the progress bar correspondingly.

          T Offline
          T Offline
          TheAlmeida
          wrote on last edited by TheAlmeida
          #4

          @JonB Hi, thank you for your reply, but how would you suggest I emit the signal from outside the thread the GUI is running? Your answer makes perfect sense but I am failing to execute it.
          I am trying to define the connection inside the __init__ of the Ui and the signal inside the interface running on the thread but where do I do the place the emit()? In the thread on a 1sec timer for example?

          JonBJ 1 Reply Last reply
          0
          • jsulmJ jsulm

            @TheAlmeida said in Updating QProgressBars running on thread with values from main:

            How how I be able to call updateProgressBar() from outside the thread?

            Using https://doc.qt.io/qt-5/signalsandslots.html
            The thread calculating the values will emit a signal and pass current value as signal parameter. This signal will be connected to a slot in your GUI thread in your UI class. In this slot you will update the progress bar.

            T Offline
            T Offline
            TheAlmeida
            wrote on last edited by
            #5

            @jsulm Thank you for your input, it seems (at least for my small programming brain) that you and JonB suggested the same course of action(?) but how can I define the signal outside of the UI class? I am sorry for such dumb and most likely very basic questions

            1 Reply Last reply
            0
            • T TheAlmeida

              @JonB Hi, thank you for your reply, but how would you suggest I emit the signal from outside the thread the GUI is running? Your answer makes perfect sense but I am failing to execute it.
              I am trying to define the connection inside the __init__ of the Ui and the signal inside the interface running on the thread but where do I do the place the emit()? In the thread on a 1sec timer for example?

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

              @TheAlmeida said in Updating QProgressBars running on thread with values from main:

              but where do I do the place the emit()? In the thread on a 1sec timer for example?

              Well, yes, in principle that works. But it makes little sense. If all you wanted was to update a progressbar once per second you wouldn't need a thread and you could just have a timer in the UI thread to do the updates.

              Presumably the reason for your thread is that it is doing some operation which takes quite some time to complete, and you want it to signal its progress to completion so that the UI thread can update a progressbar to show it. Else I don't know what your thread is for/doing.

              Suppose your thread has a loop doing doing stuff which takes time. First you must declare the signal in the thread class. Look up how you do that in PyQt, I think it's something like a "class-level variable marked with @pyqtsignal attribute". Then in the thread class you might have something like:

              class Something:
                  @pyqtsignal
                  progress(val: int)
              
                  def doTheWork(self):
                      for i in range(100):
                          self.doSomethingWhichTakesABitOfTime()
                          self.progress.emit(i)
              

              So this would emit a signal with parameter 0..99 as it marched through its work. The main window class would have connect()ed that thread signal to its slot to update the progressbar with the value sent in the signal.

              1 Reply Last reply
              1
              • S Offline
                S Offline
                SimonSchroeder
                wrote on last edited by
                #7

                Initially, I cringed a little: One of the most important things of Qt is that the GUI needs to run in the main thread. A proper implementation would launch the "main code" inside a separate thread instead of the GUI. It seems that you don't have any problems with that in general (you do see widgets in general and can interact with them?). This could be related because in the regular Python interpreter all threads are running inside the same OS thread.

                While writing my reply, @JonB already answered you question about slots.

                In C++ there is also a way to use QMetaObject::invokeMethod to put a call to your updateProgressBar into the GUI's event loop. I am not sure how (or if) this translates to Python.

                JonBJ 1 Reply Last reply
                0
                • S SimonSchroeder

                  Initially, I cringed a little: One of the most important things of Qt is that the GUI needs to run in the main thread. A proper implementation would launch the "main code" inside a separate thread instead of the GUI. It seems that you don't have any problems with that in general (you do see widgets in general and can interact with them?). This could be related because in the regular Python interpreter all threads are running inside the same OS thread.

                  While writing my reply, @JonB already answered you question about slots.

                  In C++ there is also a way to use QMetaObject::invokeMethod to put a call to your updateProgressBar into the GUI's event loop. I am not sure how (or if) this translates to Python.

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

                  @SimonSchroeder said in Updating QProgressBars running on thread with values from main:

                  This could be related because in the regular Python interpreter all threads are running inside the same OS thread.

                  I don't know if this relevant to anything here, but where do you get this from? Could you provide a reference, please?

                  This is nothing like my understanding of Python threading. So far as I understood, Python threads absolutely are separate OS threads? Else there would be no point in Python having threading?

                  What is the case, quite unlike a C++ program, is that threads share one common GIL, which means that when threads execute certain Python statements they will get blocked on this shared resource, because only one instance of the GIL can run (in a single main Python thread) at any one instant. To a certain extent this can serialize Python multi-thread behaviour, at certain execution stages depending on the operation performed. But that is quite different from what you have written.

                  S 1 Reply Last reply
                  1
                  • JonBJ JonB

                    @SimonSchroeder said in Updating QProgressBars running on thread with values from main:

                    This could be related because in the regular Python interpreter all threads are running inside the same OS thread.

                    I don't know if this relevant to anything here, but where do you get this from? Could you provide a reference, please?

                    This is nothing like my understanding of Python threading. So far as I understood, Python threads absolutely are separate OS threads? Else there would be no point in Python having threading?

                    What is the case, quite unlike a C++ program, is that threads share one common GIL, which means that when threads execute certain Python statements they will get blocked on this shared resource, because only one instance of the GIL can run (in a single main Python thread) at any one instant. To a certain extent this can serialize Python multi-thread behaviour, at certain execution stages depending on the operation performed. But that is quite different from what you have written.

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

                    @JonB said in Updating QProgressBars running on thread with values from main:

                    What is the case, quite unlike a C++ program, is that threads share one common GIL, which means that when threads execute certain Python statements they will get blocked on this shared resource, because only one instance of the GIL can run (in a single main Python thread) at any one instant. To a certain extent this can serialize Python multi-thread behaviour, at certain execution stages depending on the operation performed. But that is quite different from what you have written.

                    I am not a Python expert. So, probably you are right.

                    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