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. Pyqt UI non responsive on Multithreading with python
Forum Updated to NodeBB v4.3 + New Features

Pyqt UI non responsive on Multithreading with python

Scheduled Pinned Locked Moved Unsolved Qt for Python
15 Posts 3 Posters 2.9k 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.
  • A Offline
    A Offline
    Albitroz
    wrote on last edited by
    #1

    I'm new to PyQt and python, i was working with a program which had a simple UI and which collects some data from a hardware

    I have 2 files handling everything and a thread to collect data , but my problem is that, when thread is running, UI becomes un responsive..

    All UI portion is handled by file "Analog_ui.py"
    All data capture portion is handled by file "AI_DAQ.py"

    Code for Analog_ui.py

    
    "___________________________Create GUI____________________________________________"
    from itertools import starmap
    import sys
    
    #import QApplications and the required widgets from PyQt.QtWidgets
    from PyQt5 import QtWidgets,QtCore, QtGui
    from PyQt5.QtCore import Qt
    from PyQt5.QtWidgets import QGridLayout, QLineEdit
    from PyQt5.QtWidgets import QVBoxLayout
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtWidgets import QLabel, QHBoxLayout, QPushButton
    from PyQt5.QtWidgets import QWidget
    from PyQt5.QtWidgets import QMainWindow
    from PyQt5 import uic
    import AI_DAQ
    
    
    
    #exec(open("Analogdata.py").read()) 
    
    class Configure_MainWindow(object): 
        
        def Ui_Configure(self, MainWindow):
            MainWindow.resize(1100,600)
            self.centralwidget=QtWidgets.QWidget(MainWindow)
            
            #adding start and stop pushbutton
            self.pushButton1=QtWidgets.QPushButton(self.centralwidget)
            self.pushButton1.setGeometry(QtCore.QRect(1000,500,93,28))
            
            
            self.pushButton2=QtWidgets.QPushButton(self.centralwidget)
            self.pushButton2.setGeometry(QtCore.QRect(1000,550,93,28))
            
            self.Physicalchannel=QtWidgets.QLineEdit(self.centralwidget)
            self.Physicalchannel.setGeometry(QtCore.QRect(40,50,140,21))
            self.Physicalchannel.setText("Dev1/ai0")
            #self.Physicalchannel.
       
            
            self.PhysicalchannelLabel=QtWidgets.QLabel(self.centralwidget)
            self.PhysicalchannelLabel.setGeometry(QtCore.QRect(40,25,111,21))
            
            self.MaxVolt=QtWidgets.QSpinBox(self.centralwidget)
            self.MaxVolt.setGeometry(QtCore.QRect(190,120,100,21))
            self.MaxVolt.setRange(0,5)
            self.MaxVolt.setValue(5)
            self.MaxVoltLabel=QtWidgets.QLabel(self.centralwidget)
            self.MaxVoltLabel.setGeometry(QtCore.QRect(190,90,60,28))
            
            self.MinVolt=QtWidgets.QSpinBox(self.centralwidget)
            self.MinVolt.setGeometry(QtCore.QRect(40,120,100,21))
            self.MinVolt.setRange(-5,0)
            self.MinVolt.setValue(-5)
            self.MinVoltLabel=QtWidgets.QLabel(self.centralwidget)
            self.MinVoltLabel.setGeometry(QtCore.QRect(40,90,60,28))
            
            self.SampleRate=QtWidgets.QSpinBox(self.centralwidget)
            self.SampleRate.setGeometry(QtCore.QRect(220,50,70,21))
            self.SampleRate.setRange(0,400)
            self.SampleRate.setValue(200)
            
            self.SampleRateLabel=QtWidgets.QLabel(self.centralwidget)
            self.SampleRateLabel.setGeometry(QtCore.QRect(220,25,60,28))
            
            """self.graphicsView= QtWidgets.QGraphicsView(self.centralwidget)
            self.graphicsView.setGeometry(QtCore.QRect(265,10,321,281))
            self.graphicsViewLabel=QtWidgets.QLabel(self.centralwidget)
            self.graphicsViewLabel.setGeometry(QtCore.QRect(100,10,60,10))"""
            
            
            MainWindow.setCentralWidget(self.centralwidget)
            
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
            
        def start(self):
            print("start button clicked")
            #a=self.SampleRate.get()
            
            AI_DAQ.cfg_read_task("Dev1/ai0")
             
            
        def stop(self):
            print("Stopping Tread")
            AI_DAQ.stop_task()
            
            
            
            
               
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "Analog Data Acquisition"))
            self.pushButton1.setText(_translate("MainWindow", "Start"))
            self.pushButton2.setText(_translate("MainWindow","Stop"))
            self.PhysicalchannelLabel.setText(_translate("MainWindow","Physical Channel"))
            self.MaxVoltLabel.setText(_translate("MainWindow","Max Voltage"))
            self.MinVoltLabel.setText(_translate("MainWindow", "Min Voltage"))
            self.SampleRateLabel.setText(_translate("MainWindow","Rate"))
            #self.graphicsViewLabel.setText(_translate("MainWindow","AnalogWave form"))
            
            self.pushButton1.clicked.connect(self.start)
            self.pushButton2.clicked.connect(self.stop)
            
                   
        
                    
    """_______________Main function_________________ """  
    
    
    if __name__=='__main__':
        
        #Create an instance of QApplication
        app=QtWidgets.QApplication(sys.argv)
        MainWindow=QtWidgets.QMainWindow()
        # Show GUI
        ui=Configure_MainWindow()
        ui.Ui_Configure(MainWindow) 
        MainWindow.show() #Windows are hidden by default
        #Execute the eventloop
        sys.exit(app.exec_())
        
    
        
    
    

    Code for AI_DAQ.py

    import threading
    from turtle import delay
    from matplotlib.pyplot import get
    import nidaqmx
    from nidaqmx import constants
    import nidaqmx.system
    import time
    
    #variables declaration
    buffer_in_size=100
    buffer_in_size_cfg = round(buffer_in_size * 1)
    task_in=nidaqmx.Task()
    running=True
    
    
            
    def stop_task():
        running=False  
     
           
    def ai_read():
        print("Inside Thread")
        task_in.start()
        while(running):
                data=task_in.read(number_of_samples_per_channel=100)
                #print(data)
                time.sleep(.01)
          
                
        task_in.stop()
        #task_in.close()   
        
    
    def cfg_read_task(chname):
        print(chname)
        running=True
        #configure and setup the AItask
        system=nidaqmx.system.System.local()
        device=system.devices['Dev1']
        phys_chan=device.ai_physical_chans['ai0']
        
        task_in.ai_channels.add_ai_voltage_chan(chname,min_val=-5,max_val=5)
        task_in.timing.cfg_samp_clk_timing (rate=100,sample_mode=constants.AcquisitionType.CONTINUOUS,samps_per_chan=buffer_in_size_cfg)
        print("Task configured")
        #configure thread starting
        thread_ai=threading.Thread(target=ai_read)
        thread_ai.start()
        thread_ai.join()
        
        
    

    here when we start the thread in AI_DAQ.py the whole UI freezes
    How can i resolve the same?

    i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

    JonBJ 1 Reply Last reply
    0
    • A Albitroz

      I'm new to PyQt and python, i was working with a program which had a simple UI and which collects some data from a hardware

      I have 2 files handling everything and a thread to collect data , but my problem is that, when thread is running, UI becomes un responsive..

      All UI portion is handled by file "Analog_ui.py"
      All data capture portion is handled by file "AI_DAQ.py"

      Code for Analog_ui.py

      
      "___________________________Create GUI____________________________________________"
      from itertools import starmap
      import sys
      
      #import QApplications and the required widgets from PyQt.QtWidgets
      from PyQt5 import QtWidgets,QtCore, QtGui
      from PyQt5.QtCore import Qt
      from PyQt5.QtWidgets import QGridLayout, QLineEdit
      from PyQt5.QtWidgets import QVBoxLayout
      from PyQt5.QtWidgets import QApplication
      from PyQt5.QtWidgets import QLabel, QHBoxLayout, QPushButton
      from PyQt5.QtWidgets import QWidget
      from PyQt5.QtWidgets import QMainWindow
      from PyQt5 import uic
      import AI_DAQ
      
      
      
      #exec(open("Analogdata.py").read()) 
      
      class Configure_MainWindow(object): 
          
          def Ui_Configure(self, MainWindow):
              MainWindow.resize(1100,600)
              self.centralwidget=QtWidgets.QWidget(MainWindow)
              
              #adding start and stop pushbutton
              self.pushButton1=QtWidgets.QPushButton(self.centralwidget)
              self.pushButton1.setGeometry(QtCore.QRect(1000,500,93,28))
              
              
              self.pushButton2=QtWidgets.QPushButton(self.centralwidget)
              self.pushButton2.setGeometry(QtCore.QRect(1000,550,93,28))
              
              self.Physicalchannel=QtWidgets.QLineEdit(self.centralwidget)
              self.Physicalchannel.setGeometry(QtCore.QRect(40,50,140,21))
              self.Physicalchannel.setText("Dev1/ai0")
              #self.Physicalchannel.
         
              
              self.PhysicalchannelLabel=QtWidgets.QLabel(self.centralwidget)
              self.PhysicalchannelLabel.setGeometry(QtCore.QRect(40,25,111,21))
              
              self.MaxVolt=QtWidgets.QSpinBox(self.centralwidget)
              self.MaxVolt.setGeometry(QtCore.QRect(190,120,100,21))
              self.MaxVolt.setRange(0,5)
              self.MaxVolt.setValue(5)
              self.MaxVoltLabel=QtWidgets.QLabel(self.centralwidget)
              self.MaxVoltLabel.setGeometry(QtCore.QRect(190,90,60,28))
              
              self.MinVolt=QtWidgets.QSpinBox(self.centralwidget)
              self.MinVolt.setGeometry(QtCore.QRect(40,120,100,21))
              self.MinVolt.setRange(-5,0)
              self.MinVolt.setValue(-5)
              self.MinVoltLabel=QtWidgets.QLabel(self.centralwidget)
              self.MinVoltLabel.setGeometry(QtCore.QRect(40,90,60,28))
              
              self.SampleRate=QtWidgets.QSpinBox(self.centralwidget)
              self.SampleRate.setGeometry(QtCore.QRect(220,50,70,21))
              self.SampleRate.setRange(0,400)
              self.SampleRate.setValue(200)
              
              self.SampleRateLabel=QtWidgets.QLabel(self.centralwidget)
              self.SampleRateLabel.setGeometry(QtCore.QRect(220,25,60,28))
              
              """self.graphicsView= QtWidgets.QGraphicsView(self.centralwidget)
              self.graphicsView.setGeometry(QtCore.QRect(265,10,321,281))
              self.graphicsViewLabel=QtWidgets.QLabel(self.centralwidget)
              self.graphicsViewLabel.setGeometry(QtCore.QRect(100,10,60,10))"""
              
              
              MainWindow.setCentralWidget(self.centralwidget)
              
              self.retranslateUi(MainWindow)
              QtCore.QMetaObject.connectSlotsByName(MainWindow)
              
          def start(self):
              print("start button clicked")
              #a=self.SampleRate.get()
              
              AI_DAQ.cfg_read_task("Dev1/ai0")
               
              
          def stop(self):
              print("Stopping Tread")
              AI_DAQ.stop_task()
              
              
              
              
                 
          def retranslateUi(self, MainWindow):
              _translate = QtCore.QCoreApplication.translate
              MainWindow.setWindowTitle(_translate("MainWindow", "Analog Data Acquisition"))
              self.pushButton1.setText(_translate("MainWindow", "Start"))
              self.pushButton2.setText(_translate("MainWindow","Stop"))
              self.PhysicalchannelLabel.setText(_translate("MainWindow","Physical Channel"))
              self.MaxVoltLabel.setText(_translate("MainWindow","Max Voltage"))
              self.MinVoltLabel.setText(_translate("MainWindow", "Min Voltage"))
              self.SampleRateLabel.setText(_translate("MainWindow","Rate"))
              #self.graphicsViewLabel.setText(_translate("MainWindow","AnalogWave form"))
              
              self.pushButton1.clicked.connect(self.start)
              self.pushButton2.clicked.connect(self.stop)
              
                     
          
                      
      """_______________Main function_________________ """  
      
      
      if __name__=='__main__':
          
          #Create an instance of QApplication
          app=QtWidgets.QApplication(sys.argv)
          MainWindow=QtWidgets.QMainWindow()
          # Show GUI
          ui=Configure_MainWindow()
          ui.Ui_Configure(MainWindow) 
          MainWindow.show() #Windows are hidden by default
          #Execute the eventloop
          sys.exit(app.exec_())
          
      
          
      
      

      Code for AI_DAQ.py

      import threading
      from turtle import delay
      from matplotlib.pyplot import get
      import nidaqmx
      from nidaqmx import constants
      import nidaqmx.system
      import time
      
      #variables declaration
      buffer_in_size=100
      buffer_in_size_cfg = round(buffer_in_size * 1)
      task_in=nidaqmx.Task()
      running=True
      
      
              
      def stop_task():
          running=False  
       
             
      def ai_read():
          print("Inside Thread")
          task_in.start()
          while(running):
                  data=task_in.read(number_of_samples_per_channel=100)
                  #print(data)
                  time.sleep(.01)
            
                  
          task_in.stop()
          #task_in.close()   
          
      
      def cfg_read_task(chname):
          print(chname)
          running=True
          #configure and setup the AItask
          system=nidaqmx.system.System.local()
          device=system.devices['Dev1']
          phys_chan=device.ai_physical_chans['ai0']
          
          task_in.ai_channels.add_ai_voltage_chan(chname,min_val=-5,max_val=5)
          task_in.timing.cfg_samp_clk_timing (rate=100,sample_mode=constants.AcquisitionType.CONTINUOUS,samps_per_chan=buffer_in_size_cfg)
          print("Task configured")
          #configure thread starting
          thread_ai=threading.Thread(target=ai_read)
          thread_ai.start()
          thread_ai.join()
          
          
      

      here when we start the thread in AI_DAQ.py the whole UI freezes
      How can i resolve the same?

      i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

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

      @Albitroz
      start() calls cfg_read_task(). That calls thread_ai.start() but then immediately thread_ai.join(). Which blocks waiting on the task to complete, and that in turn blocks the UI.

      If you need to use a thread let it run as a thread, not block till it completes.

      i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

      Use Qt signals & slots.

      A 1 Reply Last reply
      1
      • A Offline
        A Offline
        Albitroz
        wrote on last edited by
        #3

        Hi thanks for the solution, it worked.
        Qt signals & slots., i was planing to use queue instead, is that a bad idea?

        A 1 Reply Last reply
        0
        • A Albitroz

          Hi thanks for the solution, it worked.
          Qt signals & slots., i was planing to use queue instead, is that a bad idea?

          A Offline
          A Offline
          Albitroz
          wrote on last edited by
          #4

          @Albitroz said in Pyqt UI non responsive on Multi threading with python:

          Hi thanks for the solution, it worked.
          Qt signals & slots., i was planing to use queue instead, is that a bad idea?

          specifically, to transfer data which is generated by thread

          JonBJ 1 Reply Last reply
          0
          • A Albitroz

            @Albitroz said in Pyqt UI non responsive on Multi threading with python:

            Hi thanks for the solution, it worked.
            Qt signals & slots., i was planing to use queue instead, is that a bad idea?

            specifically, to transfer data which is generated by thread

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

            @Albitroz
            You can use a queue, that in itself is fine. You should also be careful to mutex, either code yourself or it must be built into the queue.

            The signal/slot would be needed at least to let the other side know (in your case, the main thread) that new data has been queued. How else would you intend to do that bit?

            A 1 Reply Last reply
            0
            • JonBJ JonB

              @Albitroz
              You can use a queue, that in itself is fine. You should also be careful to mutex, either code yourself or it must be built into the queue.

              The signal/slot would be needed at least to let the other side know (in your case, the main thread) that new data has been queued. How else would you intend to do that bit?

              A Offline
              A Offline
              Albitroz
              wrote on last edited by
              #6

              @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

              JonBJ 1 Reply Last reply
              0
              • JonBJ JonB

                @Albitroz
                start() calls cfg_read_task(). That calls thread_ai.start() but then immediately thread_ai.join(). Which blocks waiting on the task to complete, and that in turn blocks the UI.

                If you need to use a thread let it run as a thread, not block till it completes.

                i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

                Use Qt signals & slots.

                A Offline
                A Offline
                Albitroz
                wrote on last edited by
                #7

                @JonB in the same code, im facing issues in stopping my thread,
                im calling a function from my main code

                def stop_task():
                    running=False
                

                which will set the running variable to False, and in my thread, im checking for that variable

                def ai_read():
                    print("Inside Thread")
                    task_in.start()
                    while(running):
                            data=task_in.read(number_of_samples_per_channel=100)
                            #print(data)
                            time.sleep(.01)
                

                I have verified the value of running with printf inside the thread, its not getting updated, is there any thread safe variable?

                JonBJ 1 Reply Last reply
                0
                • A Albitroz

                  @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

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

                  @Albitroz said in Pyqt UI non responsive on Multithreading with python:

                  @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

                  It will work, bit it's not as efficient as it could be.

                  To do that, your main thread will have to have that interval timer and check each time. Plus often(?) the queue will not be of that size, and it will be a waste of time. Wouldn't you like to know when the thread actually pushes another item to the queue, and only check then/when the count is reached? That is what having the thread send a signal (when it queues), and the main thread have a slot attached to the signal, would achieve.

                  The only time where "timed-polling" is (almost) just as good is if you only want the receiver to pull from the queue at those interval points, not as soon as the data arrives. All in all it's hard to see why signalling would not be a preferable solution.

                  Sooner or later you will have to use signals & slots in Qt programming, so why not now?

                  A 1 Reply Last reply
                  0
                  • A Albitroz

                    @JonB in the same code, im facing issues in stopping my thread,
                    im calling a function from my main code

                    def stop_task():
                        running=False
                    

                    which will set the running variable to False, and in my thread, im checking for that variable

                    def ai_read():
                        print("Inside Thread")
                        task_in.start()
                        while(running):
                                data=task_in.read(number_of_samples_per_channel=100)
                                #print(data)
                                time.sleep(.01)
                    

                    I have verified the value of running with printf inside the thread, its not getting updated, is there any thread safe variable?

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

                    @Albitroz said in Pyqt UI non responsive on Multithreading with python:

                    I have verified the value of running with printf inside the thread, its not getting updated, is there any thread safe variable?

                    All your threading stuff is being done with Python threading. So your questions are best asked in a Python forum. I don't know when stop_task() gets called while ai_read() is in a loop.

                    Up to you, but I would use Qt signals & slots for everything like this.

                    1 Reply Last reply
                    0
                    • JonBJ JonB

                      @Albitroz said in Pyqt UI non responsive on Multithreading with python:

                      @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

                      It will work, bit it's not as efficient as it could be.

                      To do that, your main thread will have to have that interval timer and check each time. Plus often(?) the queue will not be of that size, and it will be a waste of time. Wouldn't you like to know when the thread actually pushes another item to the queue, and only check then/when the count is reached? That is what having the thread send a signal (when it queues), and the main thread have a slot attached to the signal, would achieve.

                      The only time where "timed-polling" is (almost) just as good is if you only want the receiver to pull from the queue at those interval points, not as soon as the data arrives. All in all it's hard to see why signalling would not be a preferable solution.

                      Sooner or later you will have to use signals & slots in Qt programming, so why not now?

                      A Offline
                      A Offline
                      Albitroz
                      wrote on last edited by
                      #10

                      @JonB ok i will use signals and slots as a callback to get the data, but im facing issues stopping the thread

                      1 Reply Last reply
                      0
                      • SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by SGaist
                        #11

                        Hi,

                        What issues are you having ?

                        Note that depending on what you do in your loop you should put break statement at regular intervals to allow for an easier way out of it.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        A 1 Reply Last reply
                        0
                        • SGaistS SGaist

                          Hi,

                          What issues are you having ?

                          Note that depending on what you do in your loop you should put break statement at regular intervals to allow for an easier way out of it.

                          A Offline
                          A Offline
                          Albitroz
                          wrote on last edited by
                          #12

                          @SGaist HI
                          Currently im facing issues, in transferring data from different threads

                          Im splitting my entire project to different ".py " file for easy debugging, in this case how can i transfer data from one file to other

                          to be pressie,

                          I have my main ".py file which runs the pyqt event loop, i have another file which generates some data through a thread". How can i pass data from this thread to my main python file, can i use signals and slots to transfer data to the main file which holds the UI

                          my main intention is to send data from different threads to the main file which runs QT event and UI so that i can display data from these threads

                          which is better, implementing a queue or signals and slots?

                          1 Reply Last reply
                          0
                          • SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            The files play no role here.

                            If you are using QThread then you can easily use signals and slots to transfert data.

                            Otherwise are you using Python's multithreading or multiprocessing ? If you really want parallel processing with Python, you shall use the later.

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            A 1 Reply Last reply
                            0
                            • SGaistS SGaist

                              The files play no role here.

                              If you are using QThread then you can easily use signals and slots to transfert data.

                              Otherwise are you using Python's multithreading or multiprocessing ? If you really want parallel processing with Python, you shall use the later.

                              A Offline
                              A Offline
                              Albitroz
                              wrote on last edited by
                              #14

                              @SGaist
                              I will be handling around 20 threads of different functionalities, and all are time critical activities, so stack overflow suggests using Multiprocessing library which one do you prefer?

                              if i go with multiprocessing library, how can i transfer data between files , my main action is to display these processed data on UI and thats the reason i use PyQt

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #15

                                You can check this article. At the there's a link for a mix between PyQt and multiprocessing.

                                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
                                0

                                • Login

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