2

In a PyQt5 application I have a QMenu. I want to make it so that once the menu is open, users can use keys 1, 2, 3, etc to select option 1, 2, 3, etc in the menu. However, I'm having trouble setting the shortcut, or getting the shortcut to react to the keypress.

I've taken an example from this website, and adapted it slightly to show my issue. I tried assigning shortcuts in the addAction function, but this does not work.

I've tried creating regular QShortcuts, but those no longer respond when the menu is open. I noticed that I can change the selected option using arrow up and down, and then confirm my selection with the enter key, so the QMenu is able to catch keypresses. But how can I assign my own shortcuts?

from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu
import sys


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = "PyQt5 Context Menu"
        self.top = 200
        self.left = 500
        self.width = 400
        self.height = 300
        self.InitWindow()


    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("icon.png"))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.show()

    def contextMenuEvent(self, event):
        contextMenu = QMenu(self)
        newAct = contextMenu.addAction("New", self.triggered, shortcut='A')
        openAct = contextMenu.addAction("Open", self.triggered2, shortcut='B')
        quitAct = contextMenu.addAction("Quit", self.triggered3, shortcut='C')
        action = contextMenu.exec_(self.mapToGlobal(event.pos()))
        if action == quitAct:
            self.close()

    def triggered(self):
        print("triggered 1")

    def triggered2(self):
        print("triggered 2")

    def triggered3(self):
        print("triggered 3")
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

duocorn
  • 43
  • 1
  • 8
  • There is something weird with ` shortcut='A'` : it doesn't display the shortcut in the context menu (when I think it should since Qt5.15, `showShortcutsInContextMenus is True` or can be changed with `App.styleHints().setShowShortcutsInContextMenus(True)`. – Demi-Lune Sep 16 '20 at 10:09
  • Using `newAct.setShortcuts(["1"])` *does indeed* display the shortcut ... but isn't enough to make it work. – Demi-Lune Sep 16 '20 at 10:10

2 Answers2

2

When a QMenu is opened, shortcuts are not active, but accelerator keys are working. You declare them with &:

    newAct = contextMenu.addAction("New &1", self.triggered)

When the context menu pops up, pressing 1 triggers the correct function.

Demi-Lune
  • 1,868
  • 2
  • 15
  • 26
1

The QKeySequence class encapsulates a key sequence as used by shortcuts. More... https://doc.qt.io/qt-5/qkeysequence.html

Try it:

import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = "PyQt5 Context Menu"
        self.top = 200
        self.left = 500
        self.width = 400
        self.height = 300
        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("icon.png"))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.show()

    def contextMenuEvent(self, event):
        contextMenu = QMenu(self)
#        newAct = contextMenu.addAction("New", self.triggered, shortcut='A')
        newAct = contextMenu.addAction(
            "New (&A)", self.triggered, shortcut=QtGui.QKeySequence.New)            # +++
        openAct = contextMenu.addAction(
            "Open (&B)", self.triggered2, shortcut=QtGui.QKeySequence.Open)         # +++
        quitAct = contextMenu.addAction(
            "Quit (&C)", self.triggered3, shortcut=QtGui.QKeySequence.Quit)         # +++
        action = contextMenu.exec_(self.mapToGlobal(event.pos()))
        if action == quitAct:
            self.close()

    def triggered(self):
        print("triggered 1")

    def triggered2(self):
        print("triggered 2")

    def triggered3(self):
        print("triggered 3")
        
        
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

enter image description here

S. Nick
  • 12,879
  • 8
  • 25
  • 33
  • This works, thanks. Ideally I would've triggered the function with just a single button press, now you have to press A, and then enter, but this works. – duocorn Nov 12 '20 at 15:46