PDA

View Full Version : QGraphicsItemGroup - store informations about children.



Leszek
25th October 2010, 08:55
I have QGraphicsItemGroup object with children.
I want to save this group to file, then retrives informations about group from file.

What kind of information about child items, should I save ?
Beside of pos(), shape().. should I save tranformations/parent transformations or bounding rect too ?

Thanks for reply.

wysota
25th October 2010, 11:42
You only need pos(), the type of item and a local transformation matrix of the item to be able to recreate the item back. Of course besides all the custom attributes an item may have (colour, brush, etc.).

Leszek
25th October 2010, 13:31
Thanks for reply.

So, I don`t have to store shape() of child elems ?

wysota
25th October 2010, 13:39
No, what do you need it for? The shape is strictly related to the item type, you can always recalculate it knowing positions and item types. There is a pitfall here - you might think that you need to store shape or at least boundingRect for items such as QGraphicsRectItem because the item's bounding rect can be different depending on the rectangle it represents. But in reality you don't need the boundingRect, you only need the rectangle that defines it (or the ellipse of the ellipse item or the two end points of the line item, etc.).

Leszek
25th October 2010, 17:35
Thanks, but propably description of my problem is wrong.

I`ve 3 elems. For eg. QGraphicsPathItems. Because of, that objects are grouped/ungrouped so I need to have that objects in one group.

So I create QGraphicsItemGroup object. Now, this group contains 3 objects (QGraphicsPathItems).

Storing to DB.
Group is stored to dataStream like below:



QDataStream ds;
ds << childItems().count();

BOOST_FOREACH(QGraphicsItem* item, childItems())
{
GraphicType typeChild = (GraphicType)item->type();
switch(typeChild)
{
case eShapeElem:
{
ShapeElem* shapeElem = qgraphicsitem_cast<ShapeElem*>(item);
ds << shapeElem;
//of course proper operators were created
// QDataStream &operator<<(QDataStream&, const ShapeElem*);
// QDataStream &operator>>(QDataStream&, ShapeElem*);
break;
}
.. other types
}
}


Group is read from dataStream like below:



int countChildren;
QDataStream ds;

ds >> countChildren;
for(int iIdx = 0; iIdx < countChildren....) {

ds >> typeChild;
switch(typeChild)
{
case eShapeElem:
{
item = new ShapeElem();
dataStream >> (ShapeElem*)item;
lstRetrivedChildren.add(item);
break;
}
}
}
BOOST_FOREACH(QGraphicsItem* item, lstRetrivedChildren)
addToGroup(item);


Storing ShapeElem to stream:



QDataStream ds;

ds << (qint32)type();
ds << path();


Reading ShapeElem from stream:



QPainterPath path;
QDataStream ds;

ds >> path;

setPath(path);


If I don`t save path(rect or other) of children, How I create them after load file?

Thanks!

wysota
25th October 2010, 18:41
"path" is one of the "extra attributes" you need to store of course. When talking about "shape" of graphics items I understand QGraphicsItem::shape().

By the way, your serialization solution is a bit poorly "object oriented", try something like this:


QDataStream ds(...);
ds << scene->items().count();
foreach(QGraphicsItem* item, scene->items()) {
MyBaseItemClass *myItem = qgraphicsitem_cast<MyBaseItemClass*>(item);
if(!myItem) continue;
myItem->serialize(ds); // define serialize() for each of your item classes
}

No need for any switches and such. Alternatively define streaming operators for item classes and call:

ds << *item;
or

ds >> *item;
respectively.

Leszek
25th October 2010, 19:27
Thanks! Load/Save group is working very well now.

Because of a I want to add this group to tree and shows it like a icon, I have to "draw" this group as QPixmap..

Not working. Child items have incorect position...
Code like below. (QGraphicsItemGroup isn`t added to Scene).




QGraphicsItemGroup lodedGroupFromFile; //not added to scene

QPixmap pixmap(45, 45);
QPainter painter(&pixmap);

QStyleOptionGraphicsItem opt;

BOOST_FOREACH(QGraphicsItem* item, lodedGroupFromFile->children()) {
item->paint(&painter, &opt);
}

scene->addPixmap(pixmap);


QPixmap is added to Scene, but children of group are draw incorectly(positions are incorect).

wysota
25th October 2010, 19:45
Drawing items is not as easy. Some transformations need to be done to the painter to draw the items correctly. It's best to rely on Graphics View here - call QGraphicsScene::render() with the rect containing the bounding rect of the item and all its children. To make sure no other items are drawn, hide them prior to rendering what you need.

Leszek
26th October 2010, 20:51
Thanks wysota!!!.
It was very helpfully for me. It is working now.

Group from scene is saved to file. This file contains informations about QPixmap involves with this group. So durring loading, content of object is loaded with additionally info about QPixmap. Then I use it to render object as icon.

I were confused, after read informations about differents between QImage and QPixmap,
Now durring saving object to file, informations about QPixmap is stored too.
Maybe better solution is storing QImage info instead of QPixmap?

Can I save object from scene as a icon with transparent background ?

wysota
26th October 2010, 21:08
Maybe better solution is storing QImage info instead of QPixmap?
You don't store a pixmap to a file. When you save a pixmap, its image representation is saved instead.


Can I save object from scene as a icon with transparent background ?
If your scene has transparent background and the pixmap you draw on is transparent then after calling QGraphicsScene::render() you should have a pixmap with transparent background.

Leszek
27th October 2010, 19:46
Thanks !!! Now I understand it. :)

Last question in this thread(I promise ;) )

How can I make something like "clone" of QGraphicsItem ?
Copy contructor is private...
By "clone" I understand exactly the same object(copy of source object), but not in memmory of course.

wysota
27th October 2010, 19:48
You have to implement that yourself by copying all relevant information from the original to the copy. It's easiest to do that with serialization/deserialization which works essentially like copy & paste.