Kristijan
Kristijan

Reputation: 195

Issue displaying QMenu in PyQt5

I am trying to display a QMenu when a row is right clicked on a QTableWidget. The issue is that whenever the menu appears, It appears as a dot. Below you can find a minimal reproducible example.

import sys

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import (QApplication, QAction, QMenu, QTableWidget,
                             QAbstractItemView)


class PhotoSetTable(QTableWidget):
    _menu = None

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setRowCount(0)
        self.setColumnCount(2)
        self.setHorizontalHeaderLabels(["Name", "Count"])
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self._menu = self._generate_menu()
        row_position = self.rowCount()
        self.insertRow(row_position)
        name_item = QtWidgets.QTableWidgetItem("asd")
        name_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
        count_item = QtWidgets.QTableWidgetItem("0")
        count_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
        self.setItem(row_position, 0, name_item)
        self.setItem(row_position, 1, count_item)


        #self._refresh()

    @staticmethod
    def _generate_menu():
        menu = QMenu()
        menu.addAction(QAction("Quit"))
        menu.addSeparator()
        menu.addAction(QAction("WUUU"))
        menu.addSeparator()

        return menu

    def mousePressEvent(self, e):
        super().mousePressEvent(e)
        if e.buttons() == QtCore.Qt.RightButton:
            item = self.itemAt(e.pos())

            if item is not None:
                self._menu.exec(e.globalPos())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = PhotoSetTable()
    ex.show()
    sys.exit(app.exec_())

What is causing this behavior?

Upvotes: 1

Views: 2167

Answers (2)

musicamante
musicamante

Reputation: 48479

The reason for which you only see a "point" is that you are actually seeing an empty menu, since you are creating QActions without parents.
QMenu.addAction(QAction*) does not transfer ownership of the QAction to the menu (it behaves as QWidget.addAction, as explained here, since QMenu is a QWidget descendent), which means that once the _generate_menu() method returns, those action are "transferred" to Python's garbage collector (aka, deleted).

If, for any reason, you really need to create "standalone" QActions, add a parent to them (or make them a property of some persisent object, even by adding to another persistent object, like a list or a tuple), or just use menu.addAction(str) as pointed out by MalloyDelacroix.
By the way, if you just set the menu as a parent, that will be enough:

    menu.addAction(QAction("Quit", menu))

That said, at least according to your example, there's really no need to use a static method for this.

Upvotes: 2

MalloyDelacroix
MalloyDelacroix

Reputation: 2293

The problem is in adding QAction to the generated context menu. Instead, try adding the menu items with the item name as a string as the first parameter, and the method it should call as the second.

@staticmethod
def _generate_menu():
    menu = QMenu()
    menu.addAction("Quit", lambda: print('quitting'))
    menu.addSeparator()
    menu.addAction("WUUU", method_name)
    menu.addSeparator()

    return menu

Upvotes: 2

Related Questions