首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >序列化QGraphicsScene内容

序列化QGraphicsScene内容
EN

Stack Overflow用户
提问于 2010-06-09 02:01:36
回答 4查看 2.5K关注 0票数 8

我正在使用Qt QGraphicsScene类,添加预定义的项目,如QGraphicsRectItemQGraphicsLineItem等,并希望将场景内容序列化到磁盘。但是,基类QGraphicsItem (我使用的其他项都是从该类派生而来)不支持序列化,所以我需要编写自己的代码。问题是所有对这些对象的访问都是通过一个基本的QGraphicsItem指针,所以我的序列化代码是可怕的:

代码语言:javascript
运行
复制
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类:

代码语言:javascript
运行
复制
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
  }
  ...
};

然后,我可以使用QGraphicsScene::addItem(new Rect(,,,));添加Rect对象

但这并不能真正帮助我,因为下面的代码会崩溃:

代码语言:javascript
运行
复制
QList<QGraphicsItem*> list = scene->items();
foreach (QGraphicsItem* item, items)
{
  Item* myitem = reinterpret_class<Item*>(item);
  myitem->serialize(...) // FAIL
}

有没有办法让这件事行得通?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-06-16 02:45:04

我同意其他发帖者的观点,QGraphicsItem实际上可以被视为一个视图项目,因此将模型数据分离到它自己的类中可能会更好。

也就是说,我认为你的崩溃是由不适当的演员造成的。

如果您执行以下操作:

代码语言:javascript
运行
复制
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。如果你考虑一下乘法继承的对象在内存中是如何表示的,第一个基类在内存中是第一个,第二个基类是第二个,依此类推。因此,指向第二个基类的指针将偏移大约第一个基类的大小。

因此,要修复您的代码,我认为您需要执行以下操作:

代码语言:javascript
运行
复制
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
EN

Stack Overflow用户

发布于 2010-06-09 02:40:12

序列化QGraphicsItem不是一个好主意。QGrahpicsScene应该表示您的数据。与其序列化表示,不如序列化应用程序的数据/模型。

如果你想记录图形实体的排列,也许你可以使用一个自定义的QGraphicsItem并绘制到一个QPicture中。

票数 1
EN

Stack Overflow用户

发布于 2018-07-29 17:48:42

可以利用Qt元类型系统将QGraphicsItemQDataStream进行接口。下面是一个完整的示例,它处理基本的Qt QGraphicsItem-derived类型,以及对象的层次结构-也就是说,子项也会被保存和恢复。接口非常小--下面是你需要用来存储一些常见类型的头文件。

添加自定义类型只需要在界面中添加单个DECLARE_GRAPHICSITEM_METATYPE(CustomItemType)行。

代码语言:javascript
运行
复制
// https://github.com/KubaO/stackoverflown/tree/master/questions/qgraphicsitem-stream-51492181
// Interface
#include <QDataStream>
#include <QGraphicsItem>
#include <QGraphicsTransform>
#include <QMetaType>
#include <algorithm>
#include <type_traits>

template <class B, class T>
struct NonConstructibleFunctionHelper {
   static void *Construct(void *, const void *) { return {}; }
   static void Destruct(void *t) { static_cast<T *>(static_cast<B *>(t))->~T(); }
   static void Save(QDataStream &ds, const void *t) {
      ds << *static_cast<const T *>(static_cast<const B *>(t));
   }
   static void Load(QDataStream &ds, void *t) {
      ds >> *static_cast<T *>(static_cast<B *>(t));
   }
};

template <class B, class T>
struct NonCopyableFunctionHelper : NonConstructibleFunctionHelper<B, T> {
   static void *Construct(void *where, const void *t) {
      return (!t) ? static_cast<B *>(new (where) T) : nullptr;
   }
};

#define DECLARE_POLYMORPHIC_METATYPE(BASE_TYPE, TYPE) \
   DECLARE_POLYMORPHIC_METATYPE_IMPL(BASE_TYPE, TYPE)
#define DECLARE_POLYMORPHIC_METATYPE_IMPL(BASE_TYPE, TYPE)                            \
   QT_BEGIN_NAMESPACE namespace QtMetaTypePrivate {                                   \
      template <>                                                                     \
      struct QMetaTypeFunctionHelper<TYPE>                                            \
          : std::conditional<                                                         \
                std::is_copy_constructible<TYPE>::value, void,                        \
                std::conditional<                                                     \
                    std::is_default_constructible<TYPE>::value,                       \
                    NonCopyableFunctionHelper<BASE_TYPE, TYPE>,                       \
                    NonConstructibleFunctionHelper<BASE_TYPE, TYPE>>::type>::type {}; \
      QT_END_NAMESPACE                                                                \
   }                                                                                  \
   Q_DECLARE_METATYPE_IMPL(TYPE)
#define DECLARE_POLYSTREAMING_METATYPE(BASE_TYPE, TYPE) \
   DECLARE_POLYSTREAMING_METATYPE_IMPL(BASE_TYPE, TYPE)
#define DECLARE_POLYSTREAMING_METATYPE_IMPL(BASE_TYPE, TYPE) \
   DECLARE_POLYMORPHIC_METATYPE_IMPL(BASE_TYPE, TYPE)        \
   QDataStream &operator<<(QDataStream &, const TYPE &);     \
   QDataStream &operator>>(QDataStream &, TYPE &);

#define DECLARE_GRAPHICSITEM_METATYPE(TYPE) \
   DECLARE_POLYSTREAMING_METATYPE_IMPL(QGraphicsItem, TYPE)

QDataStream &operator<<(QDataStream &, const QList<QGraphicsItem *> &);

void saveProperties(QDataStream &, const QObject *, const QByteArrayList &excluded = {});
void loadProperties(QDataStream &, QObject *);

QDataStream &operator<<(QDataStream &, const QGraphicsTransform *);
QDataStream &operator>>(QDataStream &, QGraphicsTransform *&);

void registerMapping(int typeId, int itemType);

template <typename T>
typename std::enable_if<std::is_base_of<QGraphicsItem, T>::value>::type
registerMapping() {
   qRegisterMetaTypeStreamOperators<T>();
   if (!std::is_base_of<QGraphicsObject, T>::value)
      // The QObject-derived types don't need such mappings.
      registerMapping(qMetaTypeId<T>(), T::Type);
}

QDataStream &operator<<(QDataStream &, const QGraphicsItem *);
QDataStream &operator>>(QDataStream &, QGraphicsItem *&);

DECLARE_POLYMORPHIC_METATYPE(QGraphicsTransform, QGraphicsRotation)
DECLARE_POLYMORPHIC_METATYPE(QGraphicsTransform, QGraphicsScale)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsObject)
DECLARE_GRAPHICSITEM_METATYPE(QAbstractGraphicsShapeItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsItemGroup)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsLineItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsPixmapItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsEllipseItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsPathItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsPolygonItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsRectItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsSimpleTextItem)
DECLARE_GRAPHICSITEM_METATYPE(QGraphicsTextItem)

class ItemStream {
   QDataStream &ds;
   QGraphicsItem &item;

  public:
   using Version = qint8;
   static constexpr Version CurVersion = 1;
   enum { VersionKey = 0x9000 };
   ItemStream(QDataStream &ds, class QGraphicsItem &item) : ds(ds), item(item) {}
   template <typename C, typename T>
   ItemStream &operator>>(void (C::*set)(T)) {
      using decayed_type = typename std::decay<T>::type;
      using value_type = typename std::conditional<std::is_enum<decayed_type>::value,
                                                   std::underlying_type<decayed_type>,
                                                   std::decay<T>>::type::type;
      value_type value;
      ds >> value;
      (static_cast<C &>(item).*set)(static_cast<T>(value));
      return *this;
   }
   static Version formatOf(const QGraphicsItem &item) {
      auto version = item.data(VersionKey);
      return Version(version.isValid() ? version.value<int>() : 0);
   }
   static void setVersion(QGraphicsItem &item, Version version) {
      item.setData(VersionKey, version);
   }
};

ItemStream类使流入属性设置器变得更容易,并且在实现流运算符时很有用。它允许用简单的itemStream >> &Class::setFoo代替type foo; dataStream >> foo; obj.setFoo(foo);

此接口允许编写以下示例-从this answer扩展。

代码语言:javascript
运行
复制
// Test
#include <QtWidgets>

QPixmap makePixmap() {
   QPixmap pix(100, 50);
   pix.fill(Qt::transparent);
   QPainter p(&pix);
   p.setPen(Qt::darkCyan);
   p.setFont({"helvetica,arial", 15});
   p.drawText(pix.rect(), Qt::AlignCenter, "Hello!");
   return pix;
}

int main(int argc, char *argv[]) {
   QApplication a(argc, argv);
   QWidget ui;
   QGridLayout layout(&ui);
   QGraphicsScene scene;
   QGraphicsView view(&scene);
   QPushButton save("Save");
   QPushButton load("Load");
   layout.addWidget(&view, 0, 0, 1, 2);
   layout.addWidget(&load, 1, 0);
   layout.addWidget(&save, 1, 1);

   auto *eitem =
       scene.addEllipse(QRect(10, 10, 80, 50), QPen(Qt::green), QBrush(Qt::black));
   auto *xform = new QGraphicsRotation;
   xform->setAngle(10);
   eitem->setPos(100, 10);
   eitem->setRotation(60);
   eitem->setTransformations({xform});

   auto *litem = scene.addLine(QLineF(0, 0, 100, 100), QPen(Qt::red));
   litem->setPos(10, 10);
   litem->setRotation(100);

   scene.createItemGroup({eitem, litem});

   auto *ritem = scene.addRect(QRect(10, 0, 100, 100), QPen(Qt::blue), QBrush(Qt::red));
   ritem->setPos(10, 100);
   ritem->setRotation(10);

   QPainterPath path;
   path.moveTo(100, 100);
   path.lineTo(10, 0);
   path.addRect(QRect(0, 0, 100, 22));
   auto *pitem = scene.addPath(path, QPen(Qt::green), QBrush(Qt::black));
   pitem->setPos(100, 22);
   pitem->setRotation(120);

   scene.addPixmap(makePixmap());

   auto *stitem = scene.addSimpleText("Simple Text", {"arial", 17});
   stitem->setPos(-50, -10);
   stitem->setPen(QPen(Qt::darkGreen));

   auto *titem = scene.addText("Text", {"arial", 17, true});
   titem->setPos(-100, 0);
   titem->setDefaultTextColor(Qt::darkYellow);

   auto const flags = QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable |
                      QGraphicsItem::ItemIsFocusable;
   for (auto *it : scene.items()) it->setFlags(flags);

   QByteArray data;
   QObject::connect(&save, &QPushButton::clicked, [&scene, &data]() {
      qDebug() << "writing ...";
      QBuffer dev(&data);
      if (dev.open(QIODevice::WriteOnly)) {
         QDataStream out(&dev);
         out << scene.items(Qt::AscendingOrder);
         scene.clear();
         qDebug() << "done writing";
      }
   });
   QObject::connect(&load, &QPushButton::clicked, [&scene, &data]() {
      qDebug() << "reading ...";
      QBuffer dev(&data);
      if (dev.open(QIODevice::ReadOnly)) {
         QList<QGraphicsItem *> items;
         QDataStream in(&dev);
         in >> items;
         for (auto *item : items) scene.addItem(item);
         qDebug() << "done reading";
      }
   });

   ui.show();
   return a.exec();
}

具体类型的专门化相当简单。对于每个DECLARE_GRAPHICSITEM_METATYPE(ItemType)声明,都必须实现QDataStream &operator>>(QDataStream &in, ItemType &g)QDataStream &operator<<(QDataStream &out, const ItemType &g)。这些流运算符必须首先调用直接基类的运算符。您还必须注册映射-这可以在main中完成,也可以在静态初始化器中完成。

这些实现受到this answer的启发。

代码语言:javascript
运行
复制
// Implementation Specializations

static bool specInit = [] {
   qRegisterMetaType<QGraphicsRotation>();
   qRegisterMetaType<QGraphicsScale>();
   registerMapping<QGraphicsItemGroup>();
   registerMapping<QGraphicsLineItem>();
   registerMapping<QGraphicsPixmapItem>();
   registerMapping<QGraphicsEllipseItem>();
   registerMapping<QGraphicsPathItem>();
   registerMapping<QGraphicsPolygonItem>();
   registerMapping<QGraphicsRectItem>();
   registerMapping<QGraphicsSimpleTextItem>();
   registerMapping<QGraphicsTextItem>();
   return true;
}();

QDataStream &operator<<(QDataStream &out, const QGraphicsEllipseItem &g) {
   out << static_cast<const QAbstractGraphicsShapeItem &>(g);
   out << g.rect() << g.startAngle() << g.spanAngle();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsEllipseItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QAbstractGraphicsShapeItem &>(g);
   ItemStream(in, g) >> &QGI::setRect >> &QGI::setStartAngle >> &QGI::setSpanAngle;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsPathItem &g) {
   out << static_cast<const QAbstractGraphicsShapeItem &>(g);
   out << g.path();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsPathItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QAbstractGraphicsShapeItem &>(g);
   ItemStream(in, g) >> &QGI::setPath;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsPolygonItem &g) {
   out << static_cast<const QAbstractGraphicsShapeItem &>(g);
   out << g.polygon() << g.fillRule();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsPolygonItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QAbstractGraphicsShapeItem &>(g);
   ItemStream(in, g) >> &QGI::setPolygon >> &QGI::setFillRule;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsRectItem &g) {
   out << static_cast<const QAbstractGraphicsShapeItem &>(g);
   out << g.rect();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsRectItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QAbstractGraphicsShapeItem &>(g);
   ItemStream(in, g) >> &QGI::setRect;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsSimpleTextItem &g) {
   out << static_cast<const QAbstractGraphicsShapeItem &>(g);
   out << g.text() << g.font();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsSimpleTextItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QAbstractGraphicsShapeItem &>(g);
   ItemStream(in, g) >> &QGI::setText >> &QGI::setFont;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsItemGroup &g) {
   return out << static_cast<const QGraphicsItem &>(g);
}

QDataStream &operator>>(QDataStream &in, QGraphicsItemGroup &g) {
   return in >> static_cast<QGraphicsItem &>(g);
}

QDataStream &operator<<(QDataStream &out, const QGraphicsLineItem &g) {
   out << static_cast<const QGraphicsItem &>(g);
   out << g.pen() << g.line();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsLineItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QGraphicsItem &>(g);
   ItemStream(in, g) >> &QGI::setPen >> &QGI::setLine;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsPixmapItem &g) {
   out << static_cast<const QGraphicsItem &>(g);
   out << g.pixmap() << g.offset() << g.transformationMode() << g.shapeMode();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsPixmapItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QGraphicsItem &>(g);
   ItemStream(in, g) >> &QGI::setPixmap >> &QGI::setOffset >>
       &QGI::setTransformationMode >> &QGI::setShapeMode;
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsTextItem &g) {
   out << static_cast<const QGraphicsObject &>(g) << g.font() << g.textWidth()
       << g.defaultTextColor() << g.toHtml() << g.tabChangesFocus()
       << g.textInteractionFlags();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsTextItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QGraphicsObject &>(g);
   ItemStream(in, g) >> &QGI::setFont >> &QGI::setTextWidth >>
       &QGI::setDefaultTextColor >> &QGI::setHtml >> &QGI::setTabChangesFocus >>
       &QGI::setTextInteractionFlags;
   return in;
}

该实现的核心实现了元类型名称和所需类型的QGraphicsItem::type()项类型之间的映射。否则,对于从QObject派生的类型(即QGraphicsObject),它将直接使用类型名称。它还可以保存没有重复项目的项目列表。

代码语言:javascript
运行
复制
// Implementation Core
#include <set>

void saveProperties(QDataStream &ds, const QObject *obj, const QByteArrayList &excluded) {
   QVariantMap map;
   QByteArray name;
   auto const &mo = obj->metaObject();
   for (int i = 0; i < mo->propertyCount(); ++i) {
      auto const &mp = mo->property(i);
      if (!mp.isStored(obj)) continue;
      name = mp.name();
      if (!excluded.contains(name)) {
         auto prop = mp.read(obj);
         if (!prop.isNull() && (!excluded.contains(name + '?') ||
                                prop != QVariant(prop.userType(), nullptr)))
            map.insert(QLatin1String(name), prop);
      }
   }
   for (auto &name : obj->dynamicPropertyNames())
      map.insert(QLatin1String(name), obj->property(name));
   qDebug() << obj->metaObject()->className() << map;
   ds << map;
}

void loadProperties(QDataStream &ds, QObject *obj) {
   QVariantMap map;
   ds >> map;
   for (auto it = map.cbegin(); it != map.cend(); ++it)
      obj->setProperty(it.key().toLatin1(), it.value());
}

QDataStream &operator<<(QDataStream &ds, const QGraphicsTransform *obj) {
   ds << obj->metaObject()->className();
   saveProperties(ds, obj);
   return ds;
}

QDataStream &operator>>(QDataStream &ds, QGraphicsTransform *&obj) {
   QByteArray className;
   ds >> className;
   auto const type = QMetaType::type(className);
   obj = static_cast<QGraphicsTransform *>(QMetaType::create(type));
   if (obj) loadProperties(ds, obj);
   return ds;
}

struct pair {
   int typeId;
   int itemType;
};
struct CoreData {
   QReadWriteLock mappingLock;
   QVector<pair> mapping;
};
Q_GLOBAL_STATIC(CoreData, coreData)

int getTypeIdForItemType(int itemType) {
   if (auto *const d = coreData()) {
      QReadLocker lock(&d->mappingLock);
      for (auto &m : qAsConst(d->mapping))
         if (m.itemType == itemType) return m.typeId;
   }
   return QMetaType::UnknownType;
}

void registerMapping(int typeId, int itemType) {
   if (getTypeIdForItemType(itemType) == typeId) return;
   if (auto *const d = coreData()) {
      QWriteLocker lock(&d->mappingLock);
      for (auto &m : qAsConst(d->mapping))
         if (m.typeId == typeId && m.itemType == itemType) return;
      d->mapping.push_back({typeId, itemType});
   }
}

QByteArray peekByteArray(QDataStream &ds) {
   qint32 size;
   auto read = ds.device()->peek(reinterpret_cast<char *>(&size), sizeof(size));
   if (read != sizeof(size)) {
      ds.setStatus(QDataStream::ReadPastEnd);
      return {};
   }
   if (ds.byteOrder() == QDataStream::BigEndian) size = qFromBigEndian(size);
   auto buf = ds.device()->peek(size + 4);
   if (buf.size() != size + 4) {
      ds.setStatus(QDataStream::ReadPastEnd);
      return {};
   }
   if (buf.endsWith('\0')) buf.chop(1);
   return buf.mid(4);
}

QDataStream &operator<<(QDataStream &ds, const QList<QGraphicsItem *> &list) {
   std::set<QGraphicsItem *> seen;
   QList<QGraphicsItem *> items;
   struct State {
      QList<QGraphicsItem *>::const_iterator it, end;
   };
   QVector<State> stack;
   stack.push_back({list.begin(), list.end()});
   while (!stack.isEmpty()) {
      auto &level = stack.back();
      while (level.it != level.end) {
         QGraphicsItem *item = *level.it++;
         if (!item || seen.find(item) != seen.end())
            continue;            // skip empty items and seen items
         if (stack.size() == 1)  // push direct items only
            items.push_back(item);
         seen.insert(item);
         const auto &children = item->childItems();
         if (!children.isEmpty()) {
            stack.push_back({children.begin(), children.end()});
            break;
         }
      }
      if (level.it == level.end) stack.pop_back();
   }
   ds << quint32(items.size());
   for (auto *item : items) ds << item;
   return ds;
}

QDataStream &operator<<(QDataStream &ds, const QGraphicsItem *item) {
   const QGraphicsObject *obj = item->toGraphicsObject();
   const int typeId = obj ? QMetaType::type(obj->metaObject()->className())
                          : getTypeIdForItemType(item->type());
   if (typeId != QMetaType::UnknownType)
      QMetaType::save(ds, typeId, item);
   else
      ds << "";
   return ds;
}

QDataStream &operator>>(QDataStream &ds, QGraphicsItem *&item) {
   QByteArray const typeName = peekByteArray(ds);
   if (ds.status() != QDataStream::Ok) return ds;
   const int typeId = QMetaType::type(typeName);
   item = static_cast<QGraphicsItem *>(QMetaType::create(typeId));
   if (item) QMetaType::load(ds, typeId, item);
   return ds;
}

QByteArray getTypeName(const QGraphicsItem &g) {
   const QGraphicsObject *obj = g.toGraphicsObject();
   if (obj) return obj->metaObject()->className();
   return QMetaType::typeName(getTypeIdForItemType(g.type()));
}

QDataStream &operator<<(QDataStream &out, const QGraphicsItem &g) {
   out << getTypeName(g) << ItemStream::CurVersion << bool(g.toGraphicsObject())
       << int(g.type()) << g.pos() << g.scale() << g.rotation() << g.transform()
       << g.transformations() << g.transformOriginPoint() << g.flags() << g.isEnabled()
       << g.isSelected() << g.isVisible() << g.acceptDrops() << g.acceptHoverEvents()
       << g.acceptTouchEvents() << g.acceptedMouseButtons() << g.filtersChildEvents()
       << g.cursor() << g.inputMethodHints() << g.opacity()
       << g.boundingRegionGranularity() << g.toolTip() << g.zValue() << g.childItems();
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   QByteArray typeName;
   bool isObject;
   int type;
   ItemStream::Version version;
   QTransform transform;
   QList<QGraphicsItem *> children;
   in >> typeName >> version;

   Q_ASSERT(getTypeName(g) == typeName);
   if (version > ItemStream::CurVersion) {
      qWarning() << "unsupported QGraphicsItem version" << version
                 << "maximum is:" << ItemStream::CurVersion;
      in.setStatus(QDataStream::ReadCorruptData);
      return in;
   }
   ItemStream::setVersion(g, version);
   in >> isObject >> type;
   ItemStream iin(in, g);
   iin >> &QGI::setPos >> &QGI::setScale >> &QGI::setRotation;
   in >> transform;
   g.setTransform(transform);
   iin >> &QGI::setTransformations >> &QGI::setTransformOriginPoint >> &QGI::setFlags >>
       &QGI::setEnabled >> &QGI::setSelected;
   if (version >= 1) {
      iin >> &QGI::setVisible >> &QGI::setAcceptDrops >> &QGI::setAcceptHoverEvents >>
          &QGI::setAcceptTouchEvents >> &QGI::setAcceptedMouseButtons >>
          &QGI::setFiltersChildEvents >> &QGI::setCursor >> &QGI::setInputMethodHints >>
          &QGI::setOpacity >> &QGI::setBoundingRegionGranularity >> &QGI::setToolTip;
   }
   iin >> &QGI::setZValue;
   in >> children;

   for (auto *c : qAsConst(children)) c->setParentItem(&g);
   return in;
}

QDataStream &operator<<(QDataStream &out, const QGraphicsObject &g) {
   static const QByteArrayList excluded{
       "effect",   "enabled",  "opacity", "parent",
       "pos",      "rotation", "scale",   "transformOriginPoint",
       "visible",  "x",        "y",       "z",
       "children", "height?",  "width?"};
   out << static_cast<const QGraphicsItem &>(g);
   saveProperties(out, &g, excluded);
   return out;
}

QDataStream &operator>>(QDataStream &in, QGraphicsObject &g) {
   in >> static_cast<QGraphicsItem &>(g);
   loadProperties(in, &g);
   return in;
}

QDataStream &operator<<(QDataStream &out, const QAbstractGraphicsShapeItem &g) {
   out << static_cast<const QGraphicsItem &>(g);
   out << g.pen() << g.brush();
   return out;
}

QDataStream &operator>>(QDataStream &in, QAbstractGraphicsShapeItem &g) {
   using QGI = std::decay<decltype(g)>::type;
   in >> static_cast<QGraphicsItem &>(g);
   ItemStream(in, g) >> &QGI::setPen >> &QGI::setBrush;
   return in;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2999952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档