PDA

View Full Version : How to connect QTimer with QPaintEvent?



Asus_G72GX
1st May 2012, 16:20
Good Evening!

Is it possible to connect the Qtimer with QPaintEvent. In my project I have already created the QPaintEvent, and drew the Ellipse, now I want to create the qtimer and after timeout I want that my existing ellipse will move to another place on my widget. Is it possible to make that? I have made it but my ellipse does not move. Please help me. I really hope on your help! Thanks!
widget.h


#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui>

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = 0);
~Widget();

QGridLayout *grid;
QWidget *widget1;
//QPen *pen;
QBrush *brush, *brush1;
QTimer *timer;

public slots:
void paintEvent(QPaintEvent *);
void paintEvent1(QPaintEvent *);

};

#endif // WIDGET_H


main.cpp


#include <QtGui/QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();

return a.exec();
}


widget.cpp


#include "widget.h"

Widget::Widget(QWidget *parent)
: QWidget(parent)
{
grid = new QGridLayout;
widget1= new QWidget;

timer = new QTimer(this);

grid->addWidget(widget1,0,6,0,6);
this->setLayout(grid);


QPainter painter(this);
//pen = new QPen;
brush = new QBrush;
brush1= new QBrush;
//pen->setColor(Qt::blue);
brush->setColor(Qt::red);


connect(timer, SIGNAL(timeout()), this,SLOT(paintEvent1(QPaintEvent*)));
timer->start(5);







}

Widget::~Widget()
{

}
void Widget::paintEvent(QPaintEvent *)
{

QPainter painter(this);


painter.setBrush(Qt::SolidPattern);
/*QRadialGradient radialGradient(50, 50, 50, 70, 70);
radialGradient.setColorAt(0.0, Qt::white);
radialGradient.setColorAt(0.2, Qt::green);
radialGradient.setColorAt(1.0, Qt::black);
painter.setBrush(radialGradient);*/
painter.drawEllipse(0,0,125,125);


update();



}
void Widget::paintEvent1(QPaintEvent *)
{

QPainter painter1(this);
painter1.setBrush(Qt::SolidPattern);
painter1.drawEllipse(0,0,185,185);
update();


}

Spitfire
1st May 2012, 17:52
connect( timer, SIGNAL( timeout() ), widget, SLOT( update() ) );
This will trigger paint event.

Btw I hope that you're not moving your ellipse in the paint event...

Asus_G72GX
1st May 2012, 18:07
connect( timer, SIGNAL( timeout() ), widget, SLOT( update() ) );
This will trigger paint event.

Btw I hope that you're not moving your ellipse in the paint event...
Thank you for reply! I have remake code. But Qt started to ignore qtimer, 2nd ellipse is drowing immediately. Is there any possibility to destroy first ellipse after drawing 2nd? Or maybe it is impossible in QPaintEvent. Maybe try to do some stuff with QPoint?


#include "widget.h"

Widget::Widget(QWidget *parent)
: QWidget(parent)
{
grid = new QGridLayout;
widget1= new QWidget;

timer = new QTimer(this);

grid->addWidget(widget1,0,6,0,6);
this->setLayout(grid);


QPainter painter(this);
//pen = new QPen;
brush = new QBrush;
brush1= new QBrush;
//pen->setColor(Qt::blue);
brush->setColor(Qt::red);


connect(timer, SIGNAL(timeout()), widget1,SLOT(update()));

timer->start(20);







}

Widget::~Widget()
{

}
void Widget::paintEvent(QPaintEvent *)
{

QPainter painter(this);


painter.setBrush(Qt::SolidPattern);
/*QRadialGradient radialGradient(50, 50, 50, 70, 70);
radialGradient.setColorAt(0.0, Qt::white);
radialGradient.setColorAt(0.2, Qt::green);
radialGradient.setColorAt(1.0, Qt::black);
painter.setBrush(radialGradient);*/
painter.drawEllipse(0,0,125,125);


update();



}
void Widget::update()
{

QPainter painter(this);

painter.drawEllipse(0,0,185,185);



}





Header.h


#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui>

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = 0);
~Widget();

QGridLayout *grid;
QWidget *widget1;
//QPen *pen;
QBrush *brush, *brush1;
QTimer *timer;

public slots:
void paintEvent(QPaintEvent *);
void update();

};

#endif // WIDGET_H

ChrisW67
2nd May 2012, 08:16
Some thoughts:

QWidget::update() is a slot your widget already has, not something you need to reimplement.
Calling update() inside the paintEvent() makes no sense.
Connecting the timer to a generic QWidget (that you are not painting) will not cause your widget to paint.


Here is a complete example of a custom widget: Analogue Clock Example

amleto
2nd May 2012, 09:38
some more points:

connect(timer, SIGNAL(timeout()), this,SLOT(paintEvent1(QPaintEvent*)));

you cant connect signals with X number of arguments to to slots with more than X arguments.

You shouldn't be making multiple paint event methods. THE paintEvent will always get called on update, YOUR paint event will only get called on timeout. Why should there be two? (There definitely should not be)

You don't need to 'destroy' anything in paint event - paint event always starts with a clean canvas.



But Qt started to ignore qtimer, 2nd ellipse is drowing immediately.
It is only doing what you tell it to do. You call update() in paintevent. Your misguided addition of your own update() method draws the second ellipse at the same time as the first. Please read your own code more carefully.

Spitfire
2nd May 2012, 10:05
I'm in a good mood today, so I'll give you ready-made (compilable) solution, if this isn't enough, then you need to go back to the books (you should anyway, most of stuff guys above are saying is in the documentation)


// header
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui/QMainWindow>

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow( QWidget* parent = 0 );

public slots:
void redrawEllipse( void );

protected:
void paintEvent( QPaintEvent* event );

private:
int radius;
};

#endif // MAINWINDOW_H




// implementation
#include "mainwindow.h"

#include <QPainter>
#include <QTimer>

MainWindow::MainWindow( QWidget* p )
:
QMainWindow( p ),
radius( 1 )
{
QTimer* t = new QTimer( this );
connect( t, SIGNAL( timeout() ), this, SLOT( redrawEllipse() ) );
t->start( 10 );
}

void MainWindow::redrawEllipse( void )
{
radius += 2;

if( radius > qMin( this->width()/2, this->height()/2 ) )
{
radius = 1;
}

this->update();
}

void MainWindow::paintEvent( QPaintEvent* e )
{
Q_UNUSED( e );

QPainter p( this );
p.drawEllipse( this->rect().center(), this->radius, this->radius );
}

Asus_G72GX
2nd May 2012, 12:21
Spitfire great thanks for you that you helped me with this!
Anyway I have discussed this problem with my lector he showed me that it possiblee to move ellipse if we declare a coordinates for it like a dx ,dy,x,y.
The final result must be close to this images below:
http://s019.radikal.ru/i634/1205/a8/27762ca2c7b1.jpg
http://s019.radikal.ru/i637/1205/ec/660d6e97f999.jpg

But I have collided that Qt does not see a z coordinate. So I make them by x,y. My code result is close to those sample images, but I was not able to move the ball to the right and upwards. Maybe is it possible to change the values? Thanks again!
Widget.h


#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui>

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = 0);
~Widget();

QGridLayout *grid;
//QWidget *widget1;
QPen *pen;
QBrush *brush, *brush1;
//QTimer *timer;
QMatrix matrix;

void paintEvent(QPaintEvent *);
int x;
int x2;

int y;
int y2;
int dx, dy;
int dx2, dy2;

void timerEvent(QTimerEvent *);
void timerEvent1(QTimerEvent *);
public slots:
void move();
};

#endif // WIDGET_H



Main.cpp



#include <QtGui/QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();

return a.exec();
}



Widget.cpp


#include "widget.h"


Widget::Widget(QWidget *parent)
: QWidget(parent)
{
grid = new QGridLayout;

QPainter painter(this);

//widget1= new QWidget;
//grid->addWidget(widget1,0,6,0,6);
this->setLayout(grid);

pen = new QPen;
brush = new QBrush;

//pen->setColor(Qt::blue);
brush->setColor(Qt::red);
//timer = new QTimer(this);
/*x = 10;

dx = 5;
dy = 10;
y =30;*/


x = 10;
dx = 5;
dy = 10;
y =30;


x2 = 10;
dx2 = 5;
dy2 = 10;
y2 =30;









//connect(timer, SIGNAL(timeout()), this,SLOT(move()));
//timer->start(3000);
this->startTimer(100);

}

void Widget::timerEvent(QTimerEvent *){

x = x + dx;


if(x >=165) dx = -5;
if(x <0) dx = 5;


y = y + dy;


if(y <=-165) dy = 10;
if(y >0) dy = -10;







// 2nd leg for blue ball


x2 = x2+ dx2;


if(x2 >=165) dx2 = 5;
if(x2 <0) dx2 = -5;
if(x2>5) dx2=1;


y2 = y2- dy2;


if(y2 <=-165) dy2 = 10;
if(y2 >0) dy2 = -10;
if(y2>-10) dx2=15;
/*if(y2>=100) dy2=5;
if(y2>0) dy2=-5;*/

/* y2 = y2 + dy2;

if(y2 <=100) dy2 = 1;
if(y2 >0) dy2 = -1;*/


update();
}


Widget::~Widget()
{

}
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter (this);
painter.setBrush(Qt::red);


/*QRadialGradient radialGradient(50, 50, 50, 70, 70);
radialGradient.setColorAt(0.0, Qt::white);
radialGradient.setColorAt(0.2, Qt::green);
radialGradient.setColorAt(1.0, Qt::black);
painter.setBrush(radialGradient);*/
painter.drawEllipse(x,y,40,40);
painter.setBrush(Qt::blue);
painter.drawEllipse(x2,y2,10,10);

}
void Widget::move()

{
QPainter painter (this);
painter.drawEllipse(0,0,165,165);
}

Spitfire
2nd May 2012, 15:17
You should be using OO approach.

Create a class 'ball', give it what you need and then move it around.
Parent widget can be canvas for the ball to move around.

To move ball in oposite direction, just multiply dx and/or dy by -1 every time you hit some edge.

here's example ball class:


class Ball : public QWidget
{
Q_OBJECT
public:
Ball( int dx, int dy, QWidget* parent = 0 )
:
QWidget( parent ),
dx( dx ),
dy( dy )
{
this->setFixedSize( 20, 20 );
}

public slots:
void advance( void )
{
QPoint p = this->pos();

int x = p.x() + this->dx;
if( x < 0 )
{
x = 0;
this->dx *= -1;
}
else if( x + this->width() > this->parentWidget()->width() )
{
x = this->parentWidget()->width() - this->width();
this->dx *= -1;
}

int y = p.y() + this->dy;
if( y < 0 )
{
y = 0;
this->dy *= -1;
}
else if( y + this->height() > this->parentWidget()->height() )
{
y = this->parentWidget()->height() - this->height();
this->dy *= -1;
}

this->move( x, y );
}

protected:
void paintEvent( QPaintEvent* e )
{
Q_UNUSED( e );

QPainter p( this );
QPainterPath pp;
pp.addEllipse( this->rect() );
p.fillPath( pp, Qt::red );
}

private:
int dx;
int dy;
};

Don't come back if you won't be able to figure out how to use it... ;)