Home > Enterprise >  PyQt6 Padding disappears if you remove the down arrow on a QPushButton that has setMenu set
PyQt6 Padding disappears if you remove the down arrow on a QPushButton that has setMenu set

Time:10-09

I need to delete this default down arrow indicator with setMenu on QPushButton. But If I somehow change QPushButton::menu-indicator style, for example like this:

QPushButton::menu-indicator { image: none; }

padding from QPushButton disappears immediately. How I can fix this issue?

Little example:

btn = QPushButton("Hello world!")
btn.setStyleSheet(
    "QPushButton { padding: 0 50px; text-align: left; }"
    "QPushButton::menu-indicator { image: none }"
)
menu = QMenu()
menu.addAction("Help")
menu.addAction("Go away")
btn.setMenu(menu)

and if I remove the line

"QPushButton::menu-indicator { image: none }"

padding appears again

Here are pictures for better understanding: without menu indicator

with menu indicator

CodePudding user response:

It seems like a bug, as it works as expected in Qt5.

After checking the sources, they changed some important aspects in the computation of the button bevel and subsequent aspects (including the geometry of the label).

I strongly suggest you to report the bug as it seems quite important.

In the meantime, there is a partial workaround: you can set a specific QProxyStyle for the interested buttons, and override the drawItemText() function (which is one of the few that are still called on a proxy style even while using a QSS).

This is a possible solution:

class ButtonFix(QProxyStyle):
    def __init__(self, button):
        super().__init__()
        self.button = button

    def drawItemText(self, rect, alignment, palette, 
        enabled, text, role=QPalette.ColorRole.NoRole):
            opt = QStyleOptionButton()
            self.button.initStyleOption(opt)
            opt.features &= ~opt.ButtonFeature.HasMenu
            rect = self.button.style().subElementRect(
                QStyle.SubElement.SE_PushButtonContents, opt, self.button)
            super().drawItemText(qp, rect, alignment, palette, 
                enabled, text, role)

Then you can just do something like this:

btn = QPushButton("Hello world!")
# ...
btn.setStyle(ButtonFix(self.proxyBtn))

Note that this obviously has some important issues (besides the fact that I just tested it on Linux and on a couple of styles):

  • once you explicitly set a style on a widget, setting the application style will have no effect;
  • in some styles, the padding might not be perfect (I only assumed the margins based on the SE_PushButtonContents enum, so it might not be consistent);
  • the bug also affects icons, but QStyleSheetStyle does not call the base style drawItemPixmap() (it just calls the QPainter's drawPixmap()), so there is no solution for that;

As soon as you know that the bug has been fixed, you can then provide the workaround just for the Qt versions that are affected by it, eventually checking the QT_VERSION_STR.

  • Related