检测并处理Escape键编辑QTableView cell

问题描述 投票:0回答:1

我的应用程序有一个子类 QTableWidget。在使用中,我丢失了一些编辑 通过按 Escape 键(vim 习惯),所以我试图拦截 Esc键询问是否放弃编辑

我还使用 control-enter 关闭并保存编辑过的单元格。

我有下面的代码作为概念证明。它几乎可以工作。逃亡 按我的意愿检测和处理密钥。

但是,我做错了什么。保存修改后的单元格后 使用 control-enter 或使用 Escape 放弃它,我无法再突出显示 单击鼠标的单元格。相反,会出现一个光标,就好像该单元格仍在编辑中一样。

任何解决此问题的建议都将不胜感激,谢谢。

#!/usr/bin/env python3

from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QMessageBox,
    QPlainTextEdit,
    QStyledItemDelegate,
    QStyleOptionViewItem,
    QTableWidget,
    QTableWidgetItem,
)


class EscapeLineEdit(QPlainTextEdit):
    """
    Subclass QPlainTextEdit to detect Escape key.
    """

    def __init__(self, parent, delegate):
        super().__init__(parent)
        self.delegate = delegate

    def keyPressEvent(self, event):
        if event.key() == Qt.Key.Key_Escape:
            discard_edits = QMessageBox.question(
                self.parent(), "Abandon edit", "Discard changes?")
            if discard_edits == QMessageBox.StandardButton.Yes:
                self.close()
        elif event.key() == Qt.Key.Key_Return:
            if event.modifiers() == Qt.KeyboardModifier.ControlModifier:
                self.delegate.commitData.emit(self)
                self.delegate.closeEditor.emit(self)
                self.close()
        super().keyPressEvent(event)


class EscapeDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)

    def createEditor(self, parent, option, index):
        return EscapeLineEdit(parent, self)


class MyTableWidget(QTableWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setItemDelegate(EscapeDelegate())
        self.cellDoubleClicked.connect(self.editCell)

    def editCell(self, row, col):
        """
        Explicitly set the cell editor to enable
        detection of the Escape key
        """

        delegate = self.itemDelegate()
        index = self.model().index(row, col)
        editor = delegate.createEditor(self.viewport(), QStyleOptionViewItem(), index)
        delegate.setEditorData(editor, index)
        self.setCellWidget(row, col, editor)


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.table_widget = MyTableWidget(self)
        self.table_widget.setRowCount(2)
        self.table_widget.setColumnCount(2)
        for row in range(2):
            for col in range(2):
                item = QTableWidgetItem()
                item.setText(f"Row {row}, Col {col}")
                self.table_widget.setItem(row, col, item)
        self.setCentralWidget(self.table_widget)

        self.table_widget.resizeColumnsToContents()
        self.table_widget.resizeRowsToContents()


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()
pyqt pyqt6
1个回答
0
投票

啊,Stackoverflow Rubber Duck 又能用了……以防其他人正在搜索类似的东西,这就是我修复它的方法(而且要简单得多):

#!/usr/bin/env python3

from PyQt6.QtCore import Qt, QEvent, QObject
from PyQt6.QtWidgets import (
    QAbstractItemDelegate,
    QAbstractItemView,
    QApplication,
    QMainWindow,
    QMessageBox,
    QPlainTextEdit,
    QStyledItemDelegate,
    QStyleOptionViewItem,
    QTableWidget,
    QTableWidgetItem,
)

from PyQt6.QtGui import QKeyEvent

from typing import cast


class EscapeDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)

    def createEditor(self, parent, option, index):
        return QPlainTextEdit(parent)

    def eventFilter(self, editor: QObject, event: QEvent):
        """By default, QPlainTextEdit doesn't handle enter or return"""

        print("EscapeDelegate event handler")
        if event.type() == QEvent.Type.KeyPress:
            key_event = cast(QKeyEvent, event)
            if key_event.key() == Qt.Key.Key_Return:
                if key_event.modifiers() == (
                    Qt.KeyboardModifier.ControlModifier
                ):
                    print("save data")
                    self.commitData.emit(editor)
                    self.closeEditor.emit(editor)
                    return True
            elif key_event.key() == Qt.Key.Key_Escape:
                discard_edits = QMessageBox.question(
                    self.parent(), "Abandon edit", "Discard changes?")
                if discard_edits == QMessageBox.StandardButton.Yes:
                    print("abandon edit")
                    self.closeEditor.emit(editor)
                    return True
        return False


class MyTableWidget(QTableWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setItemDelegate(EscapeDelegate(self))
        self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked)


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.table_widget = MyTableWidget(self)
        self.table_widget.setRowCount(2)
        self.table_widget.setColumnCount(2)
        for row in range(2):
            for col in range(2):
                item = QTableWidgetItem()
                item.setText(f"Row {row}, Col {col}")
                self.table_widget.setItem(row, col, item)
        self.setCentralWidget(self.table_widget)

        self.table_widget.resizeColumnsToContents()
        self.table_widget.resizeRowsToContents()


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()
© www.soinside.com 2019 - 2024. All rights reserved.