QSharedData, How to use?
-
Hello,
i'm a Qt beginner and experimenting with QSharedData, but don't unterstand it. I have used the Wizard of Qt Creator to create a
new class with QSharedData.header:
#ifndef PLOTSETTINGS_H #define PLOTSETTINGS_H #include <QObject> #include <QSharedDataPointer> #include <QString> #include <QFont> #include <QColor> class PlotSettingsData; class PlotSettings { public: PlotSettings(); PlotSettings(const PlotSettings &); PlotSettings &operator=(const PlotSettings &); ~PlotSettings(); struct TitleData { bool enabled; QString text; QFont font; QColor color; bool borderEnabled; QColor borderColor; } title; struct FooterData { bool enabled; QString text; QFont font; QColor color; bool borderEnabled; QColor borderColor; } footer; private: QSharedDataPointer<PlotSettingsData> data; }; #endif // PLOTSETTINGS_H
and my cpp:
#include "plotsettings.h" class PlotSettingsData : public QSharedData { public: }; PlotSettings::PlotSettings() : data(new PlotSettingsData) { // Title title.enabled = true; title.text = QString("Title"); title.font = QFont( "MS Shell Dlg 2", 14, QFont::Bold); title.color = Qt::black; title.borderEnabled = false; title.borderColor = Qt::black; // Footer footer.enabled = false; footer.text = QString("Footer"); footer.font = QFont( "MS Shell Dlg 2", 8, QFont::Normal); footer.color = Qt::black; footer.borderEnabled = false; footer.borderColor = Qt::black; } PlotSettings::PlotSettings(const PlotSettings &rhs) : data(rhs.data) { } PlotSettings &PlotSettings::operator=(const PlotSettings &rhs) { if (this != &rhs) data.operator=(rhs.data); return *this; } PlotSettings::~PlotSettings() { }
now i have two classes, lets say classA and classB. I go through the example on Qt Documentaton but
it is not understandable!Questions:
- If i'm right, i can set (but how) a.g. a title.text in classA and class B can read it?
- How can i set e.g. title.text with QSharedData?
I mean, if i have in classA and classB
#include "settings/plotsettings.h" PlotSettings d_actualSettings;
i can set d_actualSettings.title.text = "My new title". But that is only the object created in classA and classB has still the same.
Hope anybody can help me. I'm realy confused.
Stefan -
- All data you currently have in PlotSettings should go into PlotSettingsData, except for the line
QSharedDataPointer<PlotSettingsData> data;
The data within PlotSettingsData can be public. Since the class is declared in the cpp file, nobody but the PlotSettings class can use it anyway. If you want to be 100 % sure about this, you can make the members private and add PlotSettings as a friend class. - You then add getters and setters to PlotSettings, which would be implemented like this:
// Get Footer data
return data->footer;
- All data you currently have in PlotSettings should go into PlotSettingsData, except for the line
-
Hello, thx for your answer, but it doesn't work and i don't know why.
mainwindow.cpp
#include "plotmanager.h" #include "curvemanager.h" _PlotManager = new PlotManager( ui->plot); _CurveManager = new CurveManager( ui->plot);
plotmanager.h
#include "plotsettings.h" private: PlotSettings _settings;
curvemanager.h
#include "plotsettings.h" private: PlotSettings _settings;
when i use
qDebug() << Q_FUNC_INFO << _settings.getTitleText();
i can see that they don't share the PlotSettingsDataplotsettings.h
#ifndef PLOTSETTINGS_H #define PLOTSETTINGS_H #include <QObject> #include <QSharedDataPointer> #include <QString> #include <QFont> #include <QColor> class PlotSettingsData; class PlotSettings { public: PlotSettings(); PlotSettings(const PlotSettings &); PlotSettings &operator=(const PlotSettings &); ~PlotSettings(); void setTitleText(const QString &title); QString getTitleText(); private: QSharedDataPointer<PlotSettingsData> data; }; #endif // PLOTSETTINGS_H
plotsettings.cpp
#include "plotsettings.h" class PlotSettingsData : public QSharedData { friend class PlotSettings; public: QString titleText; }; PlotSettings::PlotSettings() : data(new PlotSettingsData) { data->titleText = QString("Stefan"); } PlotSettings::PlotSettings(const PlotSettings &rhs) : data(rhs.data) { } PlotSettings &PlotSettings::operator=(const PlotSettings &rhs) { if (this != &rhs) data.operator=(rhs.data); return *this; } PlotSettings::~PlotSettings() { } void PlotSettings::setTitleText(const QString &title) { data->titleText = title; } QString PlotSettings::getTitleText() { return data->titleText; }
What i'm doing wrong?
Stefan -
It's always much easier if you specifically say what doesn't work. Compiler error? Runtime crash? Data not what you expect? Be specific, please.
-
Ok, sorry. I don't have any compiler error or like that. Better i describe what i want first:
1.)
I have two classes "PlotManager" and "CurveManager". Both are included to my mainwindow.h
and there i create two objects of them.2.)
I want to have a "Settings" class that is used by "PlotManager" AND "CurveManager".
The data that i store in "Settings" should be available to both via getters/setters.
Up to now no problem, but if i create an object in "PlotManager" and "CurveManager"
from my common "Settings" class, the data is seperated and not shared.3.)
Now i start to create a new "Settings" class with QSharedData, because i guess that
i can share data over two classes. Correct me if i'm wrong. My examle was just to
set a simple QString inside "PlotManager" and get it in "CurveManager".I hope it is clear what i need or want.
Many thx for your help -
@HappyCoder
Sorry for not giving you a specific, quick-to-use answer, but I have the impression your issue lies with design, not coding.Now everything is much clearer. The code you started looked like an attempt to implement implicit sharing, so I advised in this direction. What you want to do is something different entirely.
Let's get at this step by step:
You want to access the same instance of the settings class from two objects. That means, if the settings change in one object, the other object can immediately access the new data. Correct?
I see basically two approaches:
- If you have exactly one instance of Settings for your whole application, it might make sense to provide a global instance (singleton) for it.
- If your classes have to use different instances of Settings, you can use pointers or references within your classes. And before you consider smart pointers, let's think about using normal pointers or references.
Smart pointers do some magic for you, but as every good wizard will tell you, magic comes at a price. And I'm not only talking about performance here. In my view, smart pointers make the program more complex, because there are suddenly more factors that affect the lifetime of an object. When the destructor of a class is called can be important, because it may destruct other classes, call cleanup functions, even emit signals. Call a destructor at the wrong moment, and your program may crash.
When you manage the lifetime of your objects yourself, you can keep things simpler and clearer. Smart pointers are useful where this is either not possible, or not desired for some good reason. With the exception of implicit sharing, I rarely use smart pointers. I see them as a special tool that waits in the drawer for a special case where I need it.
(I admit this is a matter of philosophy, and I'm sure other developers will disagree)
Anyway, back to your code. Ask yourself these questions:
- Who creates the settings, and who should destroy them?
- Do you have an object that manages both PlotManager and CurveManager? Would that be a good place to control the lifetime of your Settings class?
- If you don't have such an object: How will PlotManager and CurveManager ever know about each other? How can you create a PlotManager with a new Settings object, and when you create a CurveManager it already knows a Settings object exist and automatically uses it?