Сериализация содержания QGraphicsScene

Я использую 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
}

Каким-либо путем я могу сделать эту работу?

8
задан Rob 8 June 2010 в 18:01
поделиться

3 ответа

Я согласен с другими постерами, 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(...);
}

Это одна из многих причин, по которым я предпочитаю избегать множественного наследования, когда это возможно. Я настоятельно рекомендую разделять данные модели, как было рекомендовано ранее.

3
ответ дан 5 December 2019 в 23:13
поделиться

Если вы действительно хотите сериализовать эти элементы, создайте

QDataStream &operator<<(QDataStream &, const AppropriateSubclass&);
QDataStream &operator>>(QDataStream &, AppropriateSubclass&);

для каждого из подклассов QGraphicsItem, которые вы хотите сериализовать, эти функции не являются функциями-членами. Этот подход также объясняется в документации QDataStream

Но я поддерживаю ответ Стивенса, вы можете рассмотреть возможность извлечения фактических данных из сцены и помещения их в отдельный класс модели

.
0
ответ дан 5 December 2019 в 23:13
поделиться

Сериализация QGraphicsItem - не лучшая идея. QGrahpicsScene должен представлять ваши данные. Вместо сериализации представления лучше сериализовать данные / модель вашего приложения.

Если вы хотите записать расположение графических объектов, возможно, вы можете использовать пользовательский QGraphicsItem и нарисовать в QPicture .

1
ответ дан 5 December 2019 в 23:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: