如何在PyQt中从QTableView中删除行?

12

我正在使用QStandardItemModel来管理我的QTableView。

import ui_my_viewlogs
import os
from PyQt4 import QtCore, QtGui

class my_viewlogs(QtGui.QDialog, ui_my_viewlogs.Ui_viewlogs):
    def __init__(self):
        super(my_viewlogs, self).__init__()
        self.setupUi(self)
        self.model = QtGui.QStandardItemModel()
        self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.header_names = ['abc', 'def', 'ghi', 'kjl', 'mno', 'pqr']
        self.model.setHorizontalHeaderLabels(self.header_names)
        self.tableView.verticalHeader().setVisible(False)
        self.tableView.setShowGrid(False)
        self.selectionModel = self.tableView.selectionModel()
        self.tableView.customContextMenuRequested.connect(self.open_menu)
        self.tableView.setModel(self.model)
        self.tableView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)

    def open_menu(self, position):
        menu = QtGui.QMenu()
        remove_selected_item_icon = QtGui.QIcon()
        remove_selected_item_icon.addPixmap(QtGui.QPixmap(":/images      /Images/deleteSelected.png"), QtGui.QIcon.Normal, QtGui.QIcon.On)
        remove_selected_item = menu.addAction(remove_selected_item_icon, "Remove selected item(s) ")
        if action == remove_selected_item:           
            model = self.model
            indices = self.tableView.selectionModel().selectedRows() 
            for index in sorted(indices):
                model.removeRow(index.row(), QtCore.QModelIndex()) 

当我尝试删除所选行(即model.removeRow())时,出现错误“TypeError:QAbstractItemModel.removeRow()的第1个参数类型无效”。

我搜索了很多关于在pyqt的qtableview中正确删除所选行/行的方法,但是我无法删除所选行/行。

请问你能分享一段样例代码用于在pyqt的qtableview中删除所选行/行吗?


1
为什么要将 QtCore.QModelIndex 类传递给 removeRow?如果有的话,它应该是一个实例,即 QtCore.QModelIndex(),但这是默认值,所以最好完全删除它。 - Tim Wakeham
@Tim 即使我使用 QtCore.QModelIndex() 或将其全部删除... 我仍然会收到相同的错误... - Anuj Bhasin
@tim 谢谢你纠正我的拼写错误。 - Anuj Bhasin
5个回答

27

方法 model.removeRow(index.row()) 会移除所选行。

model = self.model
    indices = self.tableView.selectionModel().selectedRows() 
    for index in sorted(indices):
        model.removeRow(index.row()) 

在 indices 变量中,我们获取所选行,然后删除该行。

要删除表视图中的多个行:

index_list = []                                                          
for model_index in self.tableView.selectionModel().selectedRows():       
    index = QtCore.QPersistentModelIndex(model_index)         
    index_list.append(index)                                             

for index in index_list:                                      
     self.model.removeRow(index.row())                                                               

3

在C++中:

QModelIndexList indices = myTable->selectionModel()->selectedRows();

for (int i=indices.count()-1; i>=0; --i)
{
    QModelIndex index = indices.at(i);
    myTable->removeRow(index.row());
}

你必须从列表底部向上移动,否则你的索引将会混乱。


3

使用reversed()函数对我来说完全没问题。

        indices = self.tag_table.selectionModel().selectedRows()

        # Must delete in reverse order
        for each_row in reversed(sorted(indices)):
            self.tag_table.removeRow(each_row.row())

2
如果有人在实施 Anuj Bhasin 的答案后仍在寻找答案,因为上述解决方案在许多情况下都不会按预期工作。

原因:

  • 当您删除行索引(例如[0,1,2])并且您从0 -> 1 -> 2开始删除时,那么只有第0行和第2行将被删除!
  • 删除第一个项目将使剩余的行向上移动,使第1行第2行分别成为第0行第1行,因此当您下次删除第1行时,之前的第2行将被删除,因为它现在是第1行。

我有一个解决办法:

传递您要删除的行,例如从5行中删除[0,3]

def setSel(selected: List[int], table_widget: QTableWidget):
    """
    Select all rows for the given index range
    """
    table_widget.setSelectionMode(QAbstractItemView.MultiSelection)
    for i in selected:
        table_widget.selectRow(i)

然后使用QTableWidget作为参数调用remove_row_all_table()

def remove_row_all_table(table_widget):
    """
    Select and Delete rows from table widget
    """
    table_widget: QTableWidget
    selected_rows = table_widget.selectionModel().selectedRows()
    if selected_rows:
        row_indices = []
        for row_index in selected_rows:
            row_indices.append(row_index.row())
        row_indices.sort(key=lambda x: -1 * x)
        print(row_indices)
        for row in row_indices:  # sorted in descending order
            print(f"row count:{table_widget.rowCount()}, deleting index:{row}")
            table_widget.removeRow(row)
    print()

这个答案的总结是:您需要打开MultiSelection模式并按相反顺序删除,即从较高的索引到较低的索引,以避免我在答案开头提到的依赖关系发生。请注意保留HTML标记。

这个答案是针对qtablewidget的,它与qtableview不同。 - Inkenbrandt

0

我知道这是一个有点老的问题,但我认为这更加简洁并且能够解决问题。

def delete_record1(self, model, view):
    """Delete rows with currently selected cells and/or selected rows of the model"""
    rows = [model_index.row() for model_index in view.selectedIndexes()]
    
    rows.sort(reverse=True)

    for i in rows:
        model.removeRow(i)
    
    model.submitAll()
    model.select()    

有人可以建议一下这种方法的问题在哪里吗?


陷阱在于表格可以使用“ExtendedSelection”模式,允许在同一行中选择多个索引,甚至可以使用“SelectRows”行为,选择一行中的所有项目(包括隐藏列中的项目)。更简单的方法是检查行是否已经存在于列表中,但是在推导式中这样做会显得有些丑陋,所以使用集合是一个更好的选择:rows = sorted(set(index.row() for index in view.selectedIndexes()), reverse=True) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接