apalomer
apalomer

Reputation: 1935

Paint QPushButton with QLinearGradient

I am trying to use a QLinearGradient to paint a QPushButton with no success. I have found examples on how to paint it with a solid color. But I have been unsuccessful in finding examples for a color gradient. Moreover, my approach did not work.

Here is my complete example where the solid color push button works and the linear gradient one does not:

#include <QApplication>
#include <QGridLayout>
#include <QLinearGradient>
#include <QPalette>
#include <QPushButton>

int main(int argc, char** argv)
{
  QApplication app(argc, argv);

  // Create layout
  QGridLayout* layout = new QGridLayout;

  // Create first button
  QPushButton* button_1 = new QPushButton();
  layout->addWidget(button_1, 0, 0);
  QPalette palette_1 = button_1->palette();
  palette_1.setColor(QPalette::Button, Qt::red);
  button_1->setPalette(palette_1);
  button_1->update();

  // Create second button
  QPushButton* button_2 = new QPushButton();
  layout->addWidget(button_2, 0, 1);
  QLinearGradient gradient_button(0, 0, button_2->width(), 0);
  gradient_button.setColorAt(0, Qt::white);
  gradient_button.setColorAt(1, Qt::black);
  QPalette palette_2 = button_2->palette();
  QBrush brush(gradient_button);
  palette_2.setBrush(QPalette::Button, brush);
  button_2->setPalette(palette_2);
  button_2->update();

  // Create widget
  QWidget* widget = new QWidget;
  widget->setLayout(layout);
  widget->resize(300, 50);

  /// Show
  widget->show();

  // Run
  return app.exec();
}

Any ideas on what am I doing wrong?

Upvotes: 3

Views: 1994

Answers (2)

cbuchart
cbuchart

Reputation: 11575

Your gradient is configured to go from <0, 0> to <button_2->width(), 0>, but at the moment you create your gradient button_2 is not included in any layout: its width will be computed when the parent widget (therefore the layout where the button is) is resized. If you try fixing the width you'll see the gradient works as expected.

QPushButton* button_2 = new QPushButton();
button_2->setFixedWidth(100);

You can use an event filter to watch for the resize and adjust the gradient accordingly:

class ButtonResizeWatcher : public QObject {
protected:
  virtual bool eventFilter(QObject* o, QEvent* e) override {
    if (e->type() == QEvent::Resize) {
      auto button = qobject_cast<QPushButton*>(o);

      QLinearGradient gradient_button(0, 0, button->width(), 0);
      gradient_button.setColorAt(0, Qt::white);
      gradient_button.setColorAt(1, Qt::red);

      auto palette = button->palette();
      palette.setBrush(QPalette::Button, QBrush(gradient_button));
      button->setPalette(palette);
    }

    return QObject::eventFilter(o, e);
  }
};

Use:

ButtonResizeWatcher resize_watcher;
button_2->installEventFilter(&resize_watcher);

Full code can be found in GitHub.

Another option, as commented in a different answer, would be to use the stylesheet (qlineargradient). It depends on you if you need further control on the brush, such as "show gradient but only until certain width is reached". Also, take into consideration that stylesheets usually conflicts with other QStyles (if used).

Upvotes: 3

Alexander Chernin
Alexander Chernin

Reputation: 444

Without a success I've tried it with QPalette and done it successfully using setStyleSheet:

QPushButton* button = new QPushButton();
QString linearGradient = QString("qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));");

button->setStyleSheet(QString("background-color: %1").arg(linearGradient));

Also, we can use QString::arg(...) to set different colors and points for the gradient.

Hope this help you and excuse me for a stupid comment earlier )

Upvotes: 3

Related Questions