Search code examples
c++qtqt4fedoraqpainter

Fading away widget in QT C++


I want to make a simple QWidget which is a simple rectangle fade away. The main problem is that the paint event paint at the same place every time in fact making the effect opposite, it make the colour stronger. Is there any way of achieving this functionality? Could you maybe provide some simple example?

My code: `

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    void paintEvent(QPaintEvent*);
    ~Widget();

private:
    Ui::Widget *ui;
    int alfa;
    int i;
    QTimer time;

};

#endif // WIDGET_H

`

and the cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QColor>
#include <QPainter>
#include <QBrush>
#include <QTimer>
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent,Qt::Popup | Qt::FramelessWindowHint),
    ui(new Ui::Widget),
    time()
{
    ui->setupUi(this);
    setAttribute(Qt::WA_NoSystemBackground, true);
    setAttribute(Qt::WA_TranslucentBackground, true);
    setAttribute(Qt::WA_PaintOnScreen);
    time.setInterval(500);
    time.start();
    connect(&time,SIGNAL(timeout()),this,SLOT(update()));
    alfa=100;
    i=0;

}

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    int rectBase = height();

    QColor c(255,0,255);
    alfa=alfa-(i*10);
    c.setAlpha(alfa);
    qDebug()<<c.alpha();
    i++;

    painter.setBrush(QBrush(c));
    painter.drawRect(0, 0, width(),height());


}

Widget::~Widget()
{
    delete ui;
}

Solution

  • You shouldn't rely on QWidget::paintEvent() to change your alpha level, since it can be called less or more than you want (multiple update() calls may result in only one paintEvent() and paintEvent() may be called when you don't expect it).

    So a more reliable way to get to the result, is have a separate slot where you decrease the alpha level and then call update(). Your class definition might look like this:

    class Widget : public QWidget
    {
        Q_OBJECT
    public:
        Widget( QWidget * inParent );
    
    private:
        void paintEvent(QPaintEvent *);
    
    private slots:
        void animate();
    
    private:
        QTimer * mTimer;
        int mAlpha;
    };
    

    And the declaration:

    Widget::Widget( QWidget * inParent )
        :
          QWidget( inParent ),
          mTimer( new QTimer( this ) ),
          mAlpha( 255 )
    {
        setAttribute(Qt::WA_NoSystemBackground, true);
        setAttribute(Qt::WA_TranslucentBackground, true);
        setAttribute(Qt::WA_PaintOnScreen);
        mTimer->setInterval( 40 );
        mTimer->setSingleShot( false );
        connect( mTimer, SIGNAL(timeout()), this, SLOT(animate()) );
        mTimer->start();
    }
    
    void
    Widget::paintEvent(QPaintEvent *)
    {
        QPainter painter(this);
        painter.setBrush( QColor(255,0,255,mAlpha ) );
        painter.drawRect(rect());
    }
    
    void
    Widget::animate()
    {
        if ( mAlpha > 0 )
        {
            mAlpha -= 3;
        }
        else
        {
            mTimer->stop();
        }
        update();
    }
    

    Notice that I did decrease the interval of the timer. You only called an update() every half a second. That typically does not result in a smooth animation.