【问题标题】:How can I set Custom Key board Key press event in Qtablewidget Python?如何在 Qtablewidget Python 中设置自定义键盘按键事件?
【发布时间】:2020-07-12 06:12:06
【问题描述】:

我有一个由 QTDesigner 生成的 QTableWidget,我想在其中设置一些自定义按键事件。

  1. 当当前单元格处于编辑模式时,如果用户按下 Tab 键,它会移动到处于编辑模式的下一个单元格,但我只是希望它移动到选中的下一个单元格,而不是处于编辑模式。

    李>
  2. 当当前单元格处于编辑模式时,如果用户按左、右、上、下键 - 它应该再次移动到处于选择模式的相应单元格,而不是处于编辑模式。

如果当前单元格刚刚被选中而不处于编辑模式,这两种方法现在都可以正常工作。但是我该如何设置这个自定义事件?

谢谢!!

UI 设计师生成的代码:

from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(428, 285)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(20, 20, 391, 231))
        self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.AnyKeyPressed|QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed|QtWidgets.QAbstractItemView.SelectedClicked)
        self.tableWidget.setRowCount(5)
        self.tableWidget.setColumnCount(3)
        self.tableWidget.setObjectName("tableWidget")
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        self.tableWidget.horizontalHeader().setVisible(True)
        self.tableWidget.verticalHeader().setVisible(False)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "Name"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "Age"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "City"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

我的脚本:

from PyQt5 import QtWidgets, QtCore
from demo import Ui_MainWindow

class DemoTable(QtWidgets.QMainWindow, Ui_MainWindow):                 
    def __init__(self):
        super(DemoTable, self).__init__()
        self.setupUi(self) 

        #KeyPressEvent
        self.tableWidget.keyPressEvent = self.KeyPressed

    def KeyPressed(self,event):
        if event.key() == QtCore.Qt.Key_Left:
            print('Left Key Pressed')
        elif event.key() == QtCore.Qt.Key_Right:
            print('Right Key Pressed')
        elif event.key() == QtCore.Qt.Key_Tab:
            print('Tab Key Pressed')
        return QtWidgets.QTableWidget.keyPressEvent(self.tableWidget, event)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    demowindow = DemoTable()   
    demowindow.show()
    sys.exit(app.exec_())

【问题讨论】:

  • 第二点,我测试观察到:如果当前项处于选择模式,我按向上或向下键,分别选择顶部或底部项,不启用编辑,但在按左或右键的情况下没有任何反应。据我了解,您希望上下键的行为与左右键相同,对吗?
  • 我想知道在单元格处于左右键编辑模式时上下键的工作方式。

标签: python python-3.x pyqt pyqt5 qtablewidget


【解决方案1】:

您可以重新实现closeEditor() 方法,该方法负责在项目编辑完成后项目视图将采取的操作。

在此示例中,我将像您对按键事件所做的那样覆盖该方法,但我强烈建议您使用子类并在其中实现覆盖,因为代码会更简洁,并且可以避免现有函数和/或覆盖的方法。

class DemoTable(QtWidgets.QMainWindow, Ui_MainWindow):                 
    def __init__(self):
        super(DemoTable, self).__init__()
        self.setupUi(self) 

        #KeyPressEvent
        self.tableWidget.keyPressEvent = self.KeyPressed
        self.tableWidget.closeEditor = self.closeEditor

    def closeEditor(self, editor, hint):
        if hint in (QtWidgets.QItemDelegate.EditNextItem, 
            QtWidgets.QItemDelegate.EditPreviousItem):
                # if the hint is to edit the next or previous item, ignore it
                newHint = QtWidgets.QItemDelegate.NoHint
        else:
            newHint = hint

        # call the base implementation with the new hint
        QtWidgets.QTableWidget.closeEditor(self.tableWidget, editor, newHint)

        if hint == QtWidgets.QItemDelegate.EditNextItem:
            # find the next item to focus on
            index = self.tableWidget.moveCursor(self.tableWidget.MoveNext, 
                QtCore.Qt.NoModifier)
        elif hint  == QtWidgets.QItemDelegate.EditPreviousItem:
            # find the previous item to focus on
            index = self.tableWidget.moveCursor(self.tableWidget.MovePrevious, 
                QtCore.Qt.NoModifier)
        else:
            return
        # set the new current item
        self.tableWidget.setCurrentIndex(index)

    # ...

由于您还想使用箭头键移动到项目即使在编辑状态,您只能通过安装一个自定义项目委托来检查编辑器中的键盘事件。

不过,我必须警告你:不要这样做
在编辑文本时,左右箭头键始终用于光标导航,绝对不鼓励更改此行为。
这是不直观的、不自然的、不舒服的,违背任何常见的和预期的行为,并且会让习惯于键盘导航的用户非常、非常非常恼火。我过去曾在某个程序中看到过类似的行为,我可以告诉你,这不好而且非常烦人。

class DelegateYouShouldNotUse(QtWidgets.QStyledItemDelegate):
    def eventFilter(self, source, event):
        if isinstance(source, QtWidgets.QLineEdit) and event.type() == QtCore.QEvent.KeyPress:
            if event.key() == QtCore.Qt.Key_Right:
                # tell the view to store the current data
                self.commitData.emit(source)
                # and to move to the next item (since we've changed the
                # behavior of the closeEditor *slot* of the table, it
                # will only move to the item, without starting editing
                self.closeEditor.emit(source, self.EditNextItem)
                return True
            elif event.key() == QtCore.Qt.Key_Left:
                self.commitData.emit(source)
                self.closeEditor.emit(source, self.EditPreviousItem)
                return True
        return super().eventFilter(source, event)


class DemoTable(QtWidgets.QMainWindow, Ui_MainWindow):                 
    def __init__(self):
        super(DemoTable, self).__init__()
        # ...
        self.veryBadDelegate = DelegateYouShouldNotUse(self.tableWidget)
        self.tableWidget.setItemDelegate(self.veryBadDelegate)

如果还不够清楚,你应该不要使用这个:-)

【讨论】:

  • 谢谢! @musicamante。这在您按 Tab 键时有效。它将移动到下一个选定的单元格。但它似乎不适用于 let 和 right 键。
  • @PyPyVk 你是什么意思?您想在编辑模式下按箭头移动到单元格吗?我真的不会那样做,因为这会违背可编辑文本小部件的预期行为(左右箭头键应始终移动文本光标)。如果你真的想这样做,你需要创建一个自定义委托并在请求创建时在编辑器上安装一个事件过滤器,但我强烈建议你不要这样做,它会使文本编辑行为不直观,并且很多
  • 是的,我完全理解你在这里想要表达的意思。但至少对于这个特殊要求,如果可能的话,我需要这样做吗?
  • @PyPyVk 查看更新。但是,说真的,不要这样做:-)
猜你喜欢
  • 2015-11-10
  • 2019-02-12
  • 1970-01-01
  • 2013-08-15
  • 2016-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多