4

I am using multiple QToolButtons in a custom QGridLayout widget. The buttons are set to display icon + text based on an assigned default QAction. The only issue is that the content (icon + text) is always left-aligned.

The content (icon + text, marked as a red box in the screenshot), should be center in the button (indicated by the blue box).

enter image description here

For most cases this is just fine, given that Qt automatically tries to render that button with the minimal size. However I am stretching the button to fit nicely into my 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);

Is there a way to force the content to be centered in the button?

PS: I found the following comment in another forum, which however seems quite invasive and is not really clear to me yet:

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.

Philip Allgaier
  • 3,505
  • 2
  • 26
  • 53
  • Please post the relevant code. – user2672165 Feb 14 '15 at 16:28
  • @user2672165: I edited in the code into the question. Not sure if that helps though in this case... – Philip Allgaier Feb 14 '15 at 17:28
  • What about using the alignment in `void QGridLayout::​addWidget(QWidget * widget, int row, int column, Qt::Alignment alignment = 0)`? Also you could perhaps post a picture on how it looks and how you would like it to look because there are several parameters to consider? – user2672165 Feb 14 '15 at 19:13
  • @user2672165 I probably did not make it clear enough: The grid layout is not the issue. The button is perfectly placed and ([almost](http://stackoverflow.com/questions/28515953/qtoolbutton-with-text-overwrite-minimal-height-to-minic-regular-button-height)) perfectly sized. The issue I have is that the content inside the button is not centered. See the screenshot I added to the question. – Philip Allgaier Feb 14 '15 at 19:52
  • Ok. I think I understood that. I would try modifying pButton->layout(). The QToolButton ought to have a QHBoxLayout. – user2672165 Feb 14 '15 at 20:05
  • @user2672165 The button does not return a valid layout pointer. So unfortunately, there seems to be no layout that I could modify. – Philip Allgaier Feb 16 '15 at 08:39
  • @PhilipAllgaier - you will probably have to reimplement a `QStyle` to change the alignment. Such things are usually "hard-coded" for a particular UI style. That's just how `QWidgets` are - not very flexible. – dtech Feb 20 '15 at 11:09

2 Answers2

3

As I suggest in answer to you another question. https://stackoverflow.com/a/28630318/1917249 Do not use QToolButton, just use QPushButton, and add popup menu if needed.

Then you wont have different sizes of QToolButton and QPushButton widgets. And you will have centered icon and text.

Popupmenu can be easily added to QPushButton ( only small arrow wont be shown )

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);
 });

Or you can subclass QPushButton and add Popup menu handling there. Much better then try to center text with icon in QToolButton or have in same size of QPushButton and QToolButton

For complex example please see my answer: https://stackoverflow.com/a/28630318/1917249

Community
  • 1
  • 1
fbucek
  • 1,647
  • 13
  • 22
  • 1
    The reasoning behind attempting to go for QToolButton as opposed to QPushButton was that a QToolButton automatically takes over the action attributes (title text + icon) and handles the signal / slot linking. But in the end those benefits are not worth the hassle and drawbacks I experienced in terms of button height and text / icon alignment. I therefore switched to QPushButton and manually set the text / icon attribute and setup the slot / signal linking. – Philip Allgaier Feb 23 '15 at 10:09
1

The following class does the job for me:

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);
}

Sample use:

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