I am trying to serialize a custom class Layer*
and read it back using QDataStream. Now, Layer
is an abstract class with virtual method which is inherited by different kinds of layers: RasterLayer
, TextLayer
, AdjustmentLayer
etc.
I have a QList<Layer*> layers
which keeps track of all the layers, and any adjustments made to a layer are updated in the list. I need to serialize and deserialize the QList to its original state and restore the properties of the individual layers (of different types).
Here is layer.h:
#ifndef LAYER_H
#define LAYER_H
#include <QString>
#include <QImage>
#include <QDebug>
#include <QListWidgetItem>
#include <QGraphicsItem>
#include <QPixmap>
class Layer : public QListWidgetItem
{
public:
enum LayerType{
RASTER,
VECTOR,
TEXT,
ADJUSTMENT
};
Layer(QString name, LayerType type);
~Layer();
inline void setName(QString &name) { _name = name; }
inline QString getName() { return _name; }
inline LayerType getType() { return _type; }
virtual void setSceneSelected(bool select) = 0;
virtual void setLayerSelected(bool select) = 0;
virtual void setZvalue(int z) = 0;
virtual void setParent(QGraphicsItem *parent) = 0;
protected:
QString _name;
LayerType _type;
};
#endif // LAYER_H
This is extended by a RasterLayer class:
#ifndef RASTERLAYER_H
#define RASTERLAYER_H
#include <QGraphicsPixmapItem>
#include <QPainter>
#include <QGraphicsScene>
#include "layer.h"
class RasterLayer : public Layer, public QGraphicsPixmapItem
{
public:
RasterLayer(const QString &name, const QImage &image);
RasterLayer();
~RasterLayer();
void setLocked(bool lock);
void setSceneSelected(bool select);
void setLayerSelected(bool select);
void setZvalue(int z);
void setParent(QGraphicsItem *parent);
inline QPixmap getPixmap() const { return pixmap(); }
inline QPointF getPos() const { return QGraphicsPixmapItem::pos(); }
inline void setLayerPos(QPointF pos) { setPos(pos);}
inline void setLayerPixmap(QPixmap pixmap) { setPixmap(pixmap); }
friend QDataStream& operator<<(QDataStream& ds, RasterLayer *&layer)
{
ds << layer->getPixmap() << layer->getName() << layer->getPos();
return ds;
}
friend QDataStream& operator>>(QDataStream& ds, RasterLayer *layer)
{
QString name;
QPixmap pixmap;
QPointF pos;
ds >> pixmap >> name >> pos;
layer->setName(name);
layer->setPixmap(pixmap);
layer->setPos(pos);
return ds;
}
protected:
void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget);
private:
QImage _image;
};
#endif // RASTERLAYER_H
I am currently trying to test serialization-deserialization of a RasterLayer
like this:
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
Layer *layer = paintWidget->getItems().at(1);
// Gets the second element in the list
RasterLayer *raster = dynamic_cast<RasterLayer*> (layer);
out << raster;
file.close();
Now, as you can see here, I am specifically casting Layer*
to a RasterLayer*
to be serialized, and this works since I have worked on only one type of layer till now. So my first question is:
How do I generalize this serialization process to all types of layers?
Every type of layer will have a different way of serialization since each hold different properties. Also, the casting here feels like a bit of code smell and a possible bad design choice. So, having something like serialize the entire list of layers calling their corresponding overloaded operators would be the expected scenario.
My second question is:
How do I deserialize the data properly?
Here's how I am currently serializing an individual RasterLayer
:
QFile newFile(fileName);
newFile.open(QIODevice::ReadOnly);
QDataStream in(&newFile);
RasterLayer *layer2 = new RasterLayer;
in >> layer2;
paintWidget->pushLayer(layer2);
ui->layerView->updateItems(paintWidget->getItems());
Firstly, I don't think serializing to a pointer is something I should be doing in this case, but I am not sure what else to do or how to do better yet. Secondly, the deserialization works here, but it doesn't quite do what I would be expecting it to do. Although I am using setters in the overloaded operators, it's really not updating the layer properly. I need to call the constructor to make a new layer out of it.
I have tried this: Serialization with Qt but I am not quite sure how to have a Layer*
convert it to a Layer
, serialize it, deserialize it and then convert it back to Layer*
.
So I need to add a third step:
RasterLayer *layer3 = new RasterLayer(layer2->getName(), layer2->getPixmap().toImage());
layer3->setPos(layer2->pos());
and then push layer3
to the list to actually make it work. According to this post: https://stackoverflow.com/a/23697747/6109408, I really shouldn't be doing a new RasterLayer...
inside the operator overloading function (or else I will fry in hell), and I am following the first suggestion given there, which isn't very much working in my case and I don't know the right way to do it.
Also, how do I deserialize this for a general QList of Layer*
s instead of having to create new specific layer instances and injecting them with deserialized data? Although this is similar: Serialize a class with a Qlist of custom classes as member (using QDataStream), the answers weren't clear enough for me to understand.
I have had an idea about an intermediate value holder class that I will use to serialize all sorts of Layers and let that create and inject the parameters depending upon the type of Layer it is, but I am not sure if that will work.
Thanks for helping me out.