Solved QTableVIew
-
Hi, if a user presses a button on my PyQt5 GUI, it runs a python script which dumps data into a .csv file and then I use pandas to create dataframe out of the .csv. Finally, the dataframe is displayed using QTableView in a new window without any problem.
However, there is an additional checkbox option in my GUI. If checked, the python script will continuously run and overwrite the .csv file, meaning 5 different datasets. I want GUI to update the QTableView for every overwrite. For each overwrite, all data is overwritten (meaning all rows of data in dataframe)
For debugging, rather than continuous run, I have altered the checkbox option code so that python script is ran only 5 times. Couple of issues I'm seeing:
- While the python script is running 5 times, the window with displayed table is not accessible until all 5 script runs are finished.
- Upon each python script run, the QTableVIew is not updated. I can verify because once the QTableView is accessible after 5th run, it is not matching the 5th output.
Ideally I want only the data to update if checkbox option is clicked.
Here is my code (kind of minimized/variables changed for privacy purposes):
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout from PyQt5.QtGui import QIcon from PyQt5 import QtWidgets, QtCore, uic, QtGui from PyQt5.QtWidgets import QMessageBox class TableModel(QtCore.QAbstractTableModel): def __init__(self, data, parent=None): QtCore.QAbstractTableModel.__init__(self, parent) self._data = data def rowCount(self, parent=None): return len(self._data.index) def columnCount(self, parent=None): return self._data.columns.size def data(self, index, role=QtCore.Qt.DisplayRole): if index.isValid(): if role == QtCore.Qt.DisplayRole: return str(self._data.iloc[index.row(), index.column()]) return None def headerData(self, rowcol, orientation, role): if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole: return self._data.columns[rowcol] if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole: return self._data.index[rowcol] return None def flags(self, index): flags = super(self.__class__, self).flags(index) flags |= QtCore.Qt.ItemIsEditable flags |= QtCore.Qt.ItemIsSelectable flags |= QtCore.Qt.ItemIsEnabled flags |= QtCore.Qt.ItemIsDragEnabled flags |= QtCore.Qt.ItemIsDropEnabled return flags def sort(self, Ncol, order): """Sort table by given column number. """ try: self.layoutAboutToBeChanged.emit() self._data = self._data.sort_values(self._data.columns[Ncol], ascending=not order) self.layoutChanged.emit() except Exception as e: print(e) class App(QtWidgets.QMainWindow): def __init__(self): super(App, self).__init__() uic.loadUi('Example.ui', self) self.button.clicked.connect(self.run_script) self.checkboxbutton.stateChanged.connect(self.run_script_5times) def run_script(self): self.script_cmd = 'python3.7 example.py > example_data.csv' os.system(self.script_cmd) df = pd.read_csv('example_data.csv', index_col=False) self.model = TableModel(df) self.table = QtWidgets.QTableView() self.table.setModel(self.model) self.table.show() def run_script_5times(self, state): i = 0 while state == QtCore.Qt.Checked and i < 5: time.sleep(3) os.system(self.script_cmd) df2 = pd.read_csv('example_data.csv', index_col=False) self.model.data=df2 self.model.layoutChanged.emit() i = i + 1 ``
End goal is to have a table update with each python run without the table reloading, only the data. RIght now table is not updating and secondly once it does, I have seen examples where refresh is choppy - would like to avoid that. Let me know if I can help clarify - if someone knows options I can try?
-
Upon each python script run, the QTableVIew is not updated. I can verify because once the QTableView is accessible after 5th run, it is not matching the 5th output.
and secondly once it does, I have seen examples where refresh is choppy - would like to avoid that
Not sure what exactly you mean by either of these, or how they are connected.
self.model = TableModel(df) self.table = QtWidgets.QTableView() self.table.setModel(self.model)
Not sure how your
QTableView
is shown since it's not parented byQMainWindow
noraddWidget()
-ed anywhere. You sure you're loading into the table you see?. Maybe it's right to recreate the model & view each time, but when you talk about "choppy" I would be thinking about having one constant view, and perhaps one constant model which gets reloaded from the script.Test your code without any of the Python scrip[t/csv stuff, and if any funnies also don't do any sorting and see if that is relevant.
-
@worldsnexthero said in QTableVIew:
displayed table is not accessible until all 5 script runs are finished.
Don't, and never, use
time.sleep()
, it blocks the event loop/updates. And your loop re-reads the file without allowing update even if you didn't have thesleep()
there. Use aQTimer
. Start with that, see whether that affects your second comment too. -
Awesome, this does fix (1) qtableview window inaccessible. this is solved.
After removing time.sleep() from the code, the existing code from original comment does not update qtableview, that problem still exists. Have looked at numerous sources online and have not seen much help regarding qtableview being overwritten with new data (same table format) from another pandas dataframe. Any thoughts on this front?
-
Upon each python script run, the QTableVIew is not updated. I can verify because once the QTableView is accessible after 5th run, it is not matching the 5th output.
and secondly once it does, I have seen examples where refresh is choppy - would like to avoid that
Not sure what exactly you mean by either of these, or how they are connected.
self.model = TableModel(df) self.table = QtWidgets.QTableView() self.table.setModel(self.model)
Not sure how your
QTableView
is shown since it's not parented byQMainWindow
noraddWidget()
-ed anywhere. You sure you're loading into the table you see?. Maybe it's right to recreate the model & view each time, but when you talk about "choppy" I would be thinking about having one constant view, and perhaps one constant model which gets reloaded from the script.Test your code without any of the Python scrip[t/csv stuff, and if any funnies also don't do any sorting and see if that is relevant.