500 Variables in class how to get/set/store in json efficiently?
-
Lets say i have many variables of different types in my class lets asume there are around 500 of them:
for example:bool isActive = false; QString Name = "Paul"; int Number = 22;
I need an way to store them in a way so i can loop trough all variables in the class to get and set them. I thought of using the Variable Name as a "Key" in a QMap
QMap<QString, QVariant> StoreVariableNameANDValue; StoreVariableNameANDValue["isActive"] = false; StoreVariableNameANDValue["Name"] = QString("Paul"); StoreVariableNameANDValue["Number"] = 22; QList<QString> variableNames = StoreVariableNameANDValue.keys(); foreach(const QString &varName, variableNames) { qDebug() << "Variable Name:" << varName; qDebug() << "Value:" << StoreVariableNameANDValue[varName]; }
Problem is i also need to convert the "Value" back to the correct type. How can i do that automatically without having to write .toInt(), toBool() ... every time? For example when reading from a json file i want to save the values to i have to do manually till now like this:
mPixmap->setSceneID(obj["SceneID"].toInt());
But i want something like: without needing to .toInt() or so.
foreach(const QString &varName, variableNames) { mPixmap->setStoreVariableNameANDValue[varName] = obj[varName]; }
Any idea on how exactly to get something like that working? (I know the code above isn't exactly 100% correct, but more an outline on what i actually want). Thanks in advance, i appreciate your input. :)
EDIT: for Input i thought of maybe something like this:
QMap<QString, QVariant> StoreVariableNameANDValue; StoreVariableNameANDValue["isActive"] = false; StoreVariableNameANDValue["Name"] = QString("Paul"); StoreVariableNameANDValue["Number"] = 22; QList<QString> variableNames = StoreVariableNameANDValue.keys(); // Create a QJsonObject outside the loop QJsonObject obj; foreach(const QString &varName, variableNames) { // Add each variable to the QJsonObject obj[varName] = QJsonValue::fromVariant(StoreVariableNameANDValue[varName]); }
-
@StudentScripter
Take a step back from the details of the code you are concentrating on for a moment.What you are trying to do here is "map" between a bunch of C++ individual variables, which have names as C++ identifiers, and some representation/serialization/deserialization (happens to be JSON, but same issue with others) with strings of the names. C++ is not going to support this. Python could, or JavaScript, but not C++. So you are trying to drive a square plug into a round hole.
Accept the you want something like either
- a big
switch()
statement (on read/restore) to handle mapping between variables names as strings and the actual C++ variables; - or give up on the individual variables and write getters & setters for each current one with the data stored in your
QMap
or QObject properties or data model or similar.
A separate question is why you might have "500" variables in a class to store. If you have that much data as individual items that is not good, you might need some kind of model.
- a big
-
@JonB What kind of model would be a good way of storing this? Currently im storing the data for each of my qgraphicsitems in the qgraphicsitem subclass. (i dont have 500 parameters yet but it will grow somewhere near that)
Currently im retrieving and setting the data like that from json on load:
// Parse the JSON document QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); if (jsonError.error != QJsonParseError::NoError) { qDebug() << "Error parsing JSON: " << jsonError.errorString(); return; } // Access the first object in the array, which contains the SceneID Counter QJsonObject objCounter = doc.array().at(0).toObject(); setSceneItemCounter(objCounter["SceneID Counter"].toInt()); // Iterate through each QJsonObject in the QJsonArray foreach (QJsonValue val, doc.array()) { QJsonObject obj = val.toObject(); // Create a new ResizablePixmapItem with the data from the QJsonObject ResizablePixmapItem *mPixmap = new ResizablePixmapItem(QPixmap()); mPixmap->setSceneID(obj["SceneID"].toInt()); mPixmap->setControlName(obj["ControlName"].toString()); mPixmap->setImageFilePath(obj["ImageFilePath"].toString()); mPixmap->setPos(obj["posX"].toDouble(), obj["posY"].toDouble()); mPixmap->setSelectorFrameBounds(QRectF(obj["x"].toDouble(), obj["y"].toDouble(), obj["width"].toDouble(), obj["height"].toDouble())); mPixmap->setFrameWidth(obj["FrameWidth"].toInt()); mPixmap->setFrameHeight(obj["FrameHeight"].toInt()); // Add the ResizablePixmapItem to the QGraphicsScene addItem(mPixmap); mPixmap->setPixmap(mPixmap->getImageFilePath()); mPixmap->setFlags(QGraphicsItem::ItemIsMovable |QGraphicsItem::ItemIsSelectable); this->update(); }
I store it on save like that:
// Erstellen Sie ein QJsonArray QJsonArray array; //Speichert den Stand des SzeneItem Counters QJsonObject objC; objC["SceneID Counter"] = SceneItemCounter; array.append(objC); // Durchlaufen Sie jedes QGraphicsItem in Ihrer QGraphicsScene foreach (QGraphicsItem *item, items()) { if(item == GroupSelectionRect){ //Überspringe das GroupSelectionRect continue; } // Casten Sie das QGraphicsItem zu einem ResizablePixmapItem ResizablePixmapItem *mPixmap = dynamic_cast<ResizablePixmapItem *>(item); if (mPixmap) { // Erstellen Sie ein QJsonObject für jedes QGraphicsItem QJsonObject obj; obj["SceneID"] = mPixmap->getSceneID(); obj["ControlName"] = mPixmap->getControlName(); obj["ImageFilePath"] = mPixmap->getImageFilePath(); obj["posX"] = mPixmap->scenePos().x(); obj["posY"] = mPixmap->scenePos().y(); obj["x"] = mPixmap->selectorFrameBounds().x(); obj["y"] = mPixmap->selectorFrameBounds().y(); obj["width"] = mPixmap->selectorFrameBounds().width(); obj["height"] = mPixmap->selectorFrameBounds().height(); obj["FrameWidth"] = mPixmap->getFrameWidth(); obj["FrameHeight"] = mPixmap->getFrameHeight(); // Fügen Sie das QJsonObject zum QJsonArray hinzu array.append(obj); } } // Erstellen Sie ein QJsonDocument mit dem QJsonArray QJsonDocument doc(array);
-
@StudentScripter
"Model" really means any kind of model, where all your variable values are stored as a collection (so they can be iterated, and saved/restored as a whole) and can be accessed somehow individually so that you know what each one means. It could be, say, a row model with a mapping between row numbers and what data is stored there, or yourQMap
where you can index by a key string.What you show is OK if you want to use it. You have to put into code the variable/value name as a string and which C++ variable or function call you want to get/set it. You do that explicitly, once when you are saving and once when you are restoring.
If you wish, you can make it a bit nicer by writing a getter and setter for each "variable" which maps to/from your map.
int Mapper::sceneID() const { return obj["SceneID"].toInt(); } void Mapper::setSceneID(int id) { obj["SceneID"] = id; } ...
so now you are using the serializable map as your data store instead of individual variables, but presenting a getter/setter interface so you can code as though they were variables.
If you are saving/restoring all the properties of widgets or graphics items you show then, yes, your number of items is going to get "large". Usually people find a way to provide some kind of "model" for the "back-end" from which the "front-end" can be reconstructed. But if you really need to save/restore frame positions, bounds, widths, heights etc. then so be it. You can reduce the number of lines of code if you write "helper" functions to convert between, say, a
QRect
(which can be stored in aQVariant
so OK for yourQMap
) forselectorFrameBounds()
and aQJsonObject
with keys for the members, and re-use that.Don't forget there is QJsonObject QJsonObject::fromVariantMap(const QVariantMap &map) and QVariantMap QJsonObject::toVariantMap() const to convert between JSON objects and a
QMap
ofQVariant
s in one go. -
Hi,
Do you mean your JSON is going to be a single dictionary with 500 entries or will it rather be a dict/list of dicts ?
-
@StudentScripter I think you mean JSON object not array.
-
@JonB Well yeah, one entry for every graphicsitems holding all up to 500 values.
So for 1000 items it would be 500.000 entrys inside the json document. But i guess that shouldn't be that big of a problem as every variable written is just a few bytes. Accumulating to around 24 megabyte if you really have thousand graphicsitems and only longer strings.
-
@StudentScripter
It may be OK but why do you have so much data to serialize? Why do you have or need 500 values for each graphics item, and all need to be persisted?If you are doing something like Serializing QGraphicsScene contents, my feeling is like the response there saying
Serializing QGraphicsItem is not a good idea. A QGrahpicsScene is supposed to represent your data. Instead of serializing the representation, it's better to serialize the data/model of your application.
There might be some hints in other posts there if you do wish to serialize graphics objects nonetheless. Or others if you Google for
qgrapchicsscene serialize
if that is what you are trying to achieve. -
@JonB Yes all most of the data on which interfaces/nodes to show are stored on a per item basis as each item can have a different set of nodes with completely different propertys. So when you click on a item i have to update the interface to match that. Hope that makes sense.
-
@StudentScripter Your post crossed with my last. Just take on board the
Serializing QGraphicsItem is not a good idea. A QGrahpicsScene is supposed to represent your data. Instead of serializing the representation, it's better to serialize the data/model of your application.
But only you know what your application needs.
-
@JonB Hm i see but i really wouldn't know how else to serialize the data. As said it surely needs to be seperated so i have data for the interface according to which item is clicked. I surely could store most of the data in a seperate class, only providing the id of the graphicsitem the data belongs to.
Or what else would you maybe suggest? Thanks for all the good hints along my way, wouldn't know what i would do without the help of yours, SGaist and PI45m4. <3 Really appreciate that as not that experienced programmer.
I see you asked something like that some time ago: https://forum.qt.io/topic/109305/serializing-qgraphicsscene-and-json/8
-
@StudentScripter said in 500 Variables in class how to get/set/store in json efficiently?:
I see you asked something like that some time ago: https://forum.qt.io/topic/109305/serializing-qgraphicsscene-and-json/8
Yeah, that was in my youth ;) I had no choice there, it was to do with Python JSON handling and I was working for someone else, not my own stuff.
I can't really say more than I have. I'm not sure how you accumulate 500 different items/variables of information to associate with up to 1,000 items. How did this data get there? How are these graphics items created? Did someone sit and create them or did they come from some other underlying data model? Why do you have to look at a pixmap and save information about its "frame"? But like I said, we are not going to understand or go through all your design decisions. You may be right and for your needs this is all reasonable and necessary data.
-
Well, 500 properties per QGraphicsItem does sound like quite a lot.
As @JonB suggested: are you sure you are really needing all of them ?
You should take a step back and start by doing some drawing and design to have a clear picture of what the data you need are. What makes sense of keeping, do you really need to load them all within every item ? And also, do they all make sense together ?
As an example, if your item represent some control in a system, the properties of that control will have nothing to do with for example the position of the item in the scene, hence it would make little sense to smoosh them together.
You might also want to ensure that JSON is the correct data structure you need. Maybe a simple SQLite database might be more suited. Or maybe multiple JSON files rather than one super massive file.
-
@SGaist Well thanks for the good hints:
-
Yes i need all these variables, as every variable stores the data of a slider, button, lineedit for the specific item
-
Of course i could seperate these data out to an extra subclass, but what would it be worth? I still would have to store this data and provide a relation to the item somehow on which the data on the interface needs to change.
-
May a question: what is faster/better:
.......1. when clicking on a item reading 500 values from the json file for that item live and setting them to the slidersOR
.......2. reading all 500 values * (at maximum) 1000 items at startup from the file and saving them in the subclasses variables so when the item is clicked it just reads from the already set variables -
I could have a json file for each item with 500 values but i guess having 1000 json files wouldn't be that great either. So i guess i stick with 1 big file?
-
Regarding SQLite i haven't used it before and from what i watched i do not exactly know/understand how it could save me time/would be more suitable than a json file i can relatively easy dump all these data into. But may enlighten me. Im always eager to learn. :D
Y'all have a nice sunday.
-
-
@StudentScripter said in 500 Variables in class how to get/set/store in json efficiently?:
Yes i need all these variables, as every variable stores the data of a slider, button, lineedit for the specific item
We have tried to explain: you are supposed/better to have a model for this data, and be saving/restoring that rather than the data of each UI widget. For example, where does the value of a slider or the text of a line edit come from? That should really be a model. I think you have none and are storing the values of your UI widgets as your only "model" instead. Anyway we have said this, it is up to you.
May a question: what is faster/better:
.......1. when clicking on a item reading 500 values from the json file for that item live and setting them to the slidersOR
.......2. reading all 500 values * (at maximum) 1000 items at startup from the file and saving them in the subclasses variables so when the item is clicked it just reads from the already set variables
A JSON file is no kind of "random access" database (unlike, say, SQLite). You cannot read parts of it a time, you have to read the whole thing and let JSON parse it. So your #1 is not possible, you cannot "reading 500 values from the json file for that item live". I imagine the most time, whatever that is, will be reading & parsing the 500 x 1000 item's-worth of text from the JSON file, rather than the time then taken to "transfer" those as settings to the widgets.
So you will need to go for #2, in some shape or form. Certainly read the whole file. Then either get the "transfer" done at that point for all values to all widgets, or if that takes too long leave the data in the in-memory JSON structure and go access an individual widget's settings the first time you need it. That can be done efficiently in-memory since your JSON object hierarchy can be indexed by key or index (whichever way you chose to store it).
-
@StudentScripter
A database (such as SQLite) might be a better choice for half a million data items. And more so if the quantity grows. You can access any item directly. You can alter one item without having to re-save all the other items as you do for a JSON file.Having said that, computers are fast and have lots of memory these days. JSON for 0.5M items might be fine for the way you are going to use it. You seem to know where you are with JSON, it's quite a bit of learning to change over to a database. If you want to learn by all means go ahead. If you want to just proceed with your app try it with the JSON approach you have and see whether speed (or memory) is an issue.
A big factor is what you might want to do with the data outside of you and your application. If you have requirements there, e.g. for interfacing with other uses, that is a different matter and may dictate what you use.
-
@JonB Thank you very much. Well i guess i do not exactly need SQLite but it seems like a cool thing to learn. As its a personal project i can take the time. :D And also who doesn't like over optimised good running programs.
Im not planning to do anything with the data outside my application. So yeah i guess json would be fine here too, but as said i like to learn new stuff. Have a nice evening.
-
Then I would insist on taking the time to design things properly even for a personal project.
As @JonB wrote, you seem to want to dump quite a lot of stuff that may or may not be related to your items. Hence the first step is to properly model your stuff and then decide which data backend is the best fit.