PDA

View Full Version : How to change Pushbutton color with QPalette



GeneCode
18th September 2017, 07:24
I tried:

palOn.setColor(QPalette::Button, Qt::green);
btn->setPalette(palOn);

doesn't work. Only work when i select Flat on QtDesigner. But i dont want flat.

d_stranz
19th September 2017, 01:00
This is almost impossible to do on Windows. No matter what you try, either style sheet or palette, the button drawing code does its own thing. The most common solution is to derive a new custom class (*ahem*) from QPushButton and override the paintEvent:



// ColorButton.h

#pragma once

#include <QPushButton>

class ColorButton : public QPushButton
{
Q_OBJECT

public:
ColorButton( const QString & text, QWidget * pParent = 0 );
virtual ~ColorButton();

void setBackgroundColor( const QColor & color );

protected:
void paintEvent( QPaintEvent * pEvent );

protected:
QColor background;
};




// ColorButton.cpp

#include "ColorButton.h"
#include <QStylePainter>
#include <QStyleOptionButton>
#include <QPaintEvent>

ColorButton::ColorButton( const QString & text, QWidget * pParent )
: QPushButton( text, pParent )
, background( Qt::red )
{
}

ColorButton::~ColorButton()
{
}

void ColorButton::setBackgroundColor( const QColor & color )
{
background = color;
update();
}

void ColorButton::paintEvent( QPaintEvent * pEvent )
{
QStylePainter painter( this );
painter.fillRect( pEvent->rect(), background );

QStyleOptionButton option;
initStyleOption( &option );

if ( !isFlat() )
painter.drawPrimitive( QStyle::PE_FrameButtonBevel, option );

if ( isDefault() )
painter.drawPrimitive( QStyle::PE_FrameDefaultButton, option );

if ( hasFocus() )
painter.drawPrimitive( QStyle::PE_FrameFocusRect, option );

painter.drawControl( QStyle::CE_PushButtonLabel, option );

}




// main.cpp test program

#include <QWidget>
#include <QApplication>
#include <QVBoxLayout>
#include "ColorButton.h"

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

QWidget window ;

window.setWindowTitle( QString::fromUtf8( "QPushbutton Background" ) );
window.resize( 336, 227 );

ColorButton *button1 = new ColorButton( "Button 1" );
ColorButton *button2 = new ColorButton( "Button 2" );
ColorButton *button3 = new ColorButton( "Button 3" );

QVBoxLayout* layout = new QVBoxLayout( &window );
layout->addWidget( button1 );
layout->addWidget( button2 );
layout->addWidget( button3 );


button1->setBackgroundColor( Qt::lightGray );
button2->setBackgroundColor( Qt::green );
button3->setBackgroundColor( Qt::transparent );

button1->setCheckable( true );
button1->setChecked( true );

button2->setEnabled( false );
button3->setDefault( true );

window.show();
return app.exec();

}


This is a simplistic override of QPushButton. It implements only a few of the painting styles that change with the button state. Some of them are automatically done by the primitives (like drawing the checked state or the border of the default button). Button2 is disabled, but the only obvious thing is that the text is grayed out.

Other things probably need to be implemented (like drawing the icon if the button has one). Doing that is left as an exercise for the reader.

GeneCode
19th September 2017, 01:01
It's okay I will find a book and learn it.

d_stranz
19th September 2017, 02:26
Pretty hard to make you happy, isn't it? Took me about 3 hours to figure out the answer to this one when the simple QPalette-based solution didn't work for me either.

Enjoy your books. I don't think I'll bother to answer any of your future questions.

high_flyer
20th September 2017, 15:57
This is almost impossible to do on Windows. No matter what you try, either style sheet or palette, the button drawing code does its own thing.
Hmm, interesting.
I remember how back in the day, this was an issue of its own "the red button issue".
I remember how either the release of Qt3 or Qt4 (can't remember which anymore) during dev days they actually used it as a show case of how the "problem of the red button" is so simple to implement with Qt (might have been the introduction of QStyleSheet, but I am not sure.
If this is true (which I believe it is after you have tried it) then its a regression.

d_stranz
20th September 2017, 17:00
If this is true (which I believe it is after you have tried it) then its a regression.

I believe it might have occurred with the transition to the new Qt5 implementation of platform-specific code in a driver library (the qwindows.dll in /platforms) and the refactoring that was needed for that.

Even in the code I wrote above, it was very difficult to get the panel of the button to be red. Any call to QStylePainter::drawControl() with a CE_PushButton* argument other than "Label" results in a button with a red border and the panel filled in by the system color. And even with the code I wrote, the button appearance and behavior is subtly different from what you get from a standard QPushButton. I think it would take a lot more work to get a button that looked and acted the same but with a color of your own choosing.

GeneCode
25th September 2017, 02:50
Pretty hard to make you happy, isn't it? Took me about 3 hours to figure out the answer to this one when the simple QPalette-based solution didn't work for me either.

Enjoy your books. I don't think I'll bother to answer any of your future questions.

Aww... sorry man. I appreciate your coding and subclass example.
Thank you. :D