Genaro.exe
Genaro.exe

Reputation: 38

How to add a context menu to a context menu in PyQt5?

I am building a GUI in python with PyQt5 and I need that when I right-click on an option in my context menu, it displays another context menu as in the image...

a program that has a widget with a contextual menu inside another contextual menu

(I am aware that I can nest a menu in one of the options, but that is not what I am looking for)

The context menu does not distinguish between right-click and left-click.

There are two problems that I see to achive this...

  1. I do not know how to prevent the right-click from triggering the PyQt5.QtWidgets.QAction.
  2. The second problem is that normally one of the steps involved in creating a context menu is to use the .installEventFilter() method on a widget, but in this case, you should use it on an object of type PyQt5.QtWidgets.QAction

I know that what I am asking is something complex to achieve, but I would greatly appreciate it if you could give me some information to help me achieve it.

Here I leave you the code of a GUI with a widget with a contextual menu installed on it...

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu
import sys
from PyQt5.QtCore import QEvent


class MyWindow(QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.createWidgets()

    def createWidgets(self):
        self.my_button = QtWidgets.QPushButton(self)
        self.my_button.setText("My Widget")
        self.my_button.installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == QEvent.ContextMenu and source is self.my_button:
            menu = QMenu()

            action1 = menu.addAction("Option 1")
            action2 = menu.addAction("Option 2")
            action3 = menu.addAction("Option 3")

            selected_action = menu.exec_(event.globalPos())

            if selected_action == action1:
                print("You have selected the first option")
            if selected_action == action2:
                print("You have selected the second option")
            if selected_action == action3:
                print("You have selected the third option")

        return super().eventFilter(source, event)




def showWindow():
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

showWindow()

Upvotes: 1

Views: 3414

Answers (1)

musicamante
musicamante

Reputation: 48479

It is not enough to install the event filter on the button, and you certainly cannot install it on the QAction, which will never trigger mouse events since it does not inherit from QWidget. You have to install the filter on the menu itself.

In order to allow correct tracking of menus (and properly react to their events), it's also better to keep more static references to the menus too.

Obviuosly, you could create a subclass of QMenu, which will probably make things easier.

class MyWindow(QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.createWidgets()

    def createWidgets(self):
        self.my_button = QtWidgets.QPushButton(self)
        self.my_button.setText("My Widget")

        self.buttonMenu = QMenu(self.my_button)
        self.buttonMenu.addAction("Option 1")
        self.buttonMenu.addAction("Option 2")
        self.buttonMenu.addAction("Option 3")

        self.subMenu = QMenu(self.buttonMenu)
        self.subMenu.addAction("Sub Option 1")
        self.subMenu.addAction("Sub Option 2")
        self.subMenu.addAction("Sub Option 3")

        self.my_button.installEventFilter(self)
        self.buttonMenu.installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == QEvent.ContextMenu:
            if source == self.my_button:
                self.buttonMenu.exec_(event.globalPos())
                return True
            elif source == self.buttonMenu:
                self.subMenu.exec_(event.globalPos())
                return True

        return super().eventFilter(source, event)

Upvotes: 3

Related Questions