PDA

View Full Version : How do I draw an image in GraphicsView? It should be simple, right?



swbluto
21st October 2009, 23:46
Okay, so I'm looking for a barebone example of how to draw an image at a given position in graphicsView. I've tried to study the Canvas and AsteroidsPort examples to get an idea of what's going on, but it seems they're adding complexity that I won't need and I'm having trouble deciphering the necessary from the unnecessarily complex parts.

Basically, I started out with a rectangle drawing code to get an idea of what's going on.


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

QApplication app(argc, argv);

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

QGraphicsEllipseItem *item = new QGraphicsEllipseItem( 0, &scene );
item->setRect( -50.0, -50.0, 50, 100.0 );

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

return app.exec();
}


This worked great and all and I think I got an idea of what's going on. You create a generic graphics item, add the graphics item to the scene, set the QGraphicsView to what the scene has and then show it.

So using this, I created a the following code to display an image.



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

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

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);

QGraphicsPixmapItem *myI = new QGraphicsPixmapItem(0, &scene);

QPixmap pix;
pix.fromImage( *myImg, Qt::AutoColor );

myI->setPixmap(pix);


scene.addItem(myI);
myI->setPos(50, 50);
myI->setZValue(50);


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

return app.exec();
}


So instead of a rectangle item, I have to create a QGraphicsPixmapItem for pictures. To load the picture, I apparently had to create a QImage and then use the loading function, and then get the pix from that. I add it to the scene, set position, let the scene be viewed from the QGraphicsView and Voila! Nothing but empty whiteness. Where's my image?

Can anyone spot what might be so incredibly wrong with my code? I think I made sure the image was in the right directory, so I doubt it's not finding the picture.

wysota
21st October 2009, 23:54
QPixmap::fromImage() is a static method that returns the pixmap which you need to assign to something. Take a look at its docs.

swbluto
22nd October 2009, 00:26
Thanks!

I changed line 23 from


pix.fromImage( *myImg, Qt::AutoColor );

to


pix = pix.fromImage( *myImg, Qt::AutoColor );

I actually copied that snippet from somewhere online, so I assumed they knew what they were doing. :o

It seems to load now!

Now, if I want to constantly update the positioning of the image (it'll change depending on certain external events - it could be keyboard or mouse events), do I have to derive a class from the QGraphicsItem and overwrite the paint function? Is there some way to do it without deriving a class?

(I'll probably end up deriving a class anyways, but just curious if I can get something done with some simple code).

Also, would anyone recommend GraphicsView for my application? I'm looking at making a 2d tile based world that one could look around by dragging the mouse, but I'm not sure if GraphicsView, OpenGL or some other QTechnology would be more appropriate. I still want to have GUI user interface elements in other parts of the window, but I think QT's integration with GL makes this possible. Overall, I want it to be as simple and RAD as possible, but yet I don't want the graphics to stutter. The tiles are going to be 256x256 pixels (or something like that) and there can be anywhere from 3x3 tiles at a time to 6x6 tiles at a time, depending on screen resolution. The tiles on the immediate outside are going to be preloaded to minimize disruption.

Effectively, think of something like Google Maps, except more natively than web technology.

spud
22nd October 2009, 07:46
I did something like that once. I ended up drawing the tiles in the background like this:


void MapView::drawBackground(QPainter* painter, const QRectF & rect)
{
QPointF topLeft = mapToScene(0,0);
QPointF bottomRight = mapToScene(viewport()->width(),viewport()->height());
QPointF size = bottomRight-topLeft;
qreal scaley = viewport()->height()/size.y();
int zoom = qBound(0, (int)floor(log2(scaley)), 20); // upsampling
//int zoom = qBound(0, (int)ceil(log2(scaley)), 20); // downsampling
int scaleFactor = 1<<zoom;
double factorX = qreal(0x100000>>zoom)/(0x1000);

int xbegin = qBound(0, (int)floor(rect.left ()* scaleFactor/SceneSize), scaleFactor);
int xend = qBound(0, (int)ceil (rect.right ()* scaleFactor/SceneSize), scaleFactor);
int ybegin = qBound(0, (int)floor(rect.top ()* scaleFactor/SceneSize), scaleFactor);
int yend = qBound(0, (int)ceil (rect.bottom()* scaleFactor/SceneSize), scaleFactor);

for(int y=ybegin; y<yend; y++)
{
for(int x=xbegin; x<xend; x++)
{
QImage pixmap = downloader->requestMap(zoom, x, y);
painter->drawImage(QRectF( qreal(x*SceneSize)/scaleFactor, qreal(y*SceneSize)/scaleFactor, factorX, factorX), pixmap, pixmap.rect());
}
}
}
Sorry about the lack of comments, but you should get the idea.
requestMap(zoom, x,y) returns a tile downloaded from http://c.tile.openstreetmap.org/<zoom>/<x>/<y>.png (the same format google maps use)
Then zooming is implemented through GraphicsView::scale() and panning through QGraphicsView::ScrollHandDrag.

It works perfectly smooth with or without OpenGL as long as the calls to requestMap() are non blocking.(i.e. returns a blank pixmap if the download isn't ready)