How can I set Custom Key board Key press event in Qtablewidget Python?

試著忘記壹切 提交于 2020-11-29 19:15:22

问题


I have a QTableWidget generated by QTDesigner in which I want to set some custom key press events.

  1. when current cell is in edit mode and if user presses Tab key, it moves to next cell in edit mode but i just want it move to next cell selected and not in edit mode.

  2. when current cell is in edit mode and if user presses Left, right, up, down- it should move to corresponding cell in select mode again and not in edit mode.

both of this works well right now if current cell is just selected and not in edit mode. but how can i set this customized event?

Thanks!!

Code Generated by UI Designer:

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_())

My Script:

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_())

回答1:


You can reimplement the closeEditor() method, which is responsible of the action that the item view will take when an item editing has been completed.

In this example I'll overwrite the method as you did with the keypress event, but I strongly suggest you to use subclasses and implement the overrides in them, as the code would be cleaner and can avoid confusion between existing functions and/or overwritten methods.

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)

    # ...

Since you also want to move to the items using the arrow keys even while in editing state, you can only do this by installing a custom item delegate that checks for keyboard events in the editor.

I have to warn you, though: don't do this.
Left and right arrow keys are always used for cursor navigation when editing text, changing this behavior is absolutely discouraged.
It's unintuitive, unnatural, uncomfortable, against any common and expected behavior, and will make users accustomed to keyboard navigation very, very, very annoyed. I've seen a similar behavior in a program in the past, and I can tell you that it's not good and it's very irritating.

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)

In case it wasn't clear enough, you should not use this :-)



来源:https://stackoverflow.com/questions/60954886/how-can-i-set-custom-key-board-key-press-event-in-qtablewidget-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!