PyQt5 快捷方式并非一直有效

问题描述:

所以我用 PyQt5 构建了一个 GUI,并为我的子菜单栏制作了一个快捷方式,如下所示:

So I build a GUI with PyQt5 and made a Shortcut für my Sub-Menubar like this:

        ''' Menubar '''
        mainMenu = self.menuBar()

        ''' Sub-Menubar '''
        fileMenu = mainMenu.addMenu('Options')
        Pathfinder = QAction('Choose Folder', self)
        Pathfinder.setShortcut("Shift+L")
        Pathfinder.triggered.connect(lambda: self.clicked_menu(0))
        fileMenu.addAction(Pathfinder)

按 Shift + L 可以正常工作...只要我的鼠标光标在元素中未处于活动状态.例如,如果我更改了一个 spinBoxes 中的值并且光标(=caret)闪烁"在 spinBox 内部,Shift+L 什么也不做.

Pressing Shift + L works fine... as long as my mouse cursor is not active in an element. For instance if I change the value in one of my spinBoxes and the cursor (=caret) is "blinking" inside the spinBox, Shift+L does nothing.

        self.spinBoxMaxHolesPerCycle = QSpinBox(self)
        self.spinBoxMaxHolesPerCycle.setGeometry(485, 310, 45, 20)
        self.spinBoxMaxHolesPerCycle.setMaximum(200)
        self.spinBoxMaxHolesPerCycle.setValue(100)
        self.spinBoxMaxHolesPerCycle.valueChanged.connect(lambda: self.changedValue(11))

有没有办法解决这个问题,而无需点击其他地方来解除连接"?光标?

Is there a way to work around this issue without clicking somewhere else to "deattache" the cursor?

您面临的行为与鼠标光标无关,而是由于键盘焦点(您不过,可以通过单击将焦点设置到小部件上).

The behavior you're facing is not related to the mouse cursor, but is due to the keyboard focus (you can set the focus to a widget by clicking on it, though).

问题在于 QSpinBox 小部件包含用于使用键盘编辑值的 QLineEdit,并且由于您的快捷方式可以被解释为文本(大写的L"字母),小部件自动吃"键盘事件,防止其传播到父级.

The problem is that QSpinBox widgets contain a QLineEdit that is used to edit the value using the keyboard, and since your shortcut could be interpreted as text (the upper case "L" letter), the widget automatically "eats" the keyboard event, preventing it to be propagated to the parent.

如果你只关心一个小部件,你可以子类化它并覆盖它的keyPressEvent,如果它与快捷方式不匹配,只需调用基本实现.

If you only care about a single widget, you could subclass it and override its keyPressEvent, and if it does not match the shortcut, just call the base implementation.

由于您可能希望将行为应用于多个小部件,因此解决方案是在 QApplication 上安装事件过滤器并检查按键事件:如果事件与您的快捷方式匹配,则触发操作并返回 True.

Since you may want to apply the behavior to more than one widget, a solution would be to install an event filter on the QApplication and check for key press events: if the event matches your shortcut, just trigger the action and return True.

        # ...
        # make the action an attribute, so that it can be accessed from elsewhere
        self.pathfinderAction = QtWidgets.QAction('Choose Folder', self)
        # ...
        QtWidgets.QApplication.instance().installEventFilter(self)

    def eventFilter(self, source, event):
        if (isinstance(source, QtWidgets.QWidget) and 
            event.type() == QtCore.QEvent.KeyPress):
                sequence = QtGui.QKeySequence(int(event.modifiers()) + event.key())
                if sequence == self.pathfinderAction.shortcut():
                    # the event matches the shortcut
                    self.pathfinderAction.trigger()
                    return True
        return super().eventFilter(source, event)