Reputation: 35
consider this scenario: I need to create a ui for some settings. As, data and ui should be separated in theory, I defined a separate class which takes care of the configuration data. The question I have is how to instantiate the data class inside the settings class.
One way is to create the data class in the caller object, I mean the object that calls the settings menu class.
The other way, which my question is involved with, is to create a DATA class variable inside the settings class. I doubt what happens when the settings class gets destroyed then! would the data class object inside settings class also get destroyed? what about if it is defined as a static member of settings class?
#ifndef SETTINGSWINDOW_H
#define SETTINGSWINDOW_H
#include <QMainWindow>
#include <QModelIndex>
#include <QSignalMapper>
#include <QRadioButton>
#include <QSpinBox>
#include <QTimer>
#include "cameracommands.h"
struct Config
{
/* General Options */
QString general_key_lock;
QString general_back_light;
};
//class IConfigSource
//{
//public:
// virtual Config config() const;
// virtual void setConfig(const Config& cfg);
//};
class ConfigSource /* : public IConfigSource*/
{
public:
ConfigSource() {
config_.general_back_light = "OFF";
config_.general_key_lock = "OFF";
}
Config config() const {return config_;}
void setConfig(const Config& cfg) {config_ = cfg;}
private:
Config config_;
};
class ConfigUpdater : public QObject
{
Q_OBJECT
public:
ConfigUpdater(ConfigSource& src) : src_(src) {}
public slots:
void apply () {src_.setConfig(tempConfig_);}
void cancel() {tempConfig_ = src_.config();}
public:
void updateGeneralBackLight(QString s) {tempConfig_.general_back_light = s; qDebug() << "BackLight updated :)";}
void updateGeneralKeyLock(QString s) {tempConfig_.general_key_lock = s; qDebug() << "KeyLock updated :)";}
Config tempConfig_;
ConfigSource& src_;
};
//----------------------------
namespace Ui {
class SettingsWindow;
}
class SettingsWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SettingsWindow(QWidget *parent = 0);
~SettingsWindow();
signals:
void clicked(const QString &text);
void sendToPLC(QByteArray );
public slots:
void updateGeneralBackLight();
void updateGeneralKeyLock();
void getRow(QModelIndex);
void MySlot(QString);
private slots:
void on_pushButton_5_clicked();
void on_pushButton_3_clicked();
private:
void set_mappings();
Ui::SettingsWindow *ui;
ConfigUpdater *config_updater;
QSignalMapper *mapper;
};
#endif // SETTINGSWINDOW_H
and this is the source:
QMainWindow(parent),
ui(new Ui::SettingsWindow)
{ /* initializations */
ui->setupUi(this);
ConfigSource src;
config_updater = new ConfigUpdater(src);
Upvotes: 0
Views: 202
Reputation: 3119
Yes the data object would get destroyed when the settings object is destroyed. If you make it a static member then it would not. But that's probably not such a good idea. A better way would be to persist the data object to a file (say). You can read the file in the settings object constructor and write the file in the settings object destructor.
EDIT
class SettingsWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SettingsWindow(ConfigSource& src , QWidget *parent = 0);
...
}
SettingsWindow::SettingsWindow(ConfigSource& src , QWidget *parent)
QMainWindow(parent),
ui(new Ui::SettingsWindow)
{
ui->setupUi(this);
config_updater = new ConfigUpdater(src);
...
}
thanks, it is correct. The program terminates when I attempt to pass the below variable to the user-defined function: (inside header)
void print_config(Config cfg);
Ui::SettingsWindow *ui; ConfigUpdater *config_updater;
inside cpp:
void SettingsWindow::print_config(Config config)
{
qDebug() << config.general_back_light;
qDebug() << config.general_key_lock;
}
void SettingsWindow::on_sendToMainButton_clicked() /* cancel */
{
print_config(config_updater->tempConfig_);
print_config(config_updater->src_.config());
}
the first, print_config instruciton works fine, as for tempConfig_, but the when I pass src_ in the second statement, it jump outta program.
//------------
I know where the problem comes from, but I cannot solve it, i hope this can help:
class ConfigUpdater : public QObject
{
Q_OBJECT
public:
ConfigUpdater(ConfigSource& src) : src_(src) {}
public slots:
void apply () {src_.setConfig(tempConfig_);}
void cancel() {tempConfig_ = src_.config();}
public:
Config tempConfig_;
ConfigSource& src_;
};
Here, src_ is passed by reference, everywhere, even in the constructor of Settings window. the program fails when I attemp to access it inside memory, for example:
config_updater->cancel();
which does: void cancel() {tempConfig_ = src_.config();}
Upvotes: 0
Reputation: 29966
That depends on how do you need to use it.
Scenario 1. The settings need to be held in memory when the program is working.
Scenario 2. The settings need to be saved to the disc immediately, and then will be read on-demand.
In scenario 1, you need to be able to always access the data in the memory. So it is better to separate the settingsUI
class and the settingsData
class, so you will have access to the latter.
class settingsUI
{
<...>
private:
settingsData * data;//pointer to the data object
}
class settingsData
{
}
In scenario 2, you can aggregate settingsData
into the settingsUI
, and save the data to a file when the UI is destroyed.
class settingsUI
{
public:
<...>
~settingsUI();
private:
class settingsData
{
<..>
}data;
<...>
}
class settingsUI::~settingsUI()
{
data.saveToFile();
}
And yes, uf you aggregate settings into the UI, it will be destroyed when the UI is destroyed. Holding data as a static member is not the best idea, it is better to separate the data from the visual representation (which is in your case the UI class).
UPD:
If you want to hold it just until the program exits, I would suggest you to hold a static pointer to the data in the UI class. Here is an example with raw pointers, but you can use smart pointers too, ofc.
class data
{
}
class UI
{
private:
static data * data_;
}
data* UI::data_;
When your program starts, allocate memory for the data: UI::data_ = new data()
, and when your program ends (or if you don't need the data anymore), free the memory: delete UI::data_
. Once again, it is better to use smart pointers, so this is just an example.
Upvotes: 1
Reputation: 1382
If the settings class is used by only the UI then it makes sense to keep it within the UI class:
class Settings {
int a;
int b;
};
class Ui {
private:
Settings settings;
};
settings
will be destroyed during the destruction of Ui
.
If you are using the Settings
object in many places, it makes more sense to keep a shared pointer to it:
class Ui {
public:
Ui(std::shared_ptr<Settings> someSettings)
: settings(someSettings)
{}
private:
std::shared_ptr<Settings> settings;
};
This Settings
object will be destroyed when the last owner of the shared_ptr
is destroyed.
Upvotes: 0