Search code examples
qtalignmentleftalign

QPushButton icon aligned left with text centered


In my Qt 5.7.1 application I've some buttons, I want to align button's icons to left and centre text, but there is no option in designer to do this.

Standard algin

I can align icon and text left by adding to button stylesheet this code:

text-align:left;

Align left

But it's not what I want to achieve. So, could you please tell me, If there is any option to align icon to left, and keep text aligned center? Thank you for help.


Solution

  • Simply specialize QPushButton and override paintEvent and sizeHint, as proposed by cbuchart here. Then use it as a regular QPushButton.

    MyButton declaration and implementation:

    mybutton.h:

    #pragma once
    
    #include <QPushButton>
    
    class MyButton : public QPushButton
    {
    public:
        explicit MyButton(QWidget* parent = nullptr);
        virtual ~MyButton();
    
        void setPixmap(const QPixmap& pixmap);
    
        virtual QSize sizeHint() const override;
    
    protected:
        virtual void paintEvent(QPaintEvent* e) override;
    
    private:
        QPixmap m_pixmap;
    };
    

    mybutton.cpp:

    #include "mybutton.h"
    
    #include <QPainter>
    
    MyButton::MyButton(QWidget* parent) : QPushButton(parent)
    {
    }
    
    MyButton::~MyButton()
    {
    }
    
    QSize MyButton::sizeHint() const
    {
        const auto parentHint = QPushButton::sizeHint();
        // add margins here if needed
        return QSize(parentHint.width() + m_pixmap.width(), std::max(parentHint.height(), m_pixmap.height()));
    }
    
    void MyButton::setPixmap(const QPixmap& pixmap)
    {
        m_pixmap = pixmap;
    }
    
    void MyButton::paintEvent(QPaintEvent* e)
    {
        QPushButton::paintEvent(e);
    
        if (!m_pixmap.isNull())
        {
            const int y = (height() - m_pixmap.height()) / 2; // add margin if needed
            QPainter painter(this);
            painter.drawPixmap(5, y, m_pixmap); // hardcoded horizontal margin
        }
    }
    

    Exemple of usage:

    Here is an example where "Promote widget" feature in Qt Designer was used to create MyButton from .ui files:

    mainframe.ui:

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>400</width>
        <height>300</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <layout class="QVBoxLayout" name="verticalLayout">
        <item>
         <widget class="MyButton" name="button1">
          <property name="text">
           <string>Button</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="MyButton" name="button2">
          <property name="text">
           <string>Other button</string>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>400</width>
         <height>20</height>
        </rect>
       </property>
      </widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarArea</enum>
       </attribute>
       <attribute name="toolBarBreak">
        <bool>false</bool>
       </attribute>
      </widget>
      <widget class="QStatusBar" name="statusBar"/>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <customwidgets>
      <customwidget>
       <class>MyButton</class>
       <extends>QPushButton</extends>
       <header>mybutton.h</header>
      </customwidget>
     </customwidgets>
     <resources/>
     <connections/>
    </ui>
    

    mainwindow.h:

    #pragma once
    
    #include <QMainWindow>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    };
    

    mainwindow.cpp:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QStyle>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        QStyle* style = qApp->style();
        // set buttons pixmaps:
        ui->button1->setPixmap( style->standardPixmap(QStyle::SP_ComputerIcon) );
        ui->button2->setPixmap( style->standardPixmap(QStyle::SP_TrashIcon) );
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    main.cpp:

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    Results in:

    • Compared to docsteer answer, this solution makes it possible to apply the new style to only some buttons of your project. And the code is also smaller.
    • Compared to IGHOR answer, you can still use the button as a regular QPushButton (using QPushButton::setText), you don't need to keep a reference to a mockup QLabel to change button's text.