8
votes

Serializing QGraphicsscene Contenu

J'utilise le qt qgraphicsscene classe, ajout d'éléments prédéfinis tels que qgraphicsRecTem , qgraphicslineItem , etc., et je veux sérialiser le contenu de la scène sur le disque. Cependant, la base qgraphicsitem (que les autres articles que j'utilise dérive de) ne prennent pas en charge la sérialisation, donc j'ai besoin de rouler mon propre code. Le problème est que tout accès à ces objets est via une base qgraphicsitem du pointeur, de sorte que le code de sérialisation que j'ai est horrible: xxx

Ce n'est pas bon code IMHO. Ainsi, je pourrais plutôt créer une classe ABC comme ceci: xxx

i peut ensuite ajouter des objets rectants en utilisant qgraphicssscene :: additem (nouveau rect (nouveau (,) ;

Mais cela ne m'aide pas vraiment comme ce qui suit va crancer: xxx

Toute façon que je puisse faire ce travail? < / p>


2 commentaires

Pourquoi myItem-> Serialize () crash. Je ne le vois pas?


Étant donné que réinterpret_class ne fonctionne pas la conversion requise (le pointeur est juste interpréter différemment). Pointeur sur élément est un bit décalé par rapport à qgraphicsitem . Tout d'abord, vous avez besoin de moulage vers rect puis de la distribution par défaut à élément corrigera l'adresse matérielle à pointe correctement sur élément .


4 Réponses :


1
votes

sérialisation qgraphicsitem n'est pas une bonne idée. Un QGRAHPICSSCENE est censé représenter vos données. Au lieu de sérialiser la représentation, il est préférable de sérialiser les données / modèle de votre application.

Si vous souhaitez enregistrer un arrangement d'entités graphiques, vous pouvez peut-être utiliser un QGraphicSitem et dessiner dans un Qpicture .


2 commentaires

Les éléments contiennent tout ce dont j'ai besoin pour sérialiser, afin que les données / modèles peuvent être considérées dans ce cas.


BTW Il ne semble pas être un soutien pour lier un qgraphicsscène à un modèle séparé.



0
votes

Si vous voulez vraiment sérialiser ces éléments créer xxx

pour chacun des sous-classes qgraphicsitem que vous souhaitez sérialiser, ces fonctions sont une fonction non membre. . L'approche est également expliquée dans le Documentation QDaTrasteam

mais je Support Stephens Répondre, vous voudrez peut-être envisager de tirer les données réelles de la scène et de la mettre dans une classe de modèle distincte


1 commentaires

Cela ne fonctionne pas à moins que je ne jette que chaque qgraphicsitems au bon type avant de tenter de le diffuser.



3
votes

Je suis d'accord avec les autres affiches, le qgraphicsitem pourrait vraiment être considéré comme un élément d'affichage et séparer donc vos données de modèle en sa propre classe serait probablement mieux.

Cela dit, je pense que votre crash est causé par une inappropriée Cast. P>

Si vous effectuez les suivantes: p>

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(...);
}


1 commentaires

WTF: Reterpret_cast?



1
votes

Le système MetaType QT peut être exploité à l'interface qgraphicsitem code> avec qdatastream code>. Vous trouverez ci-dessous un exemple complet qui gère des types de base qt qgraphicsitem code>, ainsi que des hiérarchies d'objets - c'est-à-dire que les articles enfants sont enregistrés et restaurés aussi. L'interface est très petite - ci-dessous est l'en-tête que vous auriez besoin de supporter le stockage de certains types courants.

Ajout de types personnalisés nécessite uniquement l'ajout d'un seul déclrey_graphicsitem_metatype (CustomItemType) code> ligne dans le Interface. P>

// 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 commentaires

Vous devriez marquer l'autre question comme un duplicata de ceci :)