Skip to content

Qt.MouseButtons and Qt.Key potential unification for Qt5 vs Qt6 #489

@th3w1zard1

Description

@th3w1zard1

In PyQt5, it's common to use a Qt.Key like this:

    def _modifierKeyFix(self, e: QKeyEvent, parentFuncName: str):
        """Fix for when keys get stuck in the _keysDown set, call this sparingly."""
        current_modifiers = e.modifiers()

        for key in MODIFIER_KEYS:
            bitcheck = int(current_modifiers & key)  # Explicitly convert to int for clarity in logs
            if bitcheck == 0 and key in self._keysDown:
                RobustRootLogger().debug(f"Inferred Release ({parentFuncName}): {key} Key")
                self._keysDown.discard(key)

However that fails in PyQt6 even with qtpy, with the following error:

TypeError: unsupported operand type(s) for &: 'KeyboardModifier' and 'Key'

Another example, let's say I want to do similar with Qt.MouseButton:

    def _contextMenuRightMouseButtonFix(self, e: QMouseEvent, parentFuncName: str):
        """Fix for when the context menu causes focusloss events that cause the button to get stuck, call this sparingly."""
        current_buttons = e.buttons()
        # Ensure compatibility with both PyQt5 and PyQt6
        if not isinstance(current_buttons, int):
            current_buttons = int(current_buttons)
        rightbitcheck = int(current_buttons & Qt.RightButton)  # Explicitly convert to int for clarity in logs
        if rightbitcheck == 0 and Qt.RightButton in self._mouseDown:
            RobustRootLogger().debug(f"Inferred Release ({parentFuncName}): Right Button")
            self._mouseDown.discard(Qt.RightButton)

Raises this error:

"C:\GitHub\PyKotor\Tools\HolocronToolset\src\toolset\gui\widgets\renderer\walkmesh.py", line 886, in _contextMenuRightMouseButtonFix
    current_buttons = int(current_buttons)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'MouseButton'

This code works fine:

    def _contextMenuRightMouseButtonFix(self, e: QMouseEvent, parentFuncName: str):
        """Fix for when the context menu causes focusloss events that cause the button to get stuck, call this sparingly."""
        current_buttons = e.buttons()
        right_button_value = Qt.RightButton

        if isinstance(current_buttons, Qt.MouseButton):
            # PyQt6: current_buttons is a MouseButton enum, use .value to get the int representation
            rightbitcheck = current_buttons.value & right_button_value.value
        else:
            # PyQt5: current_buttons is already an int
            rightbitcheck = current_buttons & right_button_value
        if rightbitcheck == 0 and Qt.RightButton in self._mouseDown:
            RobustRootLogger().debug(f"Inferred Release ({parentFuncName}): Right Button")
            self._mouseDown.discard(Qt.RightButton)

An easy way to unify this, imo, is to check API_NAME in ("PyQt6", "PySide6") and if so just slap on the __int__ and __and__ like this in qtpy/QtCore.py:

# Mirror https://github.com/spyder-ide/qtpy/pull/393
if PYQT5 or PYSIDE2:
    QLibraryInfo.path = QLibraryInfo.location
    QLibraryInfo.LibraryPath = QLibraryInfo.LibraryLocation
if PYQT6 or PYSIDE6:
    QLibraryInfo.location = QLibraryInfo.path
    QLibraryInfo.LibraryLocation = QLibraryInfo.LibraryPath
    QtCore.Qt.MouseButton.__int__ = lambda self: self.value
    QtCore.Qt.MouseButton.__and__= lambda self, other: self.value & other
    QtCore.Qt.Key.__int__ = lambda self: self.value
    QtCore.Qt.Key.__and__= lambda self, other: self.value & other

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions