带有图标+文本的 QToolButton:如何将两者居中?

QToolButton with icon + text: How to center both?

我正在使用多个 QToolButtons in a custom QGridLayout 小部件。这些按钮被设置为基于分配的默认 QAction 显示图标 + 文本。唯一的问题是内容(图标+文本)始终是左对齐的。

内容(图标+文字,在截图中标为红框),应居中于按钮(以蓝框表示)。

在大多数情况下,这很好,因为 Qt 会自动尝试以最小尺寸呈现该按钮。但是我正在拉伸按钮以很好地适应我的 QGridLayout。

QToolButton* pButton = new QToolButton(0);
pButton->addDefaultAction(pAction);
pButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
pButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

QGridLayout *pActionAreaLayout = new QGridLayout;
pActionAreaLayout->addWidget(pSomeOtherWidget, 0, 0, 1, 2);
pActionAreaLayout->addWidget(pButton , 1, 0, 1, 1);

有没有办法强制内容在按钮中居中?

PS:我在 another forum 中发现了以下评论,但它看起来很有侵略性,我还不是很清楚:

You can try doing the horizontal alignment using a stylesheet, but you probably have to implement a QStyle proxy and reimplement drawControl() for QStyle::CE_ToolButtonLabel Or derive from QToolButton, overwrite paintEvent() and call the style for everything other than the label.

正如我在回答您另一个问题时所建议的那样。 不使用QToolButton,只使用QPushButton,如果需要的话添加弹出菜单。

那么您将不会有不同大小的 QToolButtonQPushButton 小部件。您将看到居中的图标和文本。

弹出菜单可以很容易地添加到QPushButton(只有小箭头不会显示)

QPushButton *pushButton = new QPushButton(toolAction->icon(), "PushButton", window);
// window - widget where button is placed ( to get correct QMenu position )
QObject::connect(pushButton, &QPushButton::released, [window, pushButton, action](){
    QMenu menu;
    menu.addAction(action);
    QPoint pos = window->mapToGlobal(pushButton3->pos());
    pos += QPoint(0, pushButton->height());
    menu.exec(pos);
 });

或者您可以子类化 QPushButton 并在那里添加弹出菜单处理。比 QToolButton 中的图标居中或具有 QPushButtonQToolButton

中相同大小的文本要好得多

复杂的例子请看我的回答:

以下 class 为我完成了工作:

class CenteredToolButtonStyle : public QProxyStyle
{
Q_OBJECT

public:
CenteredToolButtonStyle(QToolButton* b, const QSize& sIcon);

virtual void drawItemPixmap(QPainter *painter, const QRect &rect, int, const QPixmap &pixmap) const
    override { m_pic = pixmap; m_ny = rect.y(); Draw(painter); }
virtual void drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal, bool enabled,
    const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const override;
void Draw(QPainter *painter) const;

const QToolButton* B;
const QSize SICON;
mutable QString m_s;
mutable QPixmap m_pic;
mutable QRect m_r;
mutable int m_nf, m_ny;
mutable bool m_bEnabled;
mutable QPalette m_pal;
mutable QPalette::ColorRole m_textRole;
};


CenteredToolButtonStyle::CenteredToolButtonStyle(QToolButton* b, const QSize& sIcon)
: QProxyStyle(), B(b), SICON(sIcon), m_nf(0), m_bEnabled(true), m_ny(0)
{
b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
setParent(b);
}

void CenteredToolButtonStyle::drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal,
bool enabled, const QString &text, QPalette::ColorRole textRole/* = QPalette::NoRole*/) const
{
m_s = text;
m_r = rect;
m_nf = flags | Qt::AlignCenter;
m_bEnabled = enabled;
m_pal = pal;
m_textRole = textRole;
Draw(painter);
}

void CenteredToolButtonStyle::Draw(QPainter *painter) const
{
if (m_ny) {
    if (m_r.y() != m_ny) return;
    auto r = m_r;
    r.adjust(-SICON.width() - 8, m_ny = 0, -itemTextRect(B->fontMetrics(), m_r, m_nf, m_bEnabled, m_s).width(), 0);
    QProxyStyle::drawItemPixmap(painter, r, Qt::AlignCenter, m_pic);
}
QProxyStyle::drawItemText(painter, m_r, m_nf, m_pal, m_bEnabled, m_s, m_textRole);
}

示例使用:

foreach(auto b, ui.mainToolBar->findChildren<QToolButton*>()) 
    b->setStyle(new CenteredToolButtonStyle(b, ui.mainToolBar->iconSize()));