J'utilise le qt Ce n'est pas bon code IMHO. Ainsi, je pourrais plutôt créer une classe ABC comme ceci: p> i peut ensuite ajouter des objets rectants en utilisant Mais cela ne m'aide pas vraiment comme ce qui suit va crancer: p> Toute façon que je puisse faire ce travail? < / p> p> qgraphicsscene code> classe, ajout d'éléments prédéfinis tels que qgraphicsRecTem code>, qgraphicslineItem code>, etc., et je veux sérialiser le contenu de la scène sur le disque. Cependant, la base qgraphicsitem code> (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 code> du pointeur, de sorte que le code de sérialisation que j'ai est horrible: qgraphicssscene :: additem (nouveau rect (nouveau (,) ; code> p>
4 Réponses :
sérialisation Si vous souhaitez enregistrer un arrangement d'entités graphiques, vous pouvez peut-être utiliser un qgraphicsitem code> n'est pas une bonne idée. Un QGRAHPICSSCENE code> 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. P>
QGraphicSitem CODE> et dessiner dans un Qpicture . P>
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é.
Si vous voulez vraiment sérialiser ces éléments créer pour chacun des sous-classes 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 p> p> qgraphicsitem code> que vous souhaitez sérialiser, ces fonctions sont une fonction non membre. . L'approche est également expliquée dans le Documentation QDaTrasteam P>
Cela ne fonctionne pas à moins que je ne jette que chaque qgraphicsitems au bon type avant de tenter de le diffuser.
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(...);
}
WTF: Reterpret_cast?
Le système MetaType QT peut être exploité à l'interface Ajout de types personnalisés nécessite uniquement l'ajout d'un seul qgraphicsitem code> avec qdatastream code>. Vous trouverez ci-dessous un exemple complet qui gère des types de base qt 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;
}
Vous devriez marquer l'autre question comme un duplicata de ceci :)
Pourquoi
myItem-> Serialize () code> crash. Je ne le vois pas?Étant donné que
réinterpret_class code> ne fonctionne pas la conversion requise (le pointeur est juste interpréter différemment). Pointeur surélément code> est un bit décalé par rapport àqgraphicsitem code>. Tout d'abord, vous avez besoin de moulage versrect code> puis de la distribution par défaut àélément code> corrigera l'adresse matérielle à pointe correctement surélément code>.