pythonpysideqmenuqactionqwidgetaction

QWidgetAction not showing menu


I've created a custom widget which is used in a QMenu. Which the menu is displayed the user clicks on the Block rectangle as seen in the image below. However when i change the way the Menu is assigned to the control, it stops working for some reason.

enter image description here

However for some reason the menu does not show when i use this snippet of code:

menu_colors = QtGui.QMenu('Colors')
menu_colors.addAction(colAction)
self.ui_color_filter.setMenu(menu_colors)

instead of this:

fileMenu = menubar.addMenu('&File')
fileMenu.addAction(colAction)
self.ui_color_filter = ColorBlock()
self.ui_color_filter.setMenu(fileMenu)

Below is the full working example. Just un-comment the code to create the issue I'm trying to resolve. You'll notice the menu no longer will appear when clicking on the big black rectangle in the main part of the UI.

import sys
from PySide import QtGui, QtCore


class ColorBlock(QtGui.QPushButton):

    colorClicked = QtCore.Signal(QtGui.QColor)

    def __init__(self, *args, **kwargs):
        super(ColorBlock, self).__init__(*args, **kwargs)
        self.setAutoFillBackground(True)
        self.pressed.connect(self.color_clicked)

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.fillRect(0, 0, self.width(), self.height(), QtGui.QColor(0, 0, 0, 255))
        painter.end()

    def color_clicked(self):
        self.colorClicked.emit(QtGui.QColor())


class ColorBlocks(QtGui.QWidget):

    colorSelected = QtCore.Signal(QtGui.QColor) 

    def __init__(self, parent=None):
        super(ColorBlocks, self).__init__(parent)
        lay_main = QtGui.QGridLayout(self)
        lay_main.setSpacing(5)
        lay_main.setContentsMargins(5,5,5,5)

        row = 0
        column = 0
        for i in range(10):
            ui_swatch = ColorBlock()
            lay_main.addWidget(ui_swatch, row, column)
            ui_swatch.colorClicked.connect(self.colorSelected)

            column += 1
            if column == 5: 
                row += 1
                column = 0


class Example(QtGui.QMainWindow):
    def __init__(self):
        super(Example, self).__init__()

        ql = ColorBlocks()

        colAction = QtGui.QWidgetAction(self)
        colAction.setDefaultWidget(ql)
        ql.colorSelected.connect(self.clicked_color)
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(colAction)


        self.ui_color_filter = ColorBlock()
        self.ui_color_filter.setMenu(fileMenu)

        # menu_colors = QtGui.QMenu('Colors')
        # menu_colors.addAction(colAction)
        # self.ui_color_filter.setMenu(menu_colors)

        lay_main = QtGui.QVBoxLayout()
        lay_main.setAlignment(QtCore.Qt.AlignTop)
        lay_main.addWidget(self.ui_color_filter)
        widget_main = QtGui.QWidget()
        widget_main.setLayout(lay_main)
        self.setCentralWidget(widget_main)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Menubar')    
        self.show()

    def clicked_color(self, color):
        print('Clicked:', color.isValid(), color)
        self.ui_color_filter.color = color
        self.sender().parent().hide()


app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Solution

  • You can not share the same QAction in several QMenu, so you must create one for the QMenu of the QMenuBar of the main widget and another for the menu of the self.ui_color_filter. On the other hand, menu_colors you must pass a parent because if not removed.

    class Example(QtGui.QMainWindow):
        def __init__(self):
            super(Example, self).__init__()
    
            ql = ColorBlocks()
    
            colAction = QtGui.QWidgetAction(self)
            colAction.setDefaultWidget(ql)
            ql.colorSelected.connect(self.clicked_color)
            menubar = self.menuBar()
            fileMenu = menubar.addMenu('&File')
            fileMenu.addAction(colAction)
    
            self.ui_color_filter = ColorBlock()
            ql1 = ColorBlocks()
            colAction1 = QtGui.QWidgetAction(self)
            colAction1.setDefaultWidget(ql1)
            ql1.colorSelected.connect(self.clicked_color)
            menu_colors = QtGui.QMenu('Colors', self)
            menu_colors.addAction(colAction1)
            self.ui_color_filter.setMenu(menu_colors)
    
            lay_main = QtGui.QVBoxLayout()
            lay_main.setAlignment(QtCore.Qt.AlignTop)
            lay_main.addWidget(self.ui_color_filter)
            widget_main = QtGui.QWidget()
            widget_main.setLayout(lay_main)
            self.setCentralWidget(widget_main)
    
            self.setGeometry(300, 300, 250, 150)
            self.setWindowTitle('Menubar')    
            self.show()