Creating Custom Ellipse Button
I tried this code then did QEllipseButton b; b.setText("woot"); b.show(); in a simple window of Qt, and it will not show the area. I tried r3, and r1, update,setting a background... but it wont make me a button with a different size.
Like I would like to make an egg shaped button that works just like a pushbutton, but has a nice background image on it.
Code:
public:
}
protected:
QRegion r2
(QRect(200,
70,
90,
30));
// r2: rectangular region QRegion r3
= r1.
intersected(r2
);
// r3: intersection
painter.setClipping(true);
painter.setClipRegion(r1);
//QBrush brush(QColor(255,0,0,255));
//painter.setBackground(brush);
//update();
}
};
thx for help.
Re: Creating Custom Ellipse Button
Why don't you try QWidget::setMask( const QRegion& ).
Using a painter to achieve this will probably not work, because the background of the widget is not (yet) transparent. You could first fill the widget rect with a transparent pixmap but it is better and easier to use QWidget::setMask.
Regards
Re: Creating Custom Ellipse Button
Oh, and even if you subclass QPushButton, overriding paintEvent will not keep the push button behavior. If you like, you could call QPushButton::paintEvent in the paint event of your class( at the beginning ). But this could mess up things even more...
In my opinnion, the best solution is to subclass QAbstractButton and custom draw your button in all the states ( pressed, normal, hovered, disabled, etc...). This allows more freedom in defining the look of your widget.
Regards
Re: Creating Custom Ellipse Button
Could you show any code examples of this?
Re: Creating Custom Ellipse Button
Unfortunately I do not have any examples, nor the time to create one :). But it should be pretty straightforwards.
You define an enum in your QAbstractButton subclass.
Code:
typedef enum States
{
eStateNormal,
eStatePressed,
eStateHovered,
eStateDisabled
} States;
Then , add a State member in your class.
The state switching depends on the user actions.
Initially you start with eStateNormal.
In mousePressEvent, if the button is Qt::LeftButton, the state is eStatePressed.
In mouseMoveEvent, if no btns are pressed, the state is eStateHovered.
In mouseReleaseEvent, if the previous state was eStatePressed, then switch to eStateNormal.
After this, everything happens in paintEvent:
Code:
{
switch( mButtonState )
{
case eStateNormal:
//Paint in this state
break;
case eStatePressed:
//Paint in this state
break;
case eStateHovered:
//Paint in this state
break;
case eStateDisabled:
//Paint in this state
break;
}
}
Actually, you should make pixmaps for all the states ( either external or you build them here ). It will make drawing faster.
Regards
Re: Creating Custom Ellipse Button
Yeah I don't think this is working:
Code:
public:
typedef enum States
{
eStateNormal,
eStatePressed,
eStateHovered,
eStateDisabled
} States;
States m_ButtonState;
m_ButtonState = eStateNormal;
}
protected:
if (event->button() == Qt::LeftButton) {
m_ButtonState = eStatePressed;
}
}
if(event->buttons() & Qt::LeftButton) {
m_ButtonState = eStateHovered;
}
}
if(event->buttons() && m_ButtonState == eStatePressed){
m_ButtonState = eStateNormal;
}
}
QRegion r2
(QRect(200,
70,
90,
30));
// r2: rectangular region QRegion r3
= r1.
intersected(r2
);
// r3: intersection
switch( m_ButtonState ){
case eStateNormal:
qpx.
load(QString("JoinNormal.jpg"));
break;
case eStatePressed:
qpx.
load(QString("JoinPressed.jpg"));
break;
case eStateHovered:
qpx.
load(QString("JoinHover.jpg"));
break;
case eStateDisabled:
qpx.
load(QString("JoinNormal.jpg"));
break;
}
QRectF target
(10.0,
20.0,
80.0,
60.0);
QRectF source
(0.0,
0.0,
70.0,
40.0);
painter.drawPixmap(target, qpx, source);
painter.setClipping(true);
painter.setClipRegion(r1);
//QBrush brush(QColor(255,0,0,255));
//painter.setBackground(brush);
//update();
}
};
class QEllipseButton : public QAbstractButton {
public:
typedef enum States
{
eStateNormal,
eStatePressed,
eStateHovered,
eStateDisabled
} States;
States m_ButtonState;
QEllipseButton(QWidget * parent = 0): QAbstractButton(parent){
m_ButtonState = eStateNormal;
}
protected:
void mousePressEvent(QMouseEvent *event){
if (event->button() == Qt::LeftButton) {
m_ButtonState = eStatePressed;
}
}
void mouseMoveEvent(QMouseEvent *event){
if(event->buttons() & Qt::LeftButton) {
m_ButtonState = eStateHovered;
}
}
void mouseReleaseEvent(QMouseEvent *event){
if(event->buttons() && m_ButtonState == eStatePressed){
m_ButtonState = eStateNormal;
}
}
void paintEvent ( QPaintEvent * event ){
QRegion r1(QRect(200, 50, 500, 400), // r1: elliptic region
QRegion::Ellipse);
QRegion r2(QRect(200, 70, 90, 30)); // r2: rectangular region
QRegion r3 = r1.intersected(r2); // r3: intersection
QPainter painter(this);
QPixmap qpx;
switch( m_ButtonState ){
case eStateNormal:
qpx.load(QString("JoinNormal.jpg"));
break;
case eStatePressed:
qpx.load(QString("JoinPressed.jpg"));
break;
case eStateHovered:
qpx.load(QString("JoinHover.jpg"));
break;
case eStateDisabled:
qpx.load(QString("JoinNormal.jpg"));
break;
}
QRectF target(10.0, 20.0, 80.0, 60.0);
QRectF source(0.0, 0.0, 70.0, 40.0);
painter.drawPixmap(target, qpx, source);
painter.setClipping(true);
painter.setClipRegion(r1);
//QBrush brush(QColor(255,0,0,255));
//painter.setBackground(brush);
//update();
}
};
I posted twice, so you can copy one, since someone not so smart decided to use number lines with Geshi knowing that no one can COPY the code because of damn number lines.
Re: Creating Custom Ellipse Button
You have to trigger repainting after updating your state (call update()).
Just setting your internal state variable will not cause your button to repaint itself in this state.
HTH
Christoph
Re: Creating Custom Ellipse Button
:) Yes.
I forgot that, but you must call an update() to schedule a paintEvent each time you switch the states.
Other than this, the code looks good.
Regards
Re: Creating Custom Ellipse Button
No the code still does not work:
#include <QtGui>
#include "flowlayout.h"
class QEllipseButton : public QAbstractButton {
public:
typedef enum States
{
eStateNormal,
eStatePressed,
eStateHovered,
eStateDisabled
} States;
States m_ButtonState;
QEllipseButton(QWidget * parent = 0): QAbstractButton(parent){
m_ButtonState = eStateNormal;
}
protected:
void mousePressEvent(QMouseEvent *event){
if (event->button() == Qt::LeftButton) {
m_ButtonState = eStatePressed;
update();
}
}
void mouseMoveEvent(QMouseEvent *event){
if(event->buttons() & Qt::LeftButton) {
m_ButtonState = eStateHovered;
update();
}
}
void mouseReleaseEvent(QMouseEvent *event){
if(event->buttons() && m_ButtonState == eStatePressed){
m_ButtonState = eStateNormal;
update();
}
}
void paintEvent ( QPaintEvent * event ){
QRegion r1(QRect(200, 50, 500, 400), // r1: elliptic region
QRegion::Ellipse);
QRegion r2(QRect(200, 70, 90, 30)); // r2: rectangular region
QRegion r3 = r1.intersected(r2); // r3: intersection
QPainter painter(this);
QPixmap qpx;
switch( m_ButtonState ){
case eStateNormal:
qpx.load(QString("Normal.jpg"));
break;
case eStatePressed:
qpx.load(QString("Pressed.jpg"));
break;
case eStateHovered:
qpx.load(QString("Hover.jpg"));
break;
case eStateDisabled:
qpx.load(QString("Normal.jpg"));
break;
}
QRectF target(100.0, 100.0, 100.0, 100.0);
QRectF source(100.0, 100.0, 100.0, 100.0);
painter.drawPixmap(target, qpx, source);
painter.setClipping(true);
painter.setClipRegion(r1);
//QBrush brush(QColor(255,0,0,255));
//painter.setBackground(brush);
//update();
}
};
----------------- hOW i run it: -------
QEllipseButton b;
b.setText("hoot");
b.show();
Re: Creating Custom Ellipse Button
Code:
QRectF target
(100.0,
100.0,
100.0,
100.0);
QRectF source
(100.0,
100.0,
100.0,
100.0);
Is the problem, by any chance, that you don't see any pixmap?
Try drawing everything relative to (0,0), not (100, 100).
Also, overwrite QAbstractButton::sizeHint() and return your size hint( which probably is the size of one of the pixmaps ).
Regards
Re: Creating Custom Ellipse Button
I used 0, and I finally saw the picture. However, the clip stuff never works. Also putting everything inside a QHBoxLayout and settingLayout with a widget, makes it dissappear.
Also Hover absolutely does not work.
Re: Creating Custom Ellipse Button
Regarding hover:
Hover means you just move your mouse over the widget. You switch to hover if the left button is pressed, in mouseMoveEvent, which is not correct.
To detect hover, there are less processor stressing methods, like QWidget::enterEvent and QWidget::leaveEvent.
Regarding adding your custom btn to layouts:
When I said drawing everything relative to (0,0) I meant to the origin of what rect() returns: rect().topLeft().
Adding to layouts did not worked because everything was drawn in the topleft corner of the layout :).
Hope it works now.
Regards
Re: Creating Custom Ellipse Button
Well how do I add automaticlaly to wherever it needs to draw it...? Is there a way?
Any code examples?
Re: Creating Custom Ellipse Button
Wouldn't it be easier to do this with style sheets?
i.e.
Code:
int main(int argc, char **argv)
{
btn.setStyleSheet
(
"QPushButton {"
" border-image: url(normal.png) 17% 17% 17% 17% stretch stretch; "
" border-width: 8px;"
"}"
"QPushButton:hover {"
" border-image: url(hover.png) 17% 17% 17% 17% stretch stretch; "
" border-width: 8px;"
"}"
"QPushButton:pressed {"
" border-image: url(pressed.png) 17% 17% 17% 17% stretch stretch; "
" border-width: 8px;"
"}"
);
QObject::connect(&btn,
SIGNAL(clicked
()),
&app,
SLOT(quit
()));
btn.show();
app.exec();
}
You obviously have to adjust the percentage and border values to fit your bitmap and you won't be able to get a true ellipse since some part of the image must be stretched or repeated depending on the text length, but it seems a lot easier.
Re: Creating Custom Ellipse Button
I realize that, I won't be able to get it perfectly. I won't be able to cut the square black background into a transparent one or turn the Square feature of pushbutton into an ELLIPSE feature.
the Stretch stuff by the way didn't change anything except when the image size is different than the button size.
Re: Creating Custom Ellipse Button
Hey man, it works just fine if you do it as I've shown you.
It will work anyway if you use "ready-made" png images for the states. I mean you draw an ellipse in a png and leave everything else transparent. Then just fill the widget with these pixmaps.
If you use transp pixmaps the you don't need setting any clipping masks.
Regards
Re: Creating Custom Ellipse Button
Quote:
If you use transp pixmaps the you don't need setting any clipping masks.
Are you sure about that?
Is this from experience?
Some time back I implemented a styled button, which can take any shape, and as I remember, I had to use masks in addition to the png (which had transparent areas).
Re: Creating Custom Ellipse Button
Yes, I have already tried it some time ago.
Also, I might have filled the widget with a transparent pixmap first, then applied the actual png... Can't remember exactly, but it can be done.
Regards
Re: Creating Custom Ellipse Button
Code:
ui->pushButton->setFixedSize(150,100);
ui->pushButton->setStyleSheet("QPushButton {"
"background-color: red;"
"border-style: solid;"
"border-width: 3px;"
"border-radius: 75px 50px;"
"border-color: blue;"
"font: bold 14px;"
"padding: 6px;}"
"QPushButton:pressed {"
"background-color: rgb(224, 0, 0);}");
That's what i have implemented ... (For someone looking for a way to go)
Please note : setFixedSize(150,100); and "border-radius: 75px 50px;"
Regards.