Home>

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 ())

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
  • 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:17

    Can the update_data function be put into a thread?

    follow_the_sun2021-02-23 18:29:17

    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?

    follow_the_sun2021-02-23 18:29:17