1

I am trying to create a context menu (QMenu) for a right-click inside of PatternWidget(QWidget) with PySide6. For this purpose I have overwritten contextMenuEvent as seen below.

For whatever reason, the context menu will NOT exit, when any of the actions in it or any space around it within PatternWidget is clicked, whether by left nor by right click.

The only way I can make the QMenu close is to click inside another widget or outside of the whole Application window.

I spent a long time on Google already and it seems that people usually have the opposite problem (keeping it open when clicking somewhere). I therefore think that something must be wrong in my code that prevents the default behavior to close the QMenu rather than me having to connect to some Signal and close it manually

I was also wondering if the Mouse Click event is not bubbling up until the QMenu but,the signals of the actions in the QMenu (Copy Row Up and Down) are firing as expected when clicked.

EDIT:

  • Removed QScrollArea
  • Added Code for PatternOverlay
class MainWindow(QMainWindow):
    
    ...
    
    def __init_layout(self):
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.layout.setSpacing(1)

        self.mainWidget = QWidget()
        self.mainWidget.setLayout(self.layout)

        self._scene = QtWidgets.QGraphicsScene(self)
        self._view = QtWidgets.QGraphicsView(self._scene)
        self._view.setStyleSheet("border: 0px; background-color: Gainsboro")

        self.pattern_widget = PatternWidget()
        self._scene.addWidget(self.pattern_widget)

        self.layout.addWidget(self._view)
        self.setCentralWidget(self.mainWidget)
class PatternOverlay(QWidget):
    def __init__(self, parent):
        super().__init__(parent=parent)
        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_TransparentForMouseEvents)
        self.rects = []

    def paintEvent(self, _):
        painter = QPainter(self)
        painter.setPen(QPen(Qt.blue, 2, Qt.SolidLine))
        for rect in self.rects:
            painter.drawRect(rect)
        painter.end()
        self.rects.clear()

    def addRect(self, rect):
        self.rects.append(rect)

class PatternWidget(QWidget):

    def __init__(self, cell_width, cell_height, stitches, rows):
        super().__init__()
        self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        self.setMouseTracking(True)
        # initialize overlay
        self.__overlay = PatternOverlay(self)
        self.__overlay.resize(self.size())
        self.__overlay.show()

    ...
    
    def contextMenuEvent(self, e):
        copy_row_up_action = QAction("Copy Row Up", self)
        copy_row_up_action.setStatusTip("Copy Row Up")
        copy_row_up_action.triggered.connect(self.__handle_copy_row_up)

        copy_row_down_action = QAction("Copy Row Down", self)
        copy_row_down_action.setStatusTip("Copy Row Down")
        copy_row_down_action.triggered.connect(self.__handle_copy_row_down)

        context = QMenu(self)
        context.addActions([copy_row_up_action, copy_row_down_action])
        context.exec_(e.globalPos())
badnun872
  • 77
  • 5
  • It might be related to the new way menus and actions are treated in Qt6. I'd start with creating the menu without the parent and see what happens. Also, QGraphicsView is already a scroll area, why are you adding it to another one? Besides that, we know nothing about `PatternOverlay`, and it might be related to it, so please provide a [mre]. Also, you should use [selectors](https://doc.qt.io/qt-5/stylesheet-syntax.html#selector-types) for stylesheets, especially for complex widgets like scroll areas. – musicamante Dec 19 '21 at 13:12
  • Thank you for your response and ideas. As you suggested I have removed the QScrollArea and also added the Code for PatternOverlay to the initial question. The issue with the QMenu still persists. For a test I have also moved the GraphicsScene and View into PatternWidget instead. Now PatternWidget will call addRectangle on GraphicsScene. This does indeed fix the QMenu. I am just not sure if thats good practice I will try to create a minimal reproducible example. As I am handicapped this might some more time – badnun872 Dec 19 '21 at 13:59
  • You mentioned lots of changes, but not the actual, important one I told you: did you try to create the menu *without* the parent? Also, your code is now *more* reproducible, but please consider for future reference to do more efforts, as I had to make lot of changes in order to actually run it, it's referencing missing functions, and, actually, many parts of the code are not really necessary to reproduce it: for instance, the issue can be reproduced without `PatternOverlay`, nor setting size policy or mouse tracking for `PatternWidget`, and the main window is missing the `__init__`. – musicamante Dec 19 '21 at 18:18
  • I know those might seem trivial things, but we should be able to focus on the problem, not be distracted by irrelevant code or being forced to recreate missing parts (which might also change the behavior and eventually not allow to properly reproduce the issue as we might assume things you didn't do, and vice versa). – musicamante Dec 19 '21 at 18:20
  • Thank you so much for your efforts. As you suggested, creating the Menu without a parent will solve the issue. I wonder why it does though? – badnun872 Dec 19 '21 at 19:33
  • The simple answer is that creating it without a parent (just like any widget) makes it an actual top level widget. For standard widgets, that would not change much for a QMenu, since it always has its own window, but for QGraphicsProxyWidgets this changes, as the menu becomes a QGraphicsProxyWidget too (since the parent is): in fact, when the menu is a child of a graphics widget, it will be created *inside* the scene, when it has no parent it's "outside" the window. That said, I believe it could be a bug, but I've not used Qt6 enough to dig more into it. – musicamante Dec 19 '21 at 19:38

0 Answers0