[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Re: Animation with QPainter
From:       Matt Newell <newellm () blur ! com>
Date:       2006-11-30 19:10:37
Message-ID: 200611301110.37138.newellm () blur ! com
[Download RAW message or body]

> Hm... with a Qtimer triggered draw function that draws the new pixmap and
> bitBlt() it to the QWidget, there shouldn't be any flickering anyway.
It's qt3, there's no double buffering, so the flickering is caused by the 
background getting cleared to white(where the blue rect was), before the blit 
happens.

> Alright, had a look at the demo code. Don't call update() in move().
> Instead, draw your pixmap in move() and bitBlt() it.
>
That's (almost)exactly what he's doing, update simply calls paint event and 
the drawPixmap call is basically a bitBlt, only can actually be faster 
because it can be accelerated by the window system.

> On the other hand, there seems to be a better way to do it. You are wasting
> a lot of CPU cycles for redrawing the pixmap over and over. If your
> metronome isn't too big so that memory isn't an issue, you could pre-draw a
> couple of pixmaps and simply bitBlt() the next one in move().
He's not regenerating the pixmap each time, just clearing the background and 
blitting it.  The only cpu cycles to be saved is the wasted background 
painting where the rect is going to be painted.

Here's the example modified to do either approach i mentioned.  There is room 
for improvement in the double buffer method by not allocating the pixmap each 
time.  Since Qt3 doesn't seem to take vsync into account when painting, there 
is still some tearing evident, but there's no easy way around that.

If the drawing was more complicated and required much raw pixel manipulation, 
then it would be better to draw into a qimage instead of a qpixmap.

Matt

["animationtest.cpp" (text/x-c++src)]

#include <qapplication.h>
#include <qwidget.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qlabel.h>
#include <qtimer.h>

static bool doubleBuffer = true;

class TestAnimation : public QWidget
{
	Q_OBJECT
	public:
		TestAnimation(QWidget *parent = 0, const char *name = 0);
		~TestAnimation();
		
		void drawSurface(QPainter *);
	private:
		QPixmap rect;
		
	protected:
		void paintEvent(QPaintEvent *);
		
	private slots:
		void move();
};

TestAnimation::TestAnimation(QWidget *parent, const char *name) :
	QWidget(parent, name, Qt::WNoAutoErase)
{
	setBackgroundColor(QColor(255, 255, 255));
	resize(500, 25);
	
	rect.resize(50, 25);
	rect.fill(Qt::blue);
	
	static QTimer timer;
	connect(&timer, SIGNAL(timeout()), this, SLOT(move()));
	timer.start(10);
}

TestAnimation::~TestAnimation()
{

}

void TestAnimation::drawSurface(QPainter * painter)
{
	static int rectPosition = 0;
	static int direction = 1;
	static int rectWidth = 50;
	
	if(rectPosition <= 0) {
		direction = 1;
	} else if(rectPosition >= width() - rectWidth) {
		direction = -1;
	}
	
	rectPosition += direction * 5;
	
	// Paint the blue rect
	painter->drawPixmap(rectPosition, 0, rect);

	// Clear the background, everywhere BUT the blue rect
	QRegion bg(QRect(QPoint(0,0),size()));
	painter->setClipRegion( bg.subtract( QRegion( QRect( rectPosition, 0, rect.width(), \
rect.height() ) ) ) );  painter->fillRect( QRect( 0, 0, width(), height() ), \
Qt::white ); }

void TestAnimation::paintEvent(QPaintEvent *)
{
	if( doubleBuffer ) {
		QPixmap pix(size());
		{
			QPainter painter(&pix);
			drawSurface( &painter );
		}
		QPainter p(this);
		p.drawPixmap(0,0,pix);
	} else {
		drawSurface( &QPainter(this) );
	}
}

void TestAnimation::move()
{
	update();
}

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	TestAnimation testAnimation(0);
	app.setMainWidget(&testAnimation);
	testAnimation.show();
	return app.exec();
}

#include "animationtest.moc"



>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic