PDA

View Full Version : Design question: Optimize item layout management in a QGraphicsScene



Lykurg
4th April 2008, 17:46
Hi,

I have a class with a QGraphicsView/QGraphicsScene (m_scene) and a QList (m_itemList) which holds all items of the scene. (The items content can be altered by the user which can modify the items bounding rect.) Because I want to layout the items dynamically I have a slot called updateItemLayout() which orders the items in a "line layout" with automatic line break to avoid showing the horizontal scrollbar. So far all is ok, but how to call the slot best?

Connecting the changed() and sceneRectChanged() signal from the QGraphicsScene to my slot triggers the slot too often. E. g. the pure selection of an item triggers it, but the bounding rect of the item is not changed, so calling the layout-slot is not necessary.
Give each item a pointer to the class so that the item can call the layout-slot when needed. Guess that that solution is bad code designing.
Modify the items with signal, which are emited when the bounding rect changes. Problem: Items are not fix. User can add and delete items, so I need to add and delete connections quite often.


Is there any other possibility? Or which of the above is the best one?

Thanks,
Lykurg

P.s.: All items (e.g. TextItemText) are subclassed form pure virtual class "AbstractTextItem" which has QGraphicsItem as base.


void <class>::updateItemLayout()
{
qreal gWidth = 0, gHeight = 0, heightDiff = 0, itemWidth = 0, padding = 3;
TextItemText it;
it.setFont(m_fontGraphicsView);
qreal lineHeight = it.boundingRect().height() + 2;

for (int i = 0; i < m_itemList.size(); ++i)
{
AbstractTextItem* item = m_itemList.at(i);
heightDiff = (lineHeight - item->sceneBoundingRect().height()) / 2;
itemWidth = item->sceneBoundingRect().width();
if (gWidth != 0 && (gWidth+itemWidth+3*padding) > ui.view->width())
{
gHeight += lineHeight;
gWidth = 0;
}
item->setPos(gWidth, gHeight+heightDiff);
gWidth += itemWidth;
}

QRectF tmp = m_scene->itemsBoundingRect();
tmp.moveLeft(-padding);
tmp.moveTop(-padding);
m_scene->setSceneRect(tmp);
}

aamer4yu
4th April 2008, 20:10
Did you have a look at QGraphicsItem::itemChange ??
May be it will solve your purpose :)

Lykurg
4th April 2008, 20:39
Did you have a look at QGraphicsItem::itemChange ??

Nice, I havn't seen this yet, but unfortunately GraphicsItemChange has no value ItemBoundingRectChange.
Meanwhile I have think of a other solution, which seem to fit best my purpose:
I subclass QGraphicsScene and put there my updateItemLayout() function. If an item changes it size (I will put a routine into my custom items) i call the function myself in the item via scene()->updateItemLayout().

Thanks for mentioning QGraphicsItem::itemChange

Lykurg

aamer4yu
4th April 2008, 20:51
You can do this...
from QGraphicsItem::itemChange , emit a signal layoutChanged(this) . Catch this signal in the handling class.
from the graphicsItem pointer you can retrieve the bounding rectangle

Also see the various options that GraphicsItemChange has .