Search code examples
python-3.xuser-interfacepyside2

Why does Tab key doesn't trigger KeyPressEvent in main widget after setting adn then clearing focus on QGraphicsTextItem in PySide2


In the following code snippet, there is a strange behaviour I can't manage to understand. After I double click on the QGraphicsTextItem, the Tab key (and not any other key as far as I'm aware) is not triggering anymore the KeyPressEvent. It seems to come from the way PySide2 handle the focus in this case, and my blind guess is that it's linked to the fact that one of the QtCore.Qt.FocusReason is linked to the tab key (TabFocusReason).

import sys
from PySide2 import QtWidgets, QtCore, QtGui

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        # Create a QGraphicsScene
        self.scene = QtWidgets.QGraphicsScene()
        
        # Create QGraphicsTextItem
        text_item = QtWidgets.QGraphicsTextItem("Example")
        text_item.setDefaultTextColor(QtCore.Qt.blue)  # Optionally set text color
        self.scene.addItem(text_item)
         
        # Create QGraphicsView
        self.view = QtWidgets.QGraphicsView(self.scene)
        self.setCentralWidget(self.view)

        # Store the text item for later use
        self.text_item = text_item

    def keyPressEvent(self, event):
        """For debugging purposes. If a key triggers the event, it prints its enum value."""
        print(event.key())
        super().keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        # get the item we are clicking on
        scene_pos = self.view.mapToScene(event.pos())
        item = self.scene.itemAt(scene_pos, QtGui.QTransform())

        if isinstance(item, QtWidgets.QGraphicsTextItem):
            # minimalistically reproduces the bug
            item.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
            item.setFocus(QtCore.Qt.MouseFocusReason)
        
            item.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
            item.clearFocus()
        
            # Set the plain text to show the double click event worked
            item.setPlainText("changed")

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Solution

  • Seems a bug, but finding the real culprit may be quite difficult, especially considering the complexity of both graphics scene events and the QGraphicsTextItem implementation (which uses an internal "text control" that manages events on its own).

    A possible workaround could be to create a dummy item, make it focusable, focus it, and then remove it:

                ...
                item.setTextInteractionFlags(Qt.NoTextInteraction)
                item.setPlainText("changed")
    
                dummy = QGraphicsRectItem()
                dummy.setFlag(dummy.ItemIsFocusable)
                self.scene.addItem(dummy)
                dummy.setFocus()
                self.scene.removeItem(dummy)
    

    You should consider filing a report on https://bugreports.qt.io.