PDA

View Full Version : How to animate the transparency of a child QPushButton using QPropertyAnimation ?



daudiam
17th October 2010, 18:05
I want to progressively decrease the opacity of a QPushButton over a time of 2 seconds to complete transparency. For that I used the QPropertyAnimation class and used the property "windowOpacity" of the button to achieve the effect. But that worked only for a standalone QPushButton. When I assigned a parent to the button, the effect disappeared. Is there any way of achieving the same effect for child buttons ?

tbscope
17th October 2010, 18:26
This is the side effect of child widgets not being windows in Qt.
You can only do the opacity on the parent.

edit: however, this doesn't mean it is impossible.
Use a style specific for your button.

daudiam
17th October 2010, 19:41
Thanks. But how do we specify transparency levels in buttons ? I mean, any functions, any property which I can set.

tbscope
17th October 2010, 19:47
Read about QPalette.

wysota
17th October 2010, 22:00
Let's try to go for a quick solution. Subclass QPushButton, add a qreal "opacity" property to the button subclass (so that you can animate its value) and reimplement the paint event. In the event implementation there are two things that might work. First you might try setting up a painter and calling QPainter::setOpacity() before calling the base class implementation or if this doesn't work, call the base class implementation first and then use QPainter::setCompositionMode() to setup a composition mode that will allow you to paint the alpha channel to what is already painted using an opacity of your choice. Which composition mode to choose is left as an exercise to the reader.

bob2oneil
18th January 2011, 20:13
Following up with the suggestions from wysota (thanks wysota), I have a similar requirement when using a QLabel with a pixmap. The following code segment is my
attempt at following wysota's instructions for using a subclass in combination with a
QPropertyAnimation. I can tell from breakpoints to the setOpacity API, that the API is being called properly, but the rendering within the paintEvent never displays the QLabel pixmap with any change to the transparency. The pixmap I am using with my QLabel is a PNG with alpha content. For those of you interested in attempting a similar quest, this might be a good starting point. It would be good to the community to get this
to work as it is most useful.


m_propAnimationFadeOverscrollTop = new QPropertyAnimation(ui->overscrollTop, "windowOpacity");
m_propAnimationFadeOverscrollTop->setDuration(5000);
m_propAnimationFadeOverscrollTop->setStartValue(0.0);
m_propAnimationFadeOverscrollTop->setEndValue(1.0);
m_propAnimationFadeOverscrollTop->start();


class LabelAnimate : public QLabel
{
Q_OBJECT
Q_PROPERTY(double windowOpacity READ windowOpacity WRITE setWindowOpacity DESIGNABLE isWindow)

public:
LabelAnimate(QWidget *parent = 0): QLabel(parent),
m_alpha(0),
opacity(0.0)
{
// Start with the image completely transparent
UpdateAlphaChannel(m_alpha);
}

public:
qreal windowOpacity() const
{
return opacity;
}

void setWindowOpacity(qreal opacity)
{
opacity = qBound(qreal(0.0), opacity, qreal(1.0));
setAttribute(Qt::WA_WState_WindowOpacitySet);
}

void fadeMore()
{
if (m_alpha > 0)
{
UpdateAlphaChannel(--m_alpha);
}
}

void fadeLess()
{
if (m_alpha < 255)
{
UpdateAlphaChannel(++m_alpha);
}
}

int getAlpha() { return m_alpha; }
void setAlpha(int alpha) { UpdateAlphaChannel(alpha); }

protected:
void paintEvent(QPaintEvent *event)
{
// From wysota: setting up a painter and calling QPainter::setOpacity() before calling the base class implementation
// or if this doesn't work, call the base class implementation first and then use QPainter::setCompositionMode() to
// setup a composition mode that will allow you to paint the alpha channel to what is already painted using an opacity of
// your choice
#ifdef METHOD1
QPainter p;
p.begin(this);
p.setOpacity(opacity);
p.end();

// Call base class
QLabel::paintEvent(event);
#else
// Call base class
QLabel::paintEvent(event);

QPainter p;
p.begin(this);
p.setCompositionMode(QPainter::CompositionMode_Cle ar);
//::CompositionMode_DestinationIn);
p.end();
#endif
}

QPixmap &setAlpha(QPixmap &px, int& val)
{
QPixmap alpha = px;
QPainter p(&alpha);
p.fillRect(alpha.rect(), QColor(val, val, val));
p.end();
px.setAlphaChannel(alpha);
return px;
}

void UpdateAlphaChannel(int alpha)
{
const QPixmap *px = this->pixmap();

// Check for NULL before converting to reference
if (px != 0)
{
// Convert pointer to reference
QPixmap pm(*px);

// Change alpha using reference argument
setAlpha(pm, alpha);
}
}

private:
int m_alpha; // Current alpha level
qreal opacity; // opacity
};

Added after 1 28 minutes:

Further observation, I am not getting repaints for the pixmap as changes are made via the QPropertyAnimation to setOpacity despite my calls to update() and refresh()

Any ideas?


void setWindowOpacity(qreal opacity)
{
qDebug() << "LabelAnimate::setWindowOpacity:" << opacity;

opacity = qBound(qreal(0.0), opacity, qreal(1.0));
setAttribute(Qt::WA_WState_WindowOpacitySet);

// Force repaint
this->update();
this->repaint();
}

wysota
18th January 2011, 22:09
If you close the painter right after you change its attributes, I doubt your changes will have any effect.

Anyway, here is a quick solution using some of the additions to Qt 4.6+.

QLabel *label = new QLabel;
someLayout->addWidget(label);
label->setText("abcdefgh");
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(label);
label->setGraphicsEffect(effect);
QPropertyAnimation *anim = new QPropertyAnimation(effect, "opacity");
anim->setStartValue(0.01);
anim->setEndValue(1.0);
anim->setDuration(5000);
anim->start();

bob2oneil
19th January 2011, 20:25
Just got done implementing a fade in/fade out on a QLabel with Pixmap using wysota's direction and the QGraphicsAnimation framework, so thanks again to wysota.

My application is targeted towards embedded Linux, and therefore performance is a premium. Since I am now using portions of the QT graphics framework (and because of other requirements I have such as animated
sceen transitions) it would seem that I have moved into the graphics based world of Qt. Does this implementation decision imply any particular build option(s) for the Qt library for embedded Linux to support the graphics
engine? Are there any particular URLs that discuss optimizing Qt via build options for embedded Linux and performance tuning?

wysota
19th January 2011, 20:37
What's more important is optimizing your own application. There is not much you can do by recompiling Qt with different options.

jgoluch
8th November 2011, 15:54
Thanks for this post - this is what I needed as well! Much simpler than some of the more esoteric solutions I've seen about subclassing this and that and overriding the paint method, etc. I am fairly new to Qt so perhaps these methods were what was necessary prior to Qt 4.6??

jgoluch




If you close the painter right after you change its attributes, I doubt your changes will have any effect.

Anyway, here is a quick solution using some of the additions to Qt 4.6+.

QLabel *label = new QLabel;
someLayout->addWidget(label);
label->setText("abcdefgh");
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(label);
label->setGraphicsEffect(effect);
QPropertyAnimation *anim = new QPropertyAnimation(effect, "opacity");
anim->setStartValue(0.01);
anim->setEndValue(1.0);
anim->setDuration(5000);
anim->start();