简体   繁体   中英

Align Icon in QPushButton

Starting the program, the QIcon is aligned on the left (it's standard i guess) with the text right to it.

看起来像这样

Instead I want the icon to be centered on top with the text below it.

I tried using setStyleSheet with show_all.setStyleSheet("QIcon { vertical-align: top }") and show_all.setStyleSheet("QPushButton { text-align: bottom }") .

How can I achieve this?

QPushButton doesn't allow to choose the layout of its icon and label. Also, remember that while Qt features style sheets to style widgets, not all CSS known properties and selectors are available. Furthermore, style sheets only work on widgets , so using the QIcon selector isn't supported, since QIcon is not a QWidget subclass.

The most simple solution is to use a QToolButton and set the toolButtonStyle correctly:

self.someButton = QtWidgets.QToolButton()
# ...
self.someButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)

The alternative is to subclass the button, provide a customized paint method and reimplement both sizeHint() and paintEvent() ; the first is to ensure that the button is able to resize itself whenever required, while the second is to paint the button control (without text!) and then paint both the icon and the text.

Here's a possible implementation:

from PyQt5 import QtCore, QtGui, QtWidgets

class CustomButton(QtWidgets.QPushButton):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._icon = self.icon()
        if not self._icon.isNull():
            super().setIcon(QtGui.QIcon())

    def sizeHint(self):
        hint = super().sizeHint()
        if not self.text() or self._icon.isNull():
            return hint
        style = self.style()
        opt = QtWidgets.QStyleOptionButton()
        self.initStyleOption(opt)
        margin = style.pixelMetric(style.PM_ButtonMargin, opt, self)
        spacing = style.pixelMetric(style.PM_LayoutVerticalSpacing, opt, self)
        # get the possible rect required for the current label
        labelRect = self.fontMetrics().boundingRect(
            0, 0, 5000, 5000, QtCore.Qt.TextShowMnemonic, self.text())
        iconHeight = self.iconSize().height()
        height = iconHeight + spacing + labelRect.height() + margin * 2
        if height > hint.height():
            hint.setHeight(height)
        return hint

    def setIcon(self, icon):
        # setting an icon might change the horizontal hint, so we need to use a 
        # "local" reference for the actual icon and go on by letting Qt to *think*
        # that it doesn't have an icon;
        if icon == self._icon:
            return
        self._icon = icon
        self.updateGeometry()

    def paintEvent(self, event):
        if self._icon.isNull() or not self.text():
            super().paintEvent(event)
            return
        opt = QtWidgets.QStyleOptionButton()
        self.initStyleOption(opt)
        opt.text = ''
        qp = QtWidgets.QStylePainter(self)
        # draw the button without any text or icon
        qp.drawControl(QtWidgets.QStyle.CE_PushButton, opt)

        rect = self.rect()
        style = self.style()
        margin = style.pixelMetric(style.PM_ButtonMargin, opt, self)
        iconSize = self.iconSize()
        iconRect = QtCore.QRect((rect.width() - iconSize.width()) / 2, margin, 
            iconSize.width(), iconSize.height())
        if self.underMouse():
            state = QtGui.QIcon.Active
        elif self.isEnabled():
            state = QtGui.QIcon.Normal
        else:
            state = QtGui.QIcon.Disabled
        qp.drawPixmap(iconRect, self._icon.pixmap(iconSize, state))

        spacing = style.pixelMetric(style.PM_LayoutVerticalSpacing, opt, self)
        labelRect = QtCore.QRect(rect)
        labelRect.setTop(iconRect.bottom() + spacing)
        qp.drawText(labelRect, 
            QtCore.Qt.TextShowMnemonic|QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop, 
            self.text())


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = CustomButton('Alles anzeigen', icon=QtGui.QIcon.fromTheme('document-new'))
    w.setIconSize(QtCore.QSize(32, 32))
    w.show()
    sys.exit(app.exec_())

Alternatively, try it:

import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import (QApplication, QWidget, QGridLayout,  
    QToolBar, QAction) 


class Widget(QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        
        add_action = QAction(QIcon("img/add.png"), "Add", self)      
        add_action.triggered.connect(self.addValue)
        sub_action = QAction(QIcon("img/min.png"), "Sub", self)    
        sub_action.triggered.connect(self.subValue)

        toolbar = QToolBar()
        toolbar.setContentsMargins(0, 0, 0, 0)
        toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon | Qt.AlignLeading)
        toolbar.setIconSize(QSize(50, 50))
        toolbar.addAction(add_action)
        toolbar.addAction(sub_action)

        rootGrid = QGridLayout(self)
        rootGrid.addWidget(toolbar)

    def addValue(self):
        print("def addValue:")

    def subValue(self):
        print("def subValue:")
       

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

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM