PDA

View Full Version : Dynamic adding of widgets to QGraphicsScene on the fly



Mr_Cloud
26th April 2014, 17:38
Hello,

I'm trying to make a simple game to learn how to use QGraphicsScene. I want it to be the typical asteroid shooting game where you are a ship and you fly around.

What I'm interested in learning how to do is also to dynamically add and control items in the QGraphicsScene. Currently, I am aware that we can do something along the lines of


QGraphicsPixmapItem *bkgimg = scene->addPixmap(pixmap);//pretty background image

(pixmap was defined earlier) and then we can say


bkgimg->setPos(0,0);

if we want to move it around.


My question is can I add an item to QGraphicsScene sort of like this:

scene->addItem(QGraphicsItem(300,300));

where 300,300 are the x and y positions and be able to modify that item later on? Or perhaps there is a way to dynamically declare objects and add them to QGraphicsScene and use signals/slots to update their position?

Thanks

d_stranz
27th April 2014, 02:38
My question is can I add an item to QGraphicsScene sort of like this:

No, not like that. The code you posted won't compile.

You can of course add an item that is a subclass of QGraphicsItem dynamically. If what you are asking is can you add a QGraphicsItem instance itself to the scene and change that to a specific type of graphics item later, no, you can't. You can't create an instance of QGraphicsItem itself because it is an abstract class. But neither can you create an instance of some concrete graphics item, add it to the scene, retrieve it later and change that same instance to an object of a different type. You can remove the first object and add the second object.

You can change the properties of a graphics item instance dynamically, for example the position, size, z-value, pen, brush. etc. without adding and removing things

If you want a graphics item to be able to handle or send signals, then you need to derive your class from QGraphicsObject, which inherits QObject. You can then do almost anything you want with custom signals and slots.

Mr_Cloud
27th April 2014, 05:35
Thank you for your reply, d_stranz, it is a little clearer now.

My next question was going to be what if I have a check for an event to occur and if a certain criterion is met, I want to spawn a graphics object such as an enemy on the screen at some position; do I have to define a preset number of enemy objects and somehow consecutively set enemy1 at pos (x1,y1), enemy2 at pos(x2,y2). But I stumbled on this (http://www.cplusplus.com/forum/beginner/69766/) thread and I think I figured out how to use vectors for that.

I could define a class playerDraw : public QWidget type and create a vector<QWidget*> enemies container to which I'll be able to pass off push_back(new playerDraw(x,y), then just a simple for loop to scene->addWidget(enemies[j]) and set their position. I think that is quite an elegant solution.

Thoughts?

anda_skoa
27th April 2014, 13:57
You probably don't want widgets as you game objects but otherwise that sounds ok.

Cheers,
_

Mr_Cloud
30th April 2014, 11:49
Ok I've been learning how to add widgets dynamically to QGraphicsScene and I almost got it. I have encountered an issue when trying to set the position of a widget, as the (0,0) point of the widget is in the top left corner and I need it to be in the center.

I have

QWidget *mySprite;//it has the paintEvent which draws everything I need
QGraphicsWidget *wdg=scene->addWidget(mySprite);

//but now when I try to
wdg->rotate(90);
//it does so about top left point (0,0). And doing

wdg->translate(100,100);
//doesn't seem to help. It actually appears that it moves the whole widget instead of moving the reference point

Any ideas how I can set the center point of my QGraphicsWidget?

Thanks

Edit: Also, how should we use QVector<QGraphicsWidget*> when trying to access properties of the graphics widgets? Should we use a for loop or should we use a foreach loop? (I've never used the latter before)

anda_skoa
30th April 2014, 13:36
You are probably looking for setTransformOriginPoint()

But I still don't get why you want widgets. What kind of standard UI elements are those made of?

Cheers,
_

Mr_Cloud
30th April 2014, 15:51
Brilliant dot exe. Thank you for that.



But I still don't get why you want widgets. What kind of standard UI elements are those made of?

Just ellipses and lines at the moment. You're right, I shouldn't limit myself to QWidgets, but these seem to do the job for now.


Edit: Also, how should we use QVector<QGraphicsWidget*> when trying to access properties of the graphics widgets? Should we use a for loop or should we use a foreach loop? (I've never used the latter before)

Any ideas about this one, anda_skoa? And what I mean by this is that does a simple for (int i=0;i<myVector.size();i++){//do stuff;} work for this seemingly unusual (different, at least to me) QVector? Thanks

anda_skoa
30th April 2014, 18:00
Just ellipses and lines at the moment. You're right, I shouldn't limit myself to QWidgets, but these seem to do the job for now.

I am afraid I don't understand. There is no ellipse widget.


J
Any ideas about this one, anda_skoa?

Makes really no difference on a vector, use whatever you prefer.

Cheers,
_

Mr_Cloud
1st May 2014, 02:28
I am afraid I don't understand. There is no ellipse widget.



class spriteDraw : public QWidget
{
spriteDraw();

protected:
void paintEvent(QPaintEvent *event){//paint me like one of your french girls;}

private:
QPainterPath c;
QPainter painter;
}

anda_skoa
1st May 2014, 14:14
If you use custom painting, why not simply subclass QGraphicsItem?
Or using a QGraphicsEllipseItem for the ellipse, QGraphicLineItem or QGraphicPolygonItem for lines, or more generically QGraphicsPathItem

Cheers,
_

Mr_Cloud
2nd May 2014, 07:53
I can see why you're suggesting I use QGraphicsItem. It looks like it's much easier to handle than a QWidget. I think I'll do that.

Seeing as setRotation() is not available for QGraphicsItem, I'll implement the rotation in the void QGraphicsItem::paint().


Regards,
Mr_Cloud

anda_skoa
2nd May 2014, 10:35
Seeing as setRotation() is not available for QGraphicsItem.

No?
http://qt-project.org/doc/qt-4.8/qgraphicsitem.html#setRotation

Cheers,
_

Mr_Cloud
3rd May 2014, 16:46
You were right, anda_skoa, I was able to setRotation(). Code-wise everything compiles. It's much easier to use QGraphicsItem, thank you.

I have an issue with loading a jpeg as the background though. On the machine that has the Qt environment set up (4.8.5, MSVC 2013, environment variables set) the jpeg loads fine, but as soon as I run the exe on a PC without Qt/MSVC installed, the jpg loading into memory fails.

I've checked DLL dependencies with ProcessExplorer on Qt machine and besides the usual QtCore4 and QtGui4 DLLs, it also loads qjpeg4.dll from /qt/plugins/imageformats/ to handle the background. This DLL is not loaded nor mentioned on the non-Qt machines. How come this is happening?

Here is how I load the jpg:


#include <QImageReader>
#include <QPixmap>

QImageReader reader("bkg.jpg");
QSize imageSize = reader.size();
imageSize.scale(600,600, Qt::IgnoreAspectRatio);
reader.setScaledSize(imageSize);
QPixmap pixmap=QPixmap::fromImage(QImage(reader.read()));
scene->addPixmap(pixmap);



I tried scene->addPixmap(QPixmap::fromImage(QImage("bkg.jpg"))); for comparison and still no avail. Any ideas?


Regards,
Mr_Cloud

anda_skoa
3rd May 2014, 17:50
Do you have the image format plugin for JPEG correctly as part of your deployment?

Cheers,
_

Mr_Cloud
3rd May 2014, 17:57
I don't think so buddy. How do I do that?

anda_skoa
3rd May 2014, 19:05
See http://qt-project.org/doc/qt-4.8/deployment-plugins.html

Cheers,
_

Mr_Cloud
4th May 2014, 12:48
Thanks for that. I think I'll go with the dynamic way of just copying /imageformats/ with what dependencies I need in it.

Once again, thank you for your guidance, anda_skoa. It means a lot.


Regards,
Mr_Cloud