编辑QTableView时捕获ESC键

时间:2018-11-07 16:22:45

标签: python python-3.x pyqt pyqt5

尝试弄清楚如何在正在编辑的QTableView中捕获行的麻烦已被取消。例如,如果我正在QTableView中编辑新插入的行并按ESC,则已按向上/向下箭头键,则需要删除该行,因为(在我看来)已被取消。如果用户单击该行,也适用。我真的不能发布任何代码,因为我不知道如何实现这样的东西。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

我有一个我想要的例子(至少对于按键问题而言)。从那里,您可以为点击问题执行类似的操作。

我的解决方案使用覆盖QItemDelegate方法的自定义eventFilter。此外,它使用的是天真的模型(因为您想使用QTableView),模型上使用layoutChanged信号是由于示例的功能所致,请根据需要阅读文档以获取更合适的添加/删除数据功能需求。

希望有帮助。

示例ui:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'test.ui',
# licensing of 'test.ui' applies.
#
# Created: Wed Nov  7 16:10:12 2018
#      by: pyside2-uic  running on PySide2 5.11.0
#
# WARNING! All changes made in this file will be lost!

from PySide2 import QtCore, QtGui, QtWidgets

class Ui_Test(object):
    def setupUi(self, Test):
        Test.setObjectName("Test")
        Test.resize(538, 234)
        self.horizontalLayout = QtWidgets.QHBoxLayout(Test)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.tableView = QtWidgets.QTableView(Test)
        self.tableView.setObjectName("tableView")
        self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1)
        self.addRow = QtWidgets.QPushButton(Test)
        self.addRow.setObjectName("addRow")
        self.gridLayout.addWidget(self.addRow, 0, 1, 1, 1)
        self.horizontalLayout.addLayout(self.gridLayout)

        self.retranslateUi(Test)
        QtCore.QMetaObject.connectSlotsByName(Test)

    def retranslateUi(self, Test):
        Test.setWindowTitle(QtWidgets.QApplication.translate("Test", "Dialog", None, -1))
        self.addRow.setText(QtWidgets.QApplication.translate("Test", "add row", None, -1))

涉及的实际类(我使用PySide2):

from PySide2 import QtWidgets, QtCore, QtGui
from _test import Ui_Test


class MyDialog(QtWidgets.QDialog):
    def __init__(self, parent = None):
        super(MyDialog, self).__init__(parent = parent)
        self.ui = Ui_Test()
        self.ui.setupUi(self)
        self._model = MyModel([["first row 1 col", "first row 2"],["second row 1", "second row 2"]])
        self.ui.tableView.setModel(self._model)
        self.ui.addRow.clicked.connect(self._model.addRow)
        self.ui.tableView.setItemDelegate(MyDelegate(self.ui.tableView))
        # this is crucial: we need to be sure that the selection is single on the view
        self.ui.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)
        self.ui.tableView.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)


class MyModel(QtCore.QAbstractTableModel):
    def __init__(self, table_data = None, parent = None):
        super(MyModel, self).__init__(parent = parent)
        if not table_data: self._data = []
        self._data = table_data

    def rowCount(self, parent = None):
        return len(self._data)

    def columnCount(self, parent = None):
        return 2

    def addRow(self):
        self._data.append(["new item", "new item"])
        self.layoutChanged.emit()

    def removeRow(self, row):
        if 0 <= row < self.rowCount(): 
            del self._data[row]
            self.layoutChanged.emit()

    def data(self, index, role = QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole:
                row = index.row()
                col = index.column()
                return self._data[row][col]

    def setData(self, index, value, role = QtCore.Qt.EditRole):
        if index.isValid():
            if role == QtCore.Qt.EditRole:
                row = index.row()
                col = index.column()
                self._data[row][col] = str(value)
                return True
            else:
                return False
        else:
            return False

    def flags(self, index):
        return QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEditable|QtCore.Qt.ItemIsEnabled


class MyDelegate(QtWidgets.QItemDelegate):
    def __init__(self, parent = None):
        super(MyDelegate, self).__init__(parent)
        self.view = parent

    def eventFilter(self, editor, event):
        # there is a lot of checking in order to identify the desired situation
        # and avoid errors
        if isinstance(event, QtGui.QKeyEvent):
            if event.type() == QtCore.QEvent.KeyPress:
                if event.key() == QtCore.Qt.Key_Escape:
                    # we should have a list here of length one (due to selection restrictions on the view)
                    index = self.view.selectedIndexes()
                    if index:
                        if index[0].isValid():
                            row = index[0].row()
                            self.view.model().removeRow(row)


        return super(MyDelegate, self).eventFilter(editor, event)

if __name__ == '__main__':
    app = QtWidgets.QApplication()
    diag = MyDialog()
    diag.show()
    app.exec_()