PDA

View Full Version : Creating flat QPushButton in Linux, without button sinking when clicked



ashtray4241
9th October 2014, 14:51
Hi,

I am having some issue in coding in QT for Linux.
The scenario is that I have to create some pushbuttons, but I don't want QT native pushbutton, and I have images for both Pressed and Normal states of the button.

I am using QIcon, QStylesheet and QPaintEvent overriding to display the image.

Here is the code structure

header file:

class NewButton:public QPushButton
{
private:
QString normalImage;
QString pressedImage;
public:
NewButton() : QPushButton() {}
NewButton(QWidget *w) : QPushButton(w) {}
void setNormalImage(QString nImg)
{
normalImage=nImg;
}
void setPressedImage(QString pImg)
{
pressedImage=pImg;
}
void paintEvent(QPaintEvent *event)
{
QPixmap pmapUp(normalImage);
pmapUp.setMask(pmapUp.createMaskFromColor(QColor(2 55,0,255)));
QPixmap pmapDown(pressedImage);
pmapDown.setMask(pmapDown.createMaskFromColor(QCol or(255,0,255)));

QIcon icon;
if (this->isDown())
{
icon.addPixmap(pmapDown, QIcon::Normal, QIcon::On);
icon.addPixmap(pmapDown, QIcon::Normal, QIcon::Off);
}
else
{
icon.addPixmap(pmapUp, QIcon::Normal, QIcon::On);
icon.addPixmap(pmapUp, QIcon::Normal, QIcon::Off);
}
this->setIcon(icon);
QPushButton::paintEvent(event)
}
};

class MainWindow:public QMainWindow
{
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
NewButton *pb;
}

cpp file


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setGeometry(10,10,800,600);
centralWidget = new QWidget(this);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
centralWidget->setGeometry(0,0,780,580);
pb=new NewButton(centralWidget);
pb->setGeometry(20,20,116,68);
pb->setFlat(true);
pb->setIconSize(QSize(116,68));
pb->setStyleSheet("QPushButton{border:0px; outline: none;}");
pb->show();
}


This code is working fine in Windows, i.e. the button doesn't get shifted (sunken) when clicked. But in Linux the button is moving/shifting/sinking when clicked.
i found that out by passing same image for normal and pressed image.
In case of Windows, nothing happens when the button is clicked, but in Linux case, click is seen by sunken/risen images.

I want the Windows type behavior, since the pressed image is also passed by me which is already sunken. So basically in Linux case, it gets sunken twice (once by the image, and other by QT native)

I have tried some QProxyStyle


class MyProxyStyle : public QProxyStyle
{
public:
MyProxyStyle(QStyle *style = 0) : QProxyStyle(style) { }
int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) {
cout<<"pixelMetric enter"<<endl;
int ret = 0;
switch (metric) {
case QStyle::PM_ButtonShiftHorizontal:
case QStyle::PM_ButtonShiftVertical:
ret = 0;//QProxyStyle::pixelMetric(metric, option, widget)+20;
break;
default:
ret = QProxyStyle::pixelMetric(metric, option, widget);
break;
}
return ret;
}
};

And in cpp file, I tried


pb->setStyle(new MyProxyStyle(pb->style()));

But this is having no effect. Also the "cout" under pixelMetric is not getting executed. So maybe the style is not getting set to this PushButton.

Can anyone please help me. I am completely stuck on this.
I am using Qt 5.3.1 (also tried on Qt 5.2.1)

anda_skoa
9th October 2014, 17:32
I guess the main problem is calling QPushButton::paintEvent().

Do you need this to be a QPushButton subclass? It looks like this would be more a case when to derive from QAbstractButton.

Cheers,
_

ashtray4241
10th October 2014, 05:24
Thanks for your reply. I haven't tried with QAbstractButton. And I think apart from SetFlat(), I don't need any functionality specific to QPushButton, so I guess QAbstractButton can be tried.
Btw, after several hits and trials, I have found a solution, although I am not sure how elegant that is.

So basically, instead of calling "QPushButton::paintEvent(event)" in overridden paintEvent, I am using "drawControl" directly from this function. And here, instead of checking is button is down/checked to set "option.state" to QStyle::State_Sunken/QStyle::State_Raised (as done in QPushButton paintEvent), I am directly setting it to QStyle::State_Raised without any checks. This way the button is never sinks.
So until I find something more elegant than this, I will consider the issue to be fixed.

anda_skoa
10th October 2014, 10:51
That sounds like a suitable solution as well.

The initial implementation just did too much my calling the base class paintEvent() as a whole, doing what it would have done but leaving out things it should no longer do is a viable approach.

Cheers,
_