Updating GUI element (QTableview) with QThread, with conditionally setting dataframe
-
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 atype
variable to define which function (function1
orfunction2
) the Worker ThreadWorker
to be used to calculate the dataframe and then update theQTableview
.dfreceived
is used to received the signal from worker thread.
However, ifthreadworker
is assigned to button withlambda
(since type is required to tell which function to be used), the error shows up. -
@alan02011114
I don't understand what your question is. As the error message tells you, your slot requires adfreceived
/second position argument and you are not supplying it in your lambda so you get the error.