In the main window MainWindow
, the table self.tableWidget
is created, which receives data from the DataParser
class (in this example, this class is not explicitly used , an example of data sent by this class is list_to_add
).
Data like list_to_add
can come at any time. When receiving data, you need to add a new record to the table. For existing records, you need to subtract every second from the current date and time, the date and time in list_to_add
corresponding to each record and dynamically update the values in the table accordingly. with the result.
Example:
list_to_add= ['2021-02-02 09:00:00', 'PROGRAM', 'START'] # [operation date, operation name, status]
Upon receipt of such a list, we create a new row, create a cell in which we store the difference between the current date and time and '2021-02-02 09:00:00'
, update this cell every second.
from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QTableWidget, QTableWidgetItem
from PyQt5.QtCore import QSize, Qt
from datetime import datetime
from PyQt5.QtGui import *
class MainWindow (QMainWindow):
# Override class constructor
def __init __ (self):
# You must call the super class method
QMainWindow .__ init __ (self)
self.setMinimumSize (QSize (480, 80)) # Set sizes
self.setWindowTitle ("Working with QTableWidget") # Set the window title
central_widget= QWidget (self) # Create a central widget
self.setCentralWidget (central_widget) # Install the central widget
grid_layout= QGridLayout (self) # Create QGridLayout
central_widget.setLayout (grid_layout) # Set this layout in central widget
self.tableWidget= QTableWidget (self) # Create a table
header_font= QFont ('Sergoe UI', 12)
header_font.setWeight (QFont.Bold)
self.tableWidget.setColumnCount (3)
self.tableWidget.setHorizontalHeaderLabels (["Relative Time", "Absolute Time", "Operation Name"])
self.tableWidget.horizontalHeaderItem (0) .setFont (header_font)
self.tableWidget.horizontalHeaderItem (1) .setFont (header_font)
self.tableWidget.horizontalHeaderItem (2) .setFont (header_font)
self.tableWidget.setColumnWidth (0, 250)
self.tableWidget.setColumnWidth (1, 250)
self.tableWidget.setColumnWidth (2, 250)
list_to_add= ['2021-02-02 09:00:00', 'PROGRAM', 'START'] # [operation date, operation name, status]
rowPos= self.tableWidget.rowCount ()
date_now= datetime.now ()
datetime_event= datetime.strptime (list_to_add [0], '% Y-% m-% d% H:% M:% S')
delta_sec= (datetime.now () -datetime_event) .total_seconds ()
time_abs= self.convert_sec_to_time (delta_sec)
self.tableWidget.insertRow (rowPos)
self.tableWidget.setItem (rowPos, 2, QTableWidgetItem (list_to_add [1]))
self.tableWidget.setItem (rowPos, 1, QTableWidgetItem (time_abs))
# grid_layout.addWidget (table, 0, 0) # Adding the table to the grid
def convert_sec_to_time (self, seconds) ->str:
hours, remainder= divmod (seconds, 3600)
minutes, seconds= divmod (remainder, 60)
return '{: 02}: {: 02}: {: 02}'. format (int (hours), int (minutes), int (seconds))
if __name__== "__main__":
import sys
app= QApplication (sys.argv)
mw= MainWindow ()
mw.show ()
sys.exit (app.exec ())
-
Answer # 1
From what I understand, to fetch data you need to store
'2021-02-02 09:00:00'
and I did it by storing this data in a column with index 3 .You can choose not to show it in the table by applying the line:
self.tableWidget.setColumnHidden (3, True)
I've implemented updating the data after every new row is added. If you still need to update every second (?), then you need to implement repeating
QTimer
and execute every second:# update the values in the table rows= self.tableWidget.rowCount () for row in range (rows): _data= self.tableWidget.item (row, 3) .text () time_abs= self.time_abs_func ([_ data,]) # please note that I am inserting updated data !!! # in the column with index 0 (zero) -so you can see what is happening !!! self.tableWidget.setItem (row, 0, QTableWidgetItem (time_abs)) # self.tableWidget.setItem (row, 1, QTableWidgetItem (time_abs))
I commented my example for you, try:
import sys import random # +++ from datetime import datetime from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, \ QTableWidget, QTableWidgetItem from PyQt5.QtCore import QSize, Qt, QThread, pyqtSignal from PyQt5.QtGui import QFont class DataParser (QThread): data_signal= pyqtSignal (list) def __init __ (self): super (DataParser, self) .__ init __ () self._date= '' self._nameProg= '' self._start= '' self._flag= True def run (self): self.msleep (2000) # insert your logic for getting the list list_to_add into this loop # I have this random _list, which is generated every 10 seconds, # so that you can calmly observe what is happening while (self._flag): # '2021-02-02 09:00:00' notice I changed the date self._date= f'2021-02-03 {random.randrange (0, 24): 0 > 2}: '\ f '{random.randrange (0, 60): 0 > 2}: '\ f '{random.randrange (0, 60): 0 > 2} ' self._nameProg= f'PROGRAM {random.randrange (1.99): 0 > 2} ' self._start= 'Anything else?' _list= [self._date, self._nameProg, self._start] self.data_signal.emit (_list) # send the list to the main thread self.msleep (10000) # sleep for 10 seconds class MainWindow (QMainWindow): def __init __ (self): super () .__ init __ () self.setMinimumSize (QSize (480, 100)) self.setWindowTitle ("Working with QTableWidget") central_widget= QWidget (self) self.setCentralWidget (central_widget) grid_layout= QGridLayout (central_widget) # -self -> + central_widget !!! # central_widget.setLayout (grid_layout) # ---no self.tableWidget= QTableWidget (self) header_font= QFont ('Sergoe UI', 12) header_font.setWeight (QFont.Bold) self.tableWidget.setColumnCount (4) # (3) notice I added a column self.tableWidget.setHorizontalHeaderLabels ( ["Relative time", "Absolute time", "Operation name"]) self.tableWidget.horizontalHeaderItem (0) .setFont (header_font) self.tableWidget.horizontalHeaderItem (1) .setFont (header_font) self.tableWidget.horizontalHeaderItem (2) .setFont (header_font) self.tableWidget.setColumnWidth (0, 190) # 250 self.tableWidget.setColumnWidth (1, 180) # 250 self.tableWidget.setColumnWidth (2, 180) # 250 self.tableWidget.setColumnWidth (3, 180) # note I added a column # ATTENTION !!! uncomment the line below to Hide the column at index 3 !!! # self.tableWidget.setColumnHidden (3, True) # Hide the column with index 3 !!! # list_to_add= ['2021-02-03 09:00:00', 'PROGRAM', 'START'] # pay attention I changed the date list_to_add= ['2021-02-03 17:20:00', 'PROGRAM', 'START'] # !!! rowPos= self.tableWidget.rowCount () time_abs= self.time_abs_func (list_to_add) # -print (f'time_abs= {time_abs} ') self.tableWidget.insertRow (rowPos) self.tableWidget.setItem (rowPos, 1, QTableWidgetItem (time_abs)) self.tableWidget.setItem (rowPos, 2, QTableWidgetItem (list_to_add [1])) # notice I added the vvv column !!! self.tableWidget.setItem (rowPos, 3, QTableWidgetItem (list_to_add [0])) # grid_layout.addWidget (table, 0, 0) # Adding the table to the grid grid_layout.addWidget (self.tableWidget, 0, 0) # +++ !!! # +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv self.thread= DataParser () self.thread.data_signal.connect (self.update_data) self.thread.start () def time_abs_func (self, list_to_add): date_now= datetime.now () datetime_event= datetime.strptime (list_to_add [0], '% Y-% m-% d% H:% M:% S') delta_sec= (datetime.now () -datetime_event) .total_seconds () return self.convert_sec_to_time (delta_sec) def convert_sec_to_time (self, seconds) -> str: hours, remainder= divmod (seconds, 3600) minutes, seconds= divmod (remainder, 60) return '{: 02}: {: 02}: {: 02}'. format (int (hours), int (minutes), int (seconds)) def update_data (self, _data): "" "Here we add a new record to the table and dynamically update the values in the table. _data is derived from DataParser class -list_to_add "" " time_abs= self.time_abs_func (_data) # rowPos= self.tableWidget.rowCount () # add to the end rowPos= 0 # add to the beginning # add a new entry self.tableWidget.insertRow (rowPos) self.tableWidget.setItem (rowPos, 1, QTableWidgetItem (time_abs)) self.tableWidget.setItem (rowPos, 2, QTableWidgetItem (_data [1])) self.tableWidget.setItem (rowPos, 3, QTableWidgetItem (_data [0])) # !!! # update the values in the table rows= self.tableWidget.rowCount () # for row in range (0, rows-1): # for rowPos= self.tableWidget.rowCount () for row in range (1, rows): # for rowPos= 0 _data= self.tableWidget.item (row, 3) .text () time_abs= self.time_abs_func ([_ data,]) # please note that I am inserting updated data !!! # in the column with index 0 (zero) -so you can see what is happening !!! self.tableWidget.setItem (row, 0, QTableWidgetItem (time_abs)) # self.tableWidget.setItem (row, 1, QTableWidgetItem (time_abs)) if __name__== "__main__": app= QApplication (sys.argv) app.setFont (QFont ("Times", 10, QFont.Bold))mw= MainWindow () mw.resize (810, 500) mw.show () sys.exit (app.exec_ ())
Update
Please tell me how to make the existing records in the "absolute time" section updated every second? Do you also need to create a separate thread for this?
Pay attention to the lines marked with
# *** QTimer
import sys import random # +++ from datetime import datetime from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, \ QTableWidget, QTableWidgetItem from PyQt5.QtCore import QSize, Qt, QThread, pyqtSignal, QTimer # *** QTimer from PyQt5.QtGui import QFont class DataParser (QThread): data_signal= pyqtSignal (list) def __init __ (self): super (DataParser, self) .__ init __ () self._date= '' self._nameProg= '' self._start= '' self._flag= True def run (self): self.msleep (2000) # insert your logic for getting the list list_to_add into this loop # I have this random _list, which is generated every 5 seconds, # so that you can calmly observe what is happening while (self._flag): # '2021-02-02 09:00:00' notice I changed the date self._date= f'2021-02-03 {random.randrange (0, 24): 0 > 2}: '\ f '{random.randrange (0, 60): 0 > 2}: '\ f '{random.randrange (0, 60): 0 > 2} ' self._nameProg= f'PROGRAM {random.randrange (1.99): 0 > 2} ' self._start= 'Anything else?' _list= [self._date, self._nameProg, self._start] self.data_signal.emit (_list) # send the list to the main thread self.msleep (5000) # sleep for 5 seconds !!! class MainWindow (QMainWindow): def __init __ (self): super () .__ init __ () self.setMinimumSize (QSize (480, 100)) self.setWindowTitle ("Working with QTableWidget") central_widget= QWidget (self) self.setCentralWidget (central_widget) grid_layout= QGridLayout (central_widget) # -self -> + central_widget !!! # central_widget.setLayout (grid_layout) # ---no self.tableWidget= QTableWidget (self) header_font= QFont ('Sergoe UI', 12) header_font.setWeight (QFont.Bold) self.tableWidget.setColumnCount (4) # (3) notice I added a column self.tableWidget.setHorizontalHeaderLabels ( ["Relative time", "Absolute time", "Operation name"] ) self.tableWidget.horizontalHeaderItem (0) .setFont (header_font) self.tableWidget.horizontalHeaderItem (1) .setFont (header_font) self.tableWidget.horizontalHeaderItem (2) .setFont (header_font) self.tableWidget.setColumnWidth (0, 190) # 250 self.tableWidget.setColumnWidth (1, 180) # 250 self.tableWidget.setColumnWidth (2, 180) # 250 self.tableWidget.setColumnWidth (3, 180) # note I added a column # ATTENTION !!! uncomment the line below to Hide the column at index 3 !!! self.tableWidget.setColumnHidden (3, True) # Hide the column with index 3 !!! # list_to_add= ['2021-02-03 09:00:00', 'PROGRAM', 'START'] # pay attention I changed the datelist_to_add= ['2021-02-03 17:20:00', 'PROGRAM', 'START'] # !!! rowPos= self.tableWidget.rowCount () time_abs= self.time_abs_func (list_to_add) # -print (f'time_abs= {time_abs} ') self.tableWidget.insertRow (rowPos) self.tableWidget.setItem (rowPos, 1, QTableWidgetItem (time_abs)) self.tableWidget.setItem (rowPos, 2, QTableWidgetItem (list_to_add [1])) # notice I added the vvv column !!! self.tableWidget.setItem (rowPos, 3, QTableWidgetItem (list_to_add [0])) # grid_layout.addWidget (table, 0, 0) # Adding the table to the grid grid_layout.addWidget (self.tableWidget, 0, 0) # +++ !!! self.thread= DataParser () self.thread.data_signal.connect (self.update_data) self.thread.start () self.timer= QTimer (self, interval= 1000, timeout= self.updateTime) # *** QTimer self.timer.start () # *** QTimer def updateTime (self): # *** QTimer # update the values in the table rows= self.tableWidget.rowCount () for row in range (rows): _data= self.tableWidget.item (row, 3) .text () time_abs= self.time_abs_func ([_ data,]) # please note that I am inserting updated data !!! # in the column with index 0 (zero) -so you can see what is happening !!! # self.tableWidget.setItem (row, 0, QTableWidgetItem (time_abs)) self.tableWidget.setItem (row, 1, QTableWidgetItem (time_abs)) def time_abs_func (self, list_to_add): date_now= datetime.now () datetime_event= datetime.strptime (list_to_add [0], '% Y-% m-% d% H:% M:% S') delta_sec= (datetime.now () -datetime_event) .total_seconds () return self.convert_sec_to_time (delta_sec) def convert_sec_to_time (self, seconds) -> str: hours, remainder= divmod (seconds, 3600) minutes, seconds= divmod (remainder, 60) return '{: 02}: {: 02}: {: 02}'. format (int (hours), int (minutes), int (seconds)) def update_data (self, _data): "" "Here we add a new record to the table and dynamically update the values in the table. _data is derived from DataParser class -list_to_add "" " time_abs= self.time_abs_func (_data) # rowPos= self.tableWidget.rowCount () # add to the end rowPos= 0 # add to the beginning # add a new entry self.tableWidget.insertRow (rowPos) self.tableWidget.setItem (rowPos, 1, QTableWidgetItem (time_abs)) self.tableWidget.setItem (rowPos, 2, QTableWidgetItem (_data [1])) self.tableWidget.setItem (rowPos, 3, QTableWidgetItem (_data [0])) # !!! '' ' # update the values in the table rows= self.tableWidget.rowCount () # for row in range (0, rows-1): # for rowPos= self.tableWidget.rowCount () for row in range (1, rows): # for rowPos= 0 _data= self.tableWidget.item (row, 3) .text () time_abs= self.time_abs_func ([_ data,]) # please note that I am inserting updated data !!! # in the column with index 0 (zero) -so you can see what is happening !!! # self.tableWidget.setItem (row, 0, QTableWidgetItem (time_abs)) self.tableWidget.setItem (row, 1, QTableWidgetItem (time_abs)) '' ' if __name__== "__main__": app= QApplication (sys.argv) app.setFont (QFont ("Times", 10, QFont.Bold)) mw= MainWindow () mw.resize (810, 500)mw.show () sys.exit (app.exec_ ())
@follow_the_sun is not quite sure where you want to put the update_data method. Ask a new question, give an example of what and where you want to place and why you want to do it, and also tell us what you are failing.
S. Nick2021-02-23 18:29:17Can the update_data function be put into a thread?
follow_the_sun2021-02-23 18:29:17Please tell me how to make the existing records in the "absolute time" section updated every second? Do you also need to create a separate thread for this?
follow_the_sun2021-02-23 18:29:17
- python : QThread thread in PyQt5 has to wait for data input
- python : Remove buttons from form
- python : How do I change the border color of a QLineEdit when it is selected?
- python : How to switch between widgets by pressing Enter?
- python : How do I get a reference to a QTreeView item?
- python : TypeError: PyQt5.QtWidgets.QAbstractItemView represents a c++ abstract class and cannot be instantiated
- python : How to hide QPainter on button click?
- python : How do I move the QLabel left and right?
- python : Items on the second screen are not displayed
- Logical error in Python code
please provide a minimal reproducible example and better tell us what you want to update and what data you want to update.
S. Nick2021-02-23 18:29:17