Dans mon application Qt 5.7.1, j'ai quelques boutons, je veux aligner les icônes des boutons sur le texte gauche et central, mais il n'y a pas d'option dans le concepteur pour le faire.
Je peux aligner l'icône et le texte à gauche en ajoutant à la feuille de style du bouton ce code:
alignement du texte: gauche;
Mais ce n'est pas ce que je veux réaliser. Alors, pourriez-vous me dire s'il y a une option pour aligner l'icône à gauche et garder le texte aligné au centre? Merci pour l'aide.
Il suffit de spécialiser QPushButton
et de remplacer paintEvent
et sizeHint
, comme proposé par cbuchart ici . Ensuite, utilisez-le comme un QPushButton
normal.
MyButton
déclaration et implémentation: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
}
}
Voici un exemple où la fonctionnalité "Promouvoir le widget" dans Qt Designer a été utilisée pour créer MyButton
à partir de fichiers .ui:
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();
}
Résulte en:
QPushButton
normal (en utilisant QPushButton::setText
), vous n'avez pas besoin de conserver une référence à une maquette QLabel
pour changer le texte du bouton.Pour obtenir ce niveau de contrôle, vous devrez écrire du code pour remplacer le style de votre plate-forme. Ceci est mieux fait en utilisant un QProxyStyle . Dans ce cas, nous recherchons lorsque le style est invité à dessiner un CE_PushButtonLabel (l'étiquette comprend l'icône et ils sont codés en dur dans Qt pour être alignés ensemble).
Vous devez implémenter un QProxyStyle et remplacer la méthode drawControl () . Le code pour la majeure partie est copié directement à partir du code source de Qt pour la méthode drawcontrol par défaut (dans qcommonstyle.cpp ) - donc bien qu'il semble long, il fait principalement ce que Qt fait déjà. J'ai mis des marqueurs/****/supplémentaires autour des sections que j'ai modifiées. Cela n'apparaîtra pas dans Qt Designer, mais fonctionnera lors de l'exécution.
Résultat final (affiché sur mac, devrait correspondre à la plateforme sur laquelle vous êtes)
main.cpp:
QApplication a(argc, argv);
a.setStyle(new MyStyle);
...
mystyle.h
class MyStyle : public QProxyStyle
{
public:
virtual void drawControl(ControlElement element, const QStyleOption *opt,
QPainter *p, const QWidget *widget = Q_NULLPTR) const;
};
mystyle.cpp
// Copied from Qt source code..
static QWindow *qt_getWindow(const QWidget *widget)
{
return widget ? widget->window()->windowHandle() : 0;
}
void MyStyle::drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *widget) const
{
if(element==CE_PushButtonLabel)
{
if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt))
{
QRect textRect = button->rect;
uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic;
if (!proxy()->styleHint(SH_UnderlineShortcut, button, widget))
tf |= Qt::TextHideMnemonic;
if (!button->icon.isNull()) {
QRect iconRect;
QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
if (mode == QIcon::Normal && button->state & State_HasFocus)
mode = QIcon::Active;
QIcon::State state = QIcon::Off;
if (button->state & State_On)
state = QIcon::On;
QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state);
int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
int labelWidth = pixmapWidth;
int labelHeight = pixmapHeight;
int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width();
if (!button->text.isEmpty())
labelWidth += (textWidth + iconSpacing);
/*************************************************************/
// Make the icon rectangle always be 10px in from the left Edge
/*************************************************************/
iconRect = QRect(10,
textRect.y() + (textRect.height() - labelHeight) / 2,
pixmapWidth, pixmapHeight);
iconRect = visualRect(button->direction, textRect, iconRect);
/***********************************/
// Always horizontal align the text
/***********************************/
tf |= Qt::AlignHCenter;
if (button->state & (State_On | State_Sunken))
iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget));
p->drawPixmap(iconRect, pixmap);
} else {
tf |= Qt::AlignHCenter;
}
if (button->state & (State_On | State_Sunken))
textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget));
if (button->features & QStyleOptionButton::HasMenu) {
int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget);
if (button->direction == Qt::LeftToRight)
textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
else
textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
}
proxy()->drawItemText(p, textRect, tf, button->palette, (button->state & State_Enabled),
button->text, QPalette::ButtonText);
}
return;
}
// For all other controls, draw the default
QProxyStyle::drawControl(element, opt, p, widget);
}
Moins de code sans casser le style de l'interface utilisateur
pushButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion));
pushButton->setStyleSheet("text-align:left;");
pushButton->setLayout(new QGridLayout);
QLabel* textLabel = new QLabel("Hello world!");
textLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); // or center
textLabel->setAttribute(Qt::WA_TransparentForMouseEvents, true);
pushButton->layout()->addWidget(textLabel);
N'oubliez pas d'envoyer des signaux setText à textLabel au lieu de pushButton