如何删除 QTableView 小部件中的多行?

Nem*_*XXX 1 python pyqt qtableview pyqt5

我想通过按 QPushButton 来删除 QTableView 小部件中的行。该代码对于单行工作正常,但是,当我选择多行时,总是会遗漏一行。

这是我到目前为止所拥有的:

主界面

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>350</width>
    <height>239</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QWidget" name="formLayoutWidget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>341</width>
     <height>231</height>
    </rect>
   </property>
   <layout class="QFormLayout" name="formLayout">
    <item row="0" column="1">
     <widget class="QPushButton" name="btnPopulate">
      <property name="text">
       <string>Populate Table</string>
      </property>
     </widget>
    </item>
    <item row="2" column="1">
     <widget class="QTableView" name="tableView">
      <property name="selectionBehavior">
       <enum>QAbstractItemView::SelectRows</enum>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="btnDelete">
      <property name="text">
       <string>Delete Row(s)</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>
Run Code Online (Sandbox Code Playgroud)

测试.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
from PyQt5 import uic, QtWidgets
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QDialog, QComboBox, QApplication, QHeaderView

class GUI(QDialog):

    def __init__(self):
        super(GUI, self).__init__()
        dirname = os.path.dirname(os.path.abspath(__file__))
        uic.loadUi(os.path.join(dirname,'main.ui'), self)
        # buttons
        self.btnPopulate.clicked.connect(self.populate)
        self.btnDelete.clicked.connect(self.delete)
        # table model
        self.header = ['col1', 'col2', 'col3']
        self.QSModel = QStandardItemModel()
        self.QSModel.setColumnCount(3)
        self.QSModel.setHorizontalHeaderLabels(self.header)
        self.tableView.setModel(self.QSModel)
        self.tableView.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        
    def populate(self):
        row = self.QSModel.rowCount()
        for x in range(7):
            self.QSModel.insertRow(row)
            self.QSModel.setData(self.QSModel.index(row, 0), 'data' + str(x))
            self.QSModel.item(row, 0).setEditable(True)
            self.QSModel.setData(self.QSModel.index(row, 1), 'data' + str(x))
            self.QSModel.item(row, 1).setEditable(True)
            self.QSModel.setData(self.QSModel.index(row, 2), 'data' + str(x))
            self.QSModel.item(row, 1).setEditable(True) 

    def delete(self):
        if self.tableView.selectionModel().hasSelection():
            indexes = self.tableView.selectionModel().selectedRows() 
            for index in sorted(indexes):
                print('Deleting row %d...' % index.row())
                self.QSModel.removeRow(index.row())
        else:
            print('No row selected!')
            
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = GUI()
    window.show()
    sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)

我有以下问题:

  1. 为什么当我选择多行时总是没有删除一行?我需要更改什么才能删除所有选定的行?
  2. 如何在删除完成后自动选择下一行,以便通过重复单击“删除行”按钮来删除整个表?
  3. 是否有内置方法允许我将 QPushButton 或其操作连接到 DEL/BACKSPACE 按键?即,我希望按 DEL/BACKSPACE 按键来触发 delete()。

eyl*_*esc 5

为什么当我选择多行时总是没有删除一行?我需要更改什么才能删除所有选定的行?

问题是通过重置位置来删除一行造成的,比如你删除3,4,5,先删除3,然后4变成3,5变成4,然后你删除4,删除当前的4所以最初的 4 没有被删除。

QModelIndex是临时索引,如果位置发生更改,则不会收到通知,相反,QPersistentModelIndex如果收到通知,则即使行发生更改,您也必须使用它们来获取行。

def delete(self):
    if self.tableView.selectionModel().hasSelection():
        indexes =[QPersistentModelIndex(index) for index in self.tableView.selectionModel().selectedRows()]
        for index in indexes:
            print('Deleting row %d...' % index.row())
            self.QSModel.removeRow(index.row())
    else:
        print('No row selected!')
Run Code Online (Sandbox Code Playgroud)

如何在删除完成后自动选择下一行,以便通过重复单击“删除行”按钮来删除整个表?

要选择新行,您必须通过 的setCurrentIndex()方法将该行的某些项目设置为活动状态QTableView,在本示例中,我计算最后一行,并由此获得QPersistentModelIndex下一行的项目的 ,删除后我将其转换为QModelIndex并且我在前面的方法中使用它。

def delete(self):
    if self.tableView.selectionModel().hasSelection():
        indexes =[QPersistentModelIndex(index) for index in self.tableView.selectionModel().selectedRows()]
        maxrow = max(indexes, key=lambda x: x.row()).row()
        next_ix = QPersistentModelIndex(self.QSModel.index(maxrow+1, 0))
        for index in indexes:
            print('Deleting row %d...' % index.row())
            self.QSModel.removeRow(index.row())
        self.tableView.setCurrentIndex(QModelIndex(next_ix))
    else:
        print('No row selected!')
Run Code Online (Sandbox Code Playgroud)

是否有内置方法允许我将 QPushButton 或其操作连接到 DEL/BACKSPACE 按键?即,我希望按 DEL/BACKSPACE 按键来触发 delete()。

要获取键盘事件,您必须覆盖该keyPressEvent方法,此事件作为一个对象发生QKeyEvent,该对象具有返回按下的键的键方法,验证它是否是所需的键,如果是,则调用delete()

def keyPressEvent(self, event):
    if event.key() in (Qt.Key_Backspace, Qt.Key_Delete):
        self.delete()
    QDialog.keyPressEvent(self, event)
Run Code Online (Sandbox Code Playgroud)