Я использую QT QGraphicsScene
класс, добавляя предопределенные объекты такой как QGraphicsRectItem
, QGraphicsLineItem
, и т.д. и я хочу сериализировать содержание сцены к диску. Однако основа QGraphicsItem
класс (который другие объекты я использую, происходят из) не поддерживает сериализацию, таким образом, я должен прокрутить свой собственный код. Проблема состоит в том, что весь доступ к этим объектам через основу QGraphicsItem
указатель, таким образом, код сериализации я имею, ужасен:
QGraphicsScene* scene = new QGraphicsScene;
scene->addRect(QRectF(0, 0, 100, 100));
scene->addLine(QLineF(0, 0, 100, 100));
...
QList<QGraphicsItem*> list = scene->items();
foreach (QGraphicsItem* item, items)
{
if (item->type() == QGraphicsRectItem::Type)
{
QGraphicsRectItem* rect = qgraphicsitem_cast<QGraphicsRectItem*>(item);
// Access QGraphicsRectItem members here
}
else if (item->type() == QGraphicsLineItem::Type)
{
QGraphicsLineItem* line = qgraphicsitem_cast<QGraphicsLineItem*>(item);
// Access QGraphicsLineItem members here
}
...
}
Это не хороший код, по моему скромному мнению. Так, вместо этого я мог создать класс ABC как это:
class Item
{
public:
virtual void serialize(QDataStream& strm, int version) = 0;
};
class Rect : public QGraphicsRectItem, public Item
{
public:
void serialize(QDataStream& strm, int version)
{
// Serialize this object
}
...
};
Я могу затем добавить использование объектов Rect QGraphicsScene::addItem(new Rect(,,,));
Но это действительно не помогает мне, поскольку следующее откажет:
QList<QGraphicsItem*> list = scene->items();
foreach (QGraphicsItem* item, items)
{
Item* myitem = reinterpret_class<Item*>(item);
myitem->serialize(...) // FAIL
}
Каким-либо путем я могу сделать эту работу?
Я согласен с другими постерами, QGraphicsItem действительно можно рассматривать как элемент представления, и поэтому разделение данных модели в собственный класс, вероятно, было бы лучше.
Тем не менее, я думаю, что ваше падение вызвано неправильным приведением.
Если вы сделаете следующее:
Rect *r = new Rect();
QGraphicsItem *qi = reinterpret_cast<QGraphicsItem*>(r);
QGraphicsRectItem *qr = reinterpret_cast<QGraphicsRectItem*>(r);
Item *i = reinterpret_cast<Item*>(r);
qDebug("r = %p, qi = %p, qr = %p, i = %p", r, qi, qr, i);
Вы должны увидеть, что r == qi, r == qr, но r != i. Если вы подумаете о том, как объект, который наследуется множественным образом, представлен в памяти, то первый базовый класс будет первым в памяти, второй базовый класс - вторым, и так далее. Поэтому указатель на второй базовый класс будет смещен на [приблизительно] размер первого базового класса.
Поэтому, чтобы исправить ваш код, я думаю, вам нужно сделать что-то вроде:
QList<QGraphicsItem*> list = scene->items();
foreach (QGraphicsItem* item, items)
{
Rect* myrect = reinterpret_class<Rect*>(item); // needed to figure out the offset to the Item part
Item* myitem = reinterpret_class<Item*>(myrect);
myitem->serialize(...);
}
Это одна из многих причин, по которым я предпочитаю избегать множественного наследования, когда это возможно. Я настоятельно рекомендую разделять данные модели, как было рекомендовано ранее.
Если вы действительно хотите сериализовать эти элементы, создайте
QDataStream &operator<<(QDataStream &, const AppropriateSubclass&);
QDataStream &operator>>(QDataStream &, AppropriateSubclass&);
для каждого из подклассов QGraphicsItem
, которые вы хотите сериализовать, эти функции не являются функциями-членами. Этот подход также объясняется в документации QDataStream
Но я поддерживаю ответ Стивенса, вы можете рассмотреть возможность извлечения фактических данных из сцены и помещения их в отдельный класс модели
. Сериализация QGraphicsItem
- не лучшая идея. QGrahpicsScene
должен представлять ваши данные. Вместо сериализации представления лучше сериализовать данные / модель вашего приложения.
Если вы хотите записать расположение графических объектов, возможно, вы можете использовать пользовательский QGraphicsItem
и нарисовать в QPicture .