Как взаимодействовать с данным из таблицы Pyqt5?

Есть таблица, в первый ее столбик пользователь вносит дату в формате (час.минуты.день.месяц.год).
После чего по нажатию на кнопку во второй столбец должна выводится разница времени от первой строчки до второй, после от второй до третьей и тд. Выглядит это так:

Красным отмечена нужная таблица

Я сделал вот такой код: test_ui.py

from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(320, 240)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setObjectName(u"pushButton")

        self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)

        self.tableWidget = QTableWidget(self.centralwidget)
        if (self.tableWidget.columnCount() < 2):
            self.tableWidget.setColumnCount(2)
        __qtablewidgetitem = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
        __qtablewidgetitem1 = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
        if (self.tableWidget.rowCount() < 3):
            self.tableWidget.setRowCount(3)
        __qtablewidgetitem2 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, __qtablewidgetitem2)
        __qtablewidgetitem3 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, __qtablewidgetitem3)
        __qtablewidgetitem4 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(2, __qtablewidgetitem4)
        self.tableWidget.setObjectName(u"tableWidget")
        self.tableWidget.horizontalHeader().setDefaultSectionSize(130)

        self.gridLayout.addWidget(self.tableWidget, 0, 0, 1, 1)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 320, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435", None))
        ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)
        ___qtablewidgetitem.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0430\u0442\u0430", None));
        ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1)
        ___qtablewidgetitem1.setText(QCoreApplication.translate("MainWindow", u"\u041e\u0431\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0447\u0430\u0441", None));
        ___qtablewidgetitem2 = self.tableWidget.verticalHeaderItem(0)
        ___qtablewidgetitem2.setText(QCoreApplication.translate("MainWindow", u"1", None));
        ___qtablewidgetitem3 = self.tableWidget.verticalHeaderItem(1)
        ___qtablewidgetitem3.setText(QCoreApplication.translate("MainWindow", u"2", None));
        ___qtablewidgetitem4 = self.tableWidget.verticalHeaderItem(2)
        ___qtablewidgetitem4.setText(QCoreApplication.translate("MainWindow", u"3", None));

Логика такая: main.py

import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from test_ui import Ui_MainWindow
from docxtpl import DocxTemplate



app = QApplication(sys.argv)

Window = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(Window)
Window.setFixedSize(320, 240)
Window.show()

def buttonLoader():
    rows = ui.tableWidget.rowCount()
    cols = ui.tableWidget.columnCount()
    data = []
    for row in range(rows):
        tmp = []
        for col in range(cols):
            try:
                tmp.append(ui.tableWidget.item(row, col).text())
            except:
                tmp.append('')
        data.append(tmp)

    data_for_word = []
    for i in data: print(i)

    for i in data:
        if i[0] != '':
            data_for_word.append(i)

    for item in data:
        if any(item):
            data_for_word.append({
                "data": item[0],
                "time": item[1]
            })

    doc = DocxTemplate('test_ui.docx')

    context = {
        'tbl_contents': data_for_word
    }

    doc.render(context)
    doc.save('table.docx')


ui.pushButton.clicked.connect(buttonLoader)


sys.exit(app.exec_())

Здесь данные получаются из таблицы и вставляются в шаблон word.
Такого типа:

введите сюда описание изображения

Но, как сделать такие вычисления не знаю. Если кто знает напишите пример или дополните мой код пример.


Ответы (2 шт):

Автор решения: Alexander Chernin

вносит дату в формате ( час.минуты.день.месяц.время* )

  • наверное опечатка и имеется в виду год

В нахождении разницы между двумя датами в часах можно обратиться к классу QDateTime

# Для PySide2
from PySide2.QtCore import QDateTime
# PySide6
from PySide6.QtCore import QDateTime
# PyQt5
from PyQt5.QtCore import QDateTime

# Формат представления даты
format = "hh:mm dd.MM.yyyy"

# Пример задания дат в соответствии с форматом
dateTime1 = QDateTime.fromString("12:34 01.01.2021", format)
dateTime2 = QDateTime.fromString("12:54 01.01.2021", format)

# Получение разницы между датами в секундах
# /60. - в минутах
# /60. в часах
print(dateTime1.secsTo(dateTime2) / 60. / 60.)
→ Ссылка
Автор решения: S. Nick

Я не знаком с библиотекой docxtpl, поэтому я закомментировал все что с ней связано.

Я так понял, что вам нужен многомерный список, который содержит сведения о дате и какое-то число (например, разница времени в часах между первой и второй строками).

Если это так, то data_for_word получается по нажатию на 'Считать данные'.

Если этого для вас мало, то как-то предоставьте test_ui.docx
с таблицей, которую вы редактируете и я попробую посмотреть что у вас еще не так.

'''
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
'''
from PyQt5.Qt import *
#from docxtpl import DocxTemplate                   # pip install docxtpl

#from test_ui import Ui_MainWindow
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(320, 240)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setObjectName(u"pushButton")
        self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
        self.tableWidget = QTableWidget(self.centralwidget)
        if (self.tableWidget.columnCount() < 2):
            self.tableWidget.setColumnCount(2)
        __qtablewidgetitem = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
        __qtablewidgetitem1 = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
        if (self.tableWidget.rowCount() < 3):
            self.tableWidget.setRowCount(3)
        __qtablewidgetitem2 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, __qtablewidgetitem2)
        __qtablewidgetitem3 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, __qtablewidgetitem3)
        __qtablewidgetitem4 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(2, __qtablewidgetitem4)
        self.tableWidget.setObjectName(u"tableWidget")
        self.tableWidget.horizontalHeader().setDefaultSectionSize(130)
        self.gridLayout.addWidget(self.tableWidget, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 320, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435", None))
        ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)
        ___qtablewidgetitem.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0430\u0442\u0430", None));
        ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1)
        ___qtablewidgetitem1.setText(QCoreApplication.translate("MainWindow", u"\u041e\u0431\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0447\u0430\u0441", None));
        ___qtablewidgetitem2 = self.tableWidget.verticalHeaderItem(0)
        ___qtablewidgetitem2.setText(QCoreApplication.translate("MainWindow", u"1", None));
        ___qtablewidgetitem3 = self.tableWidget.verticalHeaderItem(1)
        ___qtablewidgetitem3.setText(QCoreApplication.translate("MainWindow", u"2", None));
        ___qtablewidgetitem4 = self.tableWidget.verticalHeaderItem(2)
        ___qtablewidgetitem4.setText(QCoreApplication.translate("MainWindow", u"3", None));
        

class MainWindow(QMainWindow, Ui_MainWindow):   
    def __init__(self):
        super().__init__()
        
        self.setupUi(self)
        self.pushButton.clicked.connect(self.buttonLoader)
        
        for row in range(self.tableWidget.rowCount()):
            date_from = QDateTimeEdit()
            date_from.setDateTime(
                QDateTime(QDate(2021, 9, 2))
            )
            date_from.dateTimeChanged.connect(
                lambda dateTime, row=row: self.date_changed(dateTime, row))
            self.tableWidget.setCellWidget(row, 0, date_from)

        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, 0)             
        self.tableWidget.setItem(0, 1, item)
        
        for row in range(1, self.tableWidget.rowCount()):    
            dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row, 1, item) 

    def date_changed(self, dateTime, row):
        if row == 0:
            dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row+1, 1, item) 
            return
            
        dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
        dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
        self.tableWidget.setItem(row, 1, item) 
        
        if row != self.tableWidget.rowCount() - 1:
            dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row+1, 1, item)                 
        
    def buttonLoader(self):
        pass
        data_for_word = []
        rows = self.tableWidget.rowCount()
        cols = self.tableWidget.columnCount()
        for row in range(rows):
            dateTime = self.tableWidget.cellWidget(row, 0).\
                       dateTime().toString('dd.MM.yyyy hh:mm')
            item = self.tableWidget.item(row, 1)
            _data = item.data(Qt.DisplayRole)
            data_for_word.append([dateTime, _data])
        
        print(f'\n{data_for_word}\n')
        print(* data_for_word, sep='\n')                      


'''    
        doc = DocxTemplate('test_ui.docx')
        context = {
            'tbl_contents': data_for_word
        }
        doc.render(context)
        doc.save('table.docx')        
'''


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    app.setFont(QFont("Times", 10, QFont.Bold))
    w = MainWindow()
    w.resize(320, 240)
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения



Update

Мне не понятна логика вычисления разницы времени.


В колонке с индексом 0 у нас QDateTimeEdit.
Класс QDateTimeEdit предоставляет виджет для редактирования даты и времени.

void QDateTimeEdit::dateTimeChanged(const QDateTime &datetime)

Этот сигнал излучается всякий раз, когда изменяется дата или время. Новые дата и время передаются в datetime.

Мы также дополнительно передаеи в слот date_changed() номер строки row=row, в которой происходят изменения.

    ...
    for row in range(self.tableWidget.rowCount()):
        date_from = QDateTimeEdit()
        date_from.setDateTime(
            QDateTime(QDate(2021, 9, 2))
        )
        date_from.dateTimeChanged.connect(
            lambda dateTime, row=row: self.date_changed(dateTime, row))
        self.tableWidget.setCellWidget(row, 0, date_from)
    ...   
        

В методе date_changed() производим вычисления разницы времени,
как только изменяется дата или время в какой-либо строке.

...
def date_changed(self, dateTime, row):

    if row == 0:      # если изменения в строке, т.е. в первой строке
        dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
        dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
        self.tableWidget.setItem(row+1, 1, item) 
        return        # выходим, т.к. все что связано с изменением
                      # dateTime в первой строке сделали
    
    # для других строк 2, 3, ..., т.е. не первой         
    dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
    dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
    item = QTableWidgetItem()
    item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
    self.tableWidget.setItem(row, 1, item) 

    # для других строк 2, 3, ..., кроме последней строки !         
    if row != self.tableWidget.rowCount() - 1:
        dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
        dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
        self.tableWidget.setItem(row+1, 1, item) 

dateTime : QDateTime

https://doc.qt.io/qt-5/qdatetimeedit.html#dateTime-prop

Это свойство содержит QDateTime, установленный в QDateTimeEdit.

 #  QDateTime <-          QDateTimeEdit.dateTime()    
    dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
    dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
    
    item = QTableWidgetItem()
    

qint64 QDateTime::secsTo(const QDateTime &other) const

Возвращает количество секунд от dateTime1 до другого dateTime2. Если другое dateTime2 раньше, чем это dateTime1, возвращаемое значение отрицательное.

    #                            vvvvvvvvvvvvvvvvvvvvvvvvvvv
    item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
    self.tableWidget.setItem(row, 1, item) 

  
→ Ссылка