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 GUI element (QTableview) with QThread, with conditionally setting dataframe

Updating GUI element (QTableview) with QThread, with conditionally setting dataframe

Scheduled Pinned Locked Moved Unsolved Qt for Python
pyqt5pythonqthreadmultithreadinggui
2 Posts 2 Posters 1.0k 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.
  • A Offline
    A Offline
    alan02011114
    wrote on 17 Feb 2022, 11:57 last edited by
    #1

    In this program I would like to update the QTableview, by setting up a worker thread to process the calculation of new dataframe

    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    import pandas as pd
    import datetime as dt
    import numpy as np
    import sys
    
    #### Some functions to create different dataframe
    def function1(a,b,c):
        df = pd.DataFrame(np.array([[4, 2, 3], [4, 6, 4], [8, 87, 9]]), columns=[a, b, c])
        return df
    
    def function2(a,b,c):
        df = pd.DataFrame(np.array([[4, 2, 3], [4, 6, 4], [8, 87, 9]]), columns=[a, b, c])
        return df
    
    
    #### Create Worker Thread
    class Worker(QThread):
        worksignal = pyqtSignal(pd.DataFrame)
    
        def __init__(self, parent=None, *args, **kw):
            super(QThread, self).__init__()
            self.passargu(*args, **kw)
    
        @pyqtSlot(pd.DataFrame)
        def run(self):
            print("Start")
           
            if self.type == "function1":
                self.df = function1(self.para1,self.para2,self.para3)  
            elif self.type == "function2": 
                self.df = function2(self.para1,self.para2,self.para3)
    
            self.worksignal.emit(self.df)
    
        def passargu(self, type ,para1, para2, para3):
            self.type =  type
            self.para1 = para1
            self.para2 = para2
            self.para3 = para3
    
    #### Create TableModel for viewing dataframe in QTableview object
    class TableModel(QAbstractTableModel):
        def __init__(self, data):
            super(TableModel, self).__init__()
            self._data = data
    
        def data(self, index, role):
            if role == Qt.DisplayRole:
                value = self._data.iloc[index.row(), index.column()]
                return str(value)
    
        def rowCount(self, index):
            return self._data.shape[0]
    
        def columnCount(self, index):
            return self._data.shape[1]
    
        def headerData(self, section, orientation, role):
            # section is the index of the column/row.
            if role == Qt.DisplayRole:
                if orientation == Qt.Horizontal:
                    return str(self._data.columns[section]).replace("\n", " ")
                if orientation == Qt.Vertical:
                    return str(self._data.index[section]).replace("\n", " ")
    
    #### Main Gui
    class Gui(QWidget):
    
        def __init__(self, parent=None):
            super(Gui, self).__init__()   
    
            self.initUI()
    
        def initUI(self):
            layout = QFormLayout()
            self.add_button1 = QPushButton('UPDATE TABLE - FUNCTION1')
            self.add_button2 = QPushButton('UPDATE TABLE - FUNCTION2')
    
            self.para1 = QComboBox()
            self.para1.addItems([" ","A","B","C"])
            
            self.para2 = QComboBox()
            self.para2.addItems([" ","D","E","F"])
    
            self.para3 = QComboBox()
            self.para3.addItems([" ","X","Y","Z"])
    
            layout.addRow(self.add_button)
            layout.addRow(self.para1)
            layout.addRow(self.para2)
            layout.addRow(self.para3)
    
    
            self.table = QTableView()
            layout.addRow(self.table)
    
            self.setLayout(layout)
            self.add_button1.clicked.connect(lambda: self.threadworker(type="function1"))
            self.add_button2.clicked.connect(lambda: self.threadworker(type="function2"))
    
        
        def threadworker(self, dfreceived, type):
            self.worker = Worker(self, type, self.para1.currentText(), self.para2.currentText(), self.para3.currentText())
            self.worker.start()
            self.worker.worksignal.connect(self.update_table_gui)
    
        def update_table_gui(self, df):
            model = TableModel(df)  
            self.table.setModel(model)
    
    def main():
        app = QApplication(sys.argv)
        main = Gui()
        main.show()
        sys.exit(app.exec())
            
    if __name__ == "__main__":   
        main()
    

    Error message:

    self.add_button1.clicked.connect(lambda: self.threadworker(type="function1"))
    TypeError: threadworker() missing 1 required positional argument: 'dfreceived'
    

    In function threadworker I have added a type variable to define which function (function1 or function2) the Worker Thread Worker to be used to calculate the dataframe and then update the QTableview.

    dfreceived is used to received the signal from worker thread.
    However, if threadworker is assigned to button with lambda (since type is required to tell which function to be used), the error shows up.

    J 1 Reply Last reply 17 Feb 2022, 13:09
    0
    • A alan02011114
      17 Feb 2022, 11:57

      In this program I would like to update the QTableview, by setting up a worker thread to process the calculation of new dataframe

      from PyQt5.QtWidgets import *
      from PyQt5.QtGui import *
      from PyQt5.QtCore import *
      import pandas as pd
      import datetime as dt
      import numpy as np
      import sys
      
      #### Some functions to create different dataframe
      def function1(a,b,c):
          df = pd.DataFrame(np.array([[4, 2, 3], [4, 6, 4], [8, 87, 9]]), columns=[a, b, c])
          return df
      
      def function2(a,b,c):
          df = pd.DataFrame(np.array([[4, 2, 3], [4, 6, 4], [8, 87, 9]]), columns=[a, b, c])
          return df
      
      
      #### Create Worker Thread
      class Worker(QThread):
          worksignal = pyqtSignal(pd.DataFrame)
      
          def __init__(self, parent=None, *args, **kw):
              super(QThread, self).__init__()
              self.passargu(*args, **kw)
      
          @pyqtSlot(pd.DataFrame)
          def run(self):
              print("Start")
             
              if self.type == "function1":
                  self.df = function1(self.para1,self.para2,self.para3)  
              elif self.type == "function2": 
                  self.df = function2(self.para1,self.para2,self.para3)
      
              self.worksignal.emit(self.df)
      
          def passargu(self, type ,para1, para2, para3):
              self.type =  type
              self.para1 = para1
              self.para2 = para2
              self.para3 = para3
      
      #### Create TableModel for viewing dataframe in QTableview object
      class TableModel(QAbstractTableModel):
          def __init__(self, data):
              super(TableModel, self).__init__()
              self._data = data
      
          def data(self, index, role):
              if role == Qt.DisplayRole:
                  value = self._data.iloc[index.row(), index.column()]
                  return str(value)
      
          def rowCount(self, index):
              return self._data.shape[0]
      
          def columnCount(self, index):
              return self._data.shape[1]
      
          def headerData(self, section, orientation, role):
              # section is the index of the column/row.
              if role == Qt.DisplayRole:
                  if orientation == Qt.Horizontal:
                      return str(self._data.columns[section]).replace("\n", " ")
                  if orientation == Qt.Vertical:
                      return str(self._data.index[section]).replace("\n", " ")
      
      #### Main Gui
      class Gui(QWidget):
      
          def __init__(self, parent=None):
              super(Gui, self).__init__()   
      
              self.initUI()
      
          def initUI(self):
              layout = QFormLayout()
              self.add_button1 = QPushButton('UPDATE TABLE - FUNCTION1')
              self.add_button2 = QPushButton('UPDATE TABLE - FUNCTION2')
      
              self.para1 = QComboBox()
              self.para1.addItems([" ","A","B","C"])
              
              self.para2 = QComboBox()
              self.para2.addItems([" ","D","E","F"])
      
              self.para3 = QComboBox()
              self.para3.addItems([" ","X","Y","Z"])
      
              layout.addRow(self.add_button)
              layout.addRow(self.para1)
              layout.addRow(self.para2)
              layout.addRow(self.para3)
      
      
              self.table = QTableView()
              layout.addRow(self.table)
      
              self.setLayout(layout)
              self.add_button1.clicked.connect(lambda: self.threadworker(type="function1"))
              self.add_button2.clicked.connect(lambda: self.threadworker(type="function2"))
      
          
          def threadworker(self, dfreceived, type):
              self.worker = Worker(self, type, self.para1.currentText(), self.para2.currentText(), self.para3.currentText())
              self.worker.start()
              self.worker.worksignal.connect(self.update_table_gui)
      
          def update_table_gui(self, df):
              model = TableModel(df)  
              self.table.setModel(model)
      
      def main():
          app = QApplication(sys.argv)
          main = Gui()
          main.show()
          sys.exit(app.exec())
              
      if __name__ == "__main__":   
          main()
      

      Error message:

      self.add_button1.clicked.connect(lambda: self.threadworker(type="function1"))
      TypeError: threadworker() missing 1 required positional argument: 'dfreceived'
      

      In function threadworker I have added a type variable to define which function (function1 or function2) the Worker Thread Worker to be used to calculate the dataframe and then update the QTableview.

      dfreceived is used to received the signal from worker thread.
      However, if threadworker is assigned to button with lambda (since type is required to tell which function to be used), the error shows up.

      J Offline
      J Offline
      JonB
      wrote on 17 Feb 2022, 13:09 last edited by
      #2

      @alan02011114
      I don't understand what your question is. As the error message tells you, your slot requires a dfreceived/second position argument and you are not supplying it in your lambda so you get the error.

      1 Reply Last reply
      1

      2/2

      17 Feb 2022, 13:09

      • Login

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