Applying a style sheet to a QPushButton and a QToolButton
-
I'm trying to create a widget which will have similar behaviour to a QComboBox, but with different behaviours depending on whether the user clicks on the arrow or elsewhere on the widget. For starters, I'm modelling the widget itself as a wide QPushButton with a QToolButton superimposed on it. Once I have this looking as I want it to, I'll add a QListView to provide the drop-down menu and make it appear whenever the unit presses the QToolButton (but not the QPushButton). My basic test code so far looks like this:
#include <QtWidgets/QApplication> #include <QDialog> #include <QPushButton> #include <QToolButton> #include <QPushButton> #include <QGridLayout> class StylesheetTest : public QDialog { Q_OBJECT public: StylesheetTest(QWidget * parent = nullptr) : QDialog(parent) { // Create the widgets and layouts itsLayout = new QGridLayout; itsMainButton = new QPushButton; itsDropdownButton = new QToolButton; // Place the widgets in the layout: itsLayout -> addWidget(itsMainButton, 0, 0, 1, 2); itsLayout -> addWidget(itsDropdownButton, 0, 1, 1, 1); itsLayout -> setSpacing(0); itsLayout -> setColumnStretch(0, 1); itsMainButton -> setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); itsDropdownButton -> setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); itsDropdownButton -> setArrowType(Qt::DownArrow); // Formally appoint the layout setLayout(itsLayout); // Now the stylesheet settings setStyleSheet("QToolButton { border: none; } "); // Give the button a label itsMainButton -> setText("An extraordinarily long label for a button"); } private: QPushButton *itsMainButton; QToolButton *itsDropdownButton; QGridLayout *itsLayout; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); StylesheetTest t; t.show(); return a.exec(); } #include "main.moc"
This gets me most of the way there; the resulting button looks like this:
It looks very much like a QComboBox, but I get the independent behaviours of the QPushButton and the QToolButton, just as I want. However, I'd like to make it even better:
- I'd like to set a bit of a margin on the right-hand side of the QPushButton, so that the text doesn't overlap the arrow
- I'd like the arrow itself to be a bit smaller
Everything I know about style sheets (which admittedly isn't much) tells me that to achieve this I need something resembling
// Now the stylesheet settings setStyleSheet("QPushButton { padding-right: 20px; }"); setStyleSheet("QToolButton { border: none; } " "QToolButton::down-arrow { width: 8px; height: 8px; }" );
but in fact the result of this is a mess:
Further experimentation shows that trying to set the 'padding-right' parameter of the QPushButton to any value at all leads to its vertical height getting squeezed in this way, while all attempts to modify the size of the down-arrow fail. I'm obviously doing something wrong, but I can't see what. Any hints would be gratefully received.
UPDATE
I've decided that a better approach is, rather than using a QToolButton in front of a QPushButton and having manually to implement the QListView behaviour, to put a QPushButton in front of a QComboBox leacing just the latter's arrow exposed. Like this:
#include <QtWidgets/QApplication> #include <QDialog> #include <QPushButton> #include <QComboBox> #include <QGridLayout> class StylesheetTest : public QDialog { Q_OBJECT public: StylesheetTest(QWidget * parent = nullptr) : QDialog(parent) { // Create the widgets and layouts itsLayout = new QGridLayout; itsMainButton = new QPushButton; itsHiddenComboBox = new QComboBox; // Place the widgets in the layout: itsLayout -> addWidget(itsHiddenComboBox, 0, 0, 1, 3); itsLayout -> addWidget(itsMainButton, 0, 0, 1, 2); itsLayout -> setSpacing(0); itsLayout -> setColumnStretch(0, 1); itsLayout -> setColumnMinimumWidth(2, 20); itsMainButton -> setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); itsHiddenComboBox -> setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); // Formally appoint the layout setLayout(itsLayout); // Now the stylesheet settings setStyleSheet("QPushButton { border: none; padding-left: 10px; } "); itsMainButton -> setText("An extraordinarily long label for a button"); } private: QPushButton *itsMainButton; QComboBox *itsHiddenComboBox; QGridLayout *itsLayout; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); StylesheetTest t; t.show(); return a.exec(); } #include "main.moc"
The one shortcoming of this solution is that, having eliminated the border from the QPushButton, it no longer responds visibly to being clicked (even though the usual signals are sent). As it happens I can cope with this, as my ultimate intention is for pressing the QPushButton to cause a change of the cursor and this will make it obvious enough to the user that the button has been successfully clicked.