Как добавлять и удалять строки в QTableWidget?

Есть код, в котором вставляется в первый столбец таблицы tableWidget_3 данные dataEdit.

Как сделать так чтобы по нажатию на кнопку "удалить строку" строка удалялась,
а по нажатию на "добавить" - строку добавлялась?

main.py

import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QWidget, QLabel
from PyQt5 import uic
from PyQt5.QtWidgets import QMainWindow
from PyQt5 import QtCore, QtWidgets
from PyQt5.Qt import *


class Widget(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("UI_lke2.ui", self)

        for row in range(self.tableWidget_3.rowCount()):
            date_from = QtWidgets.QDateTimeEdit()
            date_from.setDateTime(
                QtCore.QDateTime(QtCore.QDate(2021, 8, 26),
                                 QtCore.QTime(15, 0, 0))
            )
            self.tableWidget_3.setCellWidget(row, 0, date_from)

        for row in range(self.tableWidget_3.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_3.setCellWidget(row, 0, date_from)

        
        self.dateTime0 = self.tableWidget_3.cellWidget(0, 0).dateTime()  # !!!

    def date_changed(self, dateTime, row):
        if row == 0:
            self.dateTime0 = self.tableWidget_3.cellWidget(row, 0).dateTime()
            for row in range(1, self.tableWidget_3.rowCount()):
                dateTime2 = self.tableWidget_3.cellWidget(row, 0).dateTime()
                item = QTableWidgetItem()
                item.setData(Qt.DisplayRole,
                             self.dateTime0.secsTo(dateTime2) / 60. / 60.)
                self.tableWidget_3.setItem(row, 1, item)
            return

        dateTime2 = self.tableWidget_3.cellWidget(row, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole,
                     self.dateTime0.secsTo(dateTime2) / 60. / 60.)
        self.tableWidget_3.setItem(row, 1, item)

    
    def buttonLoader(self):
        pass
        data_for_word = []
        rows = self.tableWidget_3.rowCount()
        cols = self.tableWidget_3.columnCount()
        for row in range(rows):
            dateTime = self.tableWidget_3.cellWidget(row, 0). \
                dateTime().toString('dd.MM.yyyy hh:mm')
            item = self.tableWidget_3.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')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Widget()
    ex.show()
    sys.exit(app.exec_())

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

Автор решения: S. Nick

Я отметил для вас блок и строки, которые надо изменить.

Обратите внимание UI_lke2.ui, в нем не должно быть строк в таблице!

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

Таблица в Qt Designer содержит только столбцы! Строки добавляем через insertRow.

void QTableWidget::insertRow(int row)

Вставляет пустую строку в таблицу в строке (int row).

main.py

import sys
from PyQt5 import QtCore, QtWidgets, QtGui, uic
from PyQt5.Qt import *


class Widget(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("UI_lke2.ui", self)           # !!! UI_lke2.ui изменен !!!

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv        
        self.tableWidget_3.horizontalHeader().setSectionResizeMode(
            QtWidgets.QHeaderView.Stretch) 
            
        self.btn_add = QtWidgets.QPushButton('Add')
        self.btn_add.clicked.connect(self.add_row)
        self.btn_delete = QtWidgets.QPushButton("Delete")
        self.btn_delete.clicked.connect(self.delete_row)

        self.gridLayout.addWidget(self.tableWidget_3, 0, 0, 1, 2)
        self.gridLayout.addWidget(self.btn_add, 1, 0, 1, 1)
        self.gridLayout.addWidget(self.btn_delete, 1, 1, 1, 1)

        for _ in range(3):
            rowPosition = self.tableWidget_3.rowCount()
            self.tableWidget_3.insertRow(rowPosition)         # !!! insertRow
               
            date_from = QtWidgets.QDateTimeEdit()
            dateTime = QtCore.QDateTime().currentDateTime()
            date_from.setDateTime(QtCore.QDateTime(
                QtCore.QDate(2021, 8, 26), QtCore.QTime(15, 0, 0)
                                                  )
            )
            date_from.dateTimeChanged.connect(
                lambda dateTime, row=rowPosition: 
                self.date_changed(dateTime, row))
            self.tableWidget_3.setCellWidget(rowPosition, 0, date_from)
        
        self.dateTime0 = self.tableWidget_3.cellWidget(0, 0).dateTime()  
        self.date_changed(self.dateTime0, 0)
        self.btn_add.setFocus()

    def add_row(self):
        rowPosition = self.tableWidget_3.rowCount()
        self.tableWidget_3.insertRow(rowPosition)
        date_from = QtWidgets.QDateTimeEdit()
        dateTime = QtCore.QDateTime().currentDateTime()
        date_from.setDateTime(dateTime)
        date_from.dateTimeChanged.connect(
            lambda dateTime, row=rowPosition: 
            self.date_changed(dateTime, row))
        self.tableWidget_3.setCellWidget(rowPosition, 0, date_from)
        
        self.date_changed(dateTime, rowPosition)
        
    def delete_row(self):
        row = self.tableWidget_3.currentRow()
       
        if row == 0:
            QMessageBox.warning(
                self, 
                "ВНИМАНИЕ", 
                "<b style='color: red;'>НЕ НАДО УДАЛЯТЬ ПЕРВУЮ СТРОКУ!</b>"
            )
            return         
        elif row == -1:
            msg = QMessageBox.question(
                self,
                'Message', 
                "Выберите строку, которую вы хотите удалить.", 
                QMessageBox.Ok
            )
            return 
        else:
            msg = QMessageBox.question(
                self,
                "Внимание подтвердите удаление строки!", 
                "Вы действительно хотите удалить "
                f"строку <b style='color: red;'>{row+1}</b> ?", 
                QMessageBox.Ok | QMessageBox.Cancel
            )
            if msg == QtWidgets.QMessageBox.Cancel:
                return  
            
            for _row in range(self.tableWidget_3.rowCount()):
                date_from = self.tableWidget_3.cellWidget(_row, 0)
                date_from.dateTimeChanged.disconnect()
               
            self.tableWidget_3.removeRow(row)
            
            for _row in range(self.tableWidget_3.rowCount()):
                date_from = self.tableWidget_3.cellWidget(_row, 0)
                date_from.dateTimeChanged.connect(
                    lambda dateTime, row=_row: 
                    self.date_changed(dateTime, row))            
            self.btn_add.setFocus()
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        
    def date_changed(self, dateTime, row):
        if not self.tableWidget_3.cellWidget(row, 0):                # +++
            return                                                   # +++
            
        if row == 0:
            self.dateTime0 = self.tableWidget_3.cellWidget(row, 0).dateTime()
            for row in range(1, self.tableWidget_3.rowCount()):
                dateTime2 = self.tableWidget_3.cellWidget(row, 0).dateTime()
                item = QTableWidgetItem()
                item.setData(Qt.DisplayRole,
                             self.dateTime0.secsTo(dateTime2) / 60. / 60.)
                self.tableWidget_3.setItem(row, 1, item)
            return

        dateTime2 = self.tableWidget_3.cellWidget(row, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole,
                     self.dateTime0.secsTo(dateTime2) / 60. / 60.)
        self.tableWidget_3.setItem(row, 1, item)
    
    def buttonLoader(self):
        pass
        data_for_word = []
        rows = self.tableWidget_3.rowCount()
        cols = self.tableWidget_3.columnCount()
        for row in range(rows):
            dateTime = self.tableWidget_3.cellWidget(row, 0). \
                dateTime().toString('dd.MM.yyyy hh:mm')
            item = self.tableWidget_3.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')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setFont(QtGui.QFont("Times", 12, QtGui.QFont.Bold))
    ex = Widget()
    ex.resize(500, 400)
    ex.show()
    sys.exit(app.exec_())

UI_lke2.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>320</width>
    <height>240</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QTableWidget" name="tableWidget_3">
      <column>
       <property name="text">
        <string>1</string>
       </property>
      </column>
      <column>
       <property name="text">
        <string>2</string>
       </property>
      </column>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>320</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

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

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

→ Ссылка