我正在使用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
}
...
};
然后,我可以使用QGraphicsScene::addItem(new Rect(,,,));
添加Rect对象
但这并不能真正帮助我,因为下面的代码会崩溃:
QList<QGraphicsItem*> list = scene->items();
foreach (QGraphicsItem* item, items)
{
Item* myitem = reinterpret_class<Item*>(item);
myitem->serialize(...) // FAIL
}
有没有办法让这件事行得通?
发布于 2010-06-16 02:45:04
我同意其他发帖者的观点,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(...);
}
这是许多原因之一,我喜欢尽可能避免多重继承。我强烈建议按照前面的建议分离模型数据。
发布于 2010-06-09 02:40:12
序列化QGraphicsItem
不是一个好主意。QGrahpicsScene
应该表示您的数据。与其序列化表示,不如序列化应用程序的数据/模型。
如果你想记录图形实体的排列,也许你可以使用一个自定义的QGraphicsItem
并绘制到一个QPicture中。
发布于 2018-07-29 17:48:42
可以利用Qt元类型系统将QGraphicsItem
与QDataStream
进行接口。下面是一个完整的示例,它处理基本的Qt QGraphicsItem
-derived类型,以及对象的层次结构-也就是说,子项也会被保存和恢复。接口非常小--下面是你需要用来存储一些常见类型的头文件。
添加自定义类型只需要在界面中添加单个DECLARE_GRAPHICSITEM_METATYPE(CustomItemType)
行。
// 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扩展。
// 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的启发。
// 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
),它将直接使用类型名称。它还可以保存没有重复项目的项目列表。
// 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;
}
https://stackoverflow.com/questions/2999952
复制相似问题