Home > Enterprise >  How to properly catch and filter all keyboard events in a QTableWidget?
How to properly catch and filter all keyboard events in a QTableWidget?

Time:04-07

I'd like to filter the characters entered in the cells of a QWidgetTable to only accept hexadecimal characters (ie filter ascii character that doesn't represent an hex value).

I tried different options and still doesn't manage to do that.

One of the option is to implement my own widget superclassing the QWidgetTable with my own keyPressEvent like this:

class MyQTableWidget(QTableWidget):

    def keyPressEvent(self, event):
        print("Item - Key pressed", event.key())
        super().keyPressEvent(event)
        #event.accept()

In this case, only the first character typed and the final "enter" key is captured by the event handler ... How to capture all characters I enter in the cell ?

I understand that the editor associated with the widget may be the one that catch all intermediate key events, so I tried to use an QItemDelegate with an eventFilfer(). In this case, I'm able to capture all key events, however this breaks the default behavior of the widget ...

So how to proceed ?

Thanks

CodePudding user response:

You cannot do this by handling key events on the view. The reason for which you're only getting the first key is that the view decides what to do depending on the pressed key: for instance, if you're pressing a navigation key (arrows, tab, page, etc), then it will change the current item.

If the editTriggers() includes AnyKeyPressed (and the current item is editable), then it enters in edit mode, creates an editor for that index, and sends that key event to the editor.

Handling events in the delegate event filter is also discouraged, as you might filter out events that shouldn't be filtered, or you might accept invalid input when using the clipboard. In your case, Ctrl V wouldn't be accessible if you're not careful, but if it would you may paste content that doesn't match the hex syntax.

The proper solution is to install a QValidator on the editor, and in this case you can use a simple QRegExpValidator.

class HexDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, parent, opt, index):
        editor = super().createEditor(parent, opt, index)
        if isinstance(editor, QtWidgets.QLineEdit):
            regexp = QtCore.QRegExp('[A-Fa-f0-9] ')
            validator = QtGui.QRegExpValidator(regexp)
            editor.setValidator(validator)
        return editor

app = QtWidgets.QApplication([])
table = QtWidgets.QTableWidget(10, 10)
table.setItemDelegate(HexDelegate(table))
table.show()
app.exec()

Note that with the regexp above, the means that at least one character must be entered in order to accept the input: if the field is empty and you press enter, the editor will not submit the value. If you want to accept empty values, use [A-Fa-f0-9]*.

If you need a specific amount of characters, use the {} syntax:

  • to accept exactly 2 characters: [A-Fa-f0-9]{2};
  • to accept at least 2 characters: [A-Fa-f0-9]{2,};
  • to accept at least 2 characters, but not more than 5: [A-Fa-f0-9]{2,5};

Alternatively, when the input has a defined maximum length, you can use the line edit inputMask:

class HexDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, parent, opt, index):
        editor = super().createEditor(parent, opt, index)
        if isinstance(editor, QtWidgets.QLineEdit):
            editor.setInputMask('HHHHH;_')
        return editor

The above will require exactly 5 hexadecimal characters, but you can also require at least 2 characters (but no more than 5), using HHhhh;_. Note that the input mask cannot accept undefined number of characters, so in that case you should choose the validator solution above.

  • Related