0
votes

In my application, I need all QPushButtons to have a width of at least 150px, but bigger if needed. To do so, I am using a global stylesheet (which contains many other properties) with this simple constraint :

QPushButton {
    min-width: 150px;
}

The thing is, I also want buttons with a text that doesn't fit inside 150px to be unable to shrink to a width below which the whole text wouldn't be displayed.
This is supposed to be the normal behavior for a QPushButton, but the problem is that, as explained in the documentation for minimumSizeHint() :

QLayout will never resize a widget to a size smaller than the minimum size hint unless minimumSize() is set or the size policy is set to QSizePolicy::Ignore. If minimumSize() is set, the minimum size hint will be ignored.

This leads to some cases where buttons with long texts are displayed at the right size at startup, but when shrinking the window, the button gets too small to display all the text.
I have prepared a simple example that shows this behavior :

#include <QWidget>
#include <QApplication>
#include <QHBoxLayout>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget *w = new QWidget();
    QLayout* layout = new QHBoxLayout(w);

    QPushButton* buttonA = new QPushButton("A", w);
    QPushButton* buttonB = new QPushButton("B", w);
    buttonB->setStyleSheet("min-width: 150px");
    QPushButton* buttonC = new QPushButton("Long long text that doesn't fit in 150px", w);
    QPushButton* buttonD = new QPushButton("Very very very long text that doesn't fit in 150px", w);
    buttonD->setStyleSheet("min-width: 150px");

    layout->addWidget(buttonA);
    layout->addWidget(buttonB);
    layout->addWidget(buttonC);
    layout->addWidget(buttonD);

    w->show();

    return a.exec();
}

I thought about using dynamic properties to set the minimum width constraint only to buttons that have a base width < 150px, but this doesn't seem to be doable.

Is there a way to do what I want with stylesheets, or do I have to subclass QPushButton and override the minimumSizeHint() method (which I'd like to avoid as I would have to replace a lot of buttons in my app)?

2

2 Answers

1
votes

It would be better if you sub-class QPushButton. But there are 2 work around for this problem:

  1. You can strip the long text to specific numbers of characters and use setToolTip(QString) function to show full text when mouse will enter the button.

  2. You can override parent widget resizeEvent and can check the widths and go for approach number 1 if the size is getting really small.

  3. Use Elide Text example to get idea about elide for QPushButton. Not sure if this will work.

0
votes

I haven't been able to find a way to do this using only stylesheets, but here is the solution I came up with by subclassing QPushButton

MyPushButton.h

#include <QPushButton>

class MyPushButton
    : public QPushButton
{
    Q_OBJECT
    Q_PROPERTY(int minWidth READ minWidth WRITE setMinWidth)

public:
    MyPushButton(QWidget* parent = nullptr);
    virtual ~MyPushButton();

    int minWidth() const;
    void setMinWidth(int width);

    virtual QSize minimumSizeHint() const override;

private:
    int _minWidth;
};

MyPushButton.cpp

#include "MyPushButton.h"

MyPushButton::MyPushButton(QWidget* parent)
    : QPushButton(parent)
    , _minWidth(0)
{
}

MyPushButton::~MyPushButton()
{
}

int MyPushButton::minWidth() const
{
    return _minWidth;
}

void MyPushButton::setMinWidth(int width)
{
    _minWidth = width;
}

QSize MyPushButton::minimumSizeHint() const
{
    // if the minimum width is less than minWidth, set it to minWidth
    // else return the default minimumSizeHint
    return QSize(qMax(QPushButton::minimumSizeHint().width(), _minWidth),
        QPushButton::minimumSizeHint().height());
}

stylesheet.qss

MyPushButton {
    qproperty-minWidth: 150;
}

Buttons with a minimumSizeHint width lower than 150px will be forced to that size, bigger ones will keep the default behavior of QPushButton.