PDA

View Full Version : How to change position of Qgraphicsview image in real-time?



swbluto
24th October 2009, 05:32
Hello, I recently figured out how to draw an image but now I'm trying to be able change the position of the image "whenever I want"/i.e. real time. I tried to by changing the position in a loop in the main file, but it just seemed to make the window freeze.

So, can someone give me an idea of what's going on? I tried studying the examples but the layers and layers of abstractions seem to be hiding the fundamentals.

So, I have to create a class that extends the Qgraphicsitem and use that to create the Qpixmap item. And, then I have to overwrite the paint function that draws the image? And then after that, I can change the position of the QPixmap whenever I want and the position will automatically change in the scene?

Just curious if I'm getting this straight.

swbluto
24th October 2009, 08:38
I was looking at the asteroids example, and I think I got to the root of what caused it to move. Apparently there's a "moveBy" function and I assume an overwritten paint function does the actual painting (refreshing the painting).

Searching online, it appears this is a function from QCanvasItem but I think that belongs to QCanvas and I thought QCanvas was being antiquated in favor of QGraphics? So, what the modern form of doing this? I don't really like how all of the "QGraphicsItem" examples are just ports from QCanvas, so it doesn't seem like I can learn the "proper way" to do this with QGraphics.

axeljaeger
24th October 2009, 14:16
If you create a loop that does something, it will block your GUI, so this is expected behaviour.

The proper way would be either to implement advance() in the graphic item or move it in a slot that is periodically triggered by a QTimer.

swbluto
24th October 2009, 23:45
Seeing how advance() is a function of QGraphicsItem....

Would I sub-class QGraphicsItem and then over-ride the advance and paint function to customize?

And then in the advance function, I would manually use the setPos to change the position of the image?

And then in the paint function, I would just call "drawImage" or something similar to redraw the image?

axeljaeger
25th October 2009, 00:03
Yes, indeed.

swbluto
25th October 2009, 02:52
Ok, so I got the code set up and it builds fine but... it's not moving, although the image does show. Here's the code...

I programmed it to just move back and forth from one spot to the next on each advance, so maybe it's just moving by sooo fast that it appears to stay in one position? :confused:



#include <QApplication>
#include <QGraphicsEllipseItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <qdatetime.h>
#include <qmainwindow.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qpainter.h>
#include <qprinter.h>
#include <qlabel.h>
#include <qimage.h>
#include <qpixmap.h>
#include <QMouseEvent>
#include <QStyleOptionGraphicsItem>
#include <qdebug.h>
#include <stdlib.h>

QString myImgName = "myimg.png";
static QImage *myImg;

static const int imageRTTI = 984376;

class ImageItem: public QGraphicsRectItem
{
public:
ImageItem( QImage img );
int rtti () const { return imageRTTI; }
void advance(int phase);
protected:
void paint( QPainter *, const QStyleOptionGraphicsItem *option, QWidget *widget );
private:
QImage image;
QPixmap pixmap;
int state;
};


void ImageItem::advance(int phase)
{
if(state==0)
{
moveBy(0,30);
state = 1;
}
else
{
moveBy(0,-30);
state=0;
}
}


ImageItem::ImageItem( QImage img )
: image(img)
{
state = 0;
setRect(0, 0, image.width(), image.height());
setFlag(ItemIsMovable);
pixmap = pixmap.fromImage(image, Qt::OrderedAlphaDither);

}

void ImageItem::paint( QPainter *p, const QStyleOptionGraphicsItem *option, QWidget * )
{
p->drawPixmap( option->exposedRect, pixmap, option->exposedRect );
}

int main( int argc, char **argv )
{

QApplication app(argc, argv);

QGraphicsScene scene;
scene.setSceneRect( -100.0, -100.0, 200.0, 200.0 );

myImg = new QImage;
myImg->load(myImgName);

QAbstractGraphicsShapeItem* i = new ImageItem(*myImg);
scene.addItem(i);
i->setPos(-50,-50);

QGraphicsView view( &scene );
view.setRenderHints( QPainter::Antialiasing );
view.show();

return app.exec();
}

swbluto
25th October 2009, 02:56
Okay, I just changed the code so that instead of moving back and forth, it constantly goes in one direction. So, if it was going "so fast", it would've disappeared. Well, it didn't, so that tells me advance is not being executed, or the image isn't being updated, or something.

swbluto
25th October 2009, 08:03
Just got it to work!!! :D

Apparently I had to stick something like...



QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance()));
timer.start(100);


in the main function to get it to operate correctly. If my intuition is correct, timeout is called when the timer counts down from 100 to 0 and it then calls advance(), and then the timer starts again at 100 and repeats the cycle. So, it seems to be a way for everything to synchronize.

Now, it's time for some real development to begin.:p




#include <QApplication>
#include <QGraphicsEllipseItem>
#include <QGraphicsScene>
#include <QGraphicsView>

#include <qdatetime.h>
#include <qmainwindow.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qpainter.h>
#include <qprinter.h>
#include <qlabel.h>
#include <qimage.h>
#include <qpixmap.h>
#include <QMouseEvent>
#include <QStyleOptionGraphicsItem>
#include <qdebug.h>
#include <stdlib.h>
#include <qtimer.h>

QString myImgName = "myimg.png";
static QImage *myImg;


static const int imageRTTI = 984376;


class ImageItem: public QGraphicsRectItem
{
public:
ImageItem( QImage img );
int rtti () const { return imageRTTI; }
void advance(int phase);
protected:
void paint( QPainter *, const QStyleOptionGraphicsItem *option, QWidget *widget );
private:
QImage image;
QPixmap pixmap;
int state;
};


void ImageItem::advance(int phase)
{
moveBy(0,1);
}


ImageItem::ImageItem( QImage img )
: image(img)
{
state = 0;
setRect(0, 0, image.width(), image.height());
setFlag(ItemIsMovable);
#if !defined(Q_WS_QWS)
pixmap = pixmap.fromImage(image, Qt::OrderedAlphaDither);
#endif
}

void ImageItem::paint( QPainter *p, const QStyleOptionGraphicsItem *option, QWidget * )
{
// On Qt/Embedded, we can paint a QImage as fast as a QPixmap,
// but on other platforms, we need to use a QPixmap.
#if defined(Q_WS_QWS)
p->drawImage( option->exposedRect, image, option->exposedRect, Qt::OrderedAlphaDither );
#else
p->drawPixmap( option->exposedRect, pixmap, option->exposedRect );
#endif
}

int main( int argc, char **argv )
{

QApplication app(argc, argv);

QGraphicsScene scene;
scene.setSceneRect( -100.0, -100.0, 200.0, 200.0 );

myImg = new QImage;
myImg->load(myImgName);


QAbstractGraphicsShapeItem* i = new ImageItem(*myImg);
scene.addItem(i);
i->setPos(-50,-50);

QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance()));
timer.start(100);

QGraphicsView view( &scene );
view.setRenderHints( QPainter::Antialiasing );
view.show();

return app.exec();
}