Introduction
This is my second article on Qt. I recommend to everyone who is interested in C++ to have a look at this great framework.
Sometimes when I code, I think, "hmm, this hard value coded should be in a preference file", but if I do with, I have to make a GUI interface to change this preference by user. And sometimes, I don't have enough time. But the project continues and at one moment, I have to do this. I have worked in a company for software with something around 1000 preferences entry. So we make a system to have a GUI to change these preferences settings. It's a sophisticated one with XML file described in the INI file. Here, I want to show you how I make a simple one.
I want a system where the type of the setting entry is in the name of the Key of INI file. I have to make a GUI to watch and set the setting of an application. Qt has an object to make that, it's a really good one: QSettings
. So I have an idea, and I want to share with you it. The settings are saved in the common INI format (key = value). I want to generate my UI dynamically from the definition of the key's name. To do this, I have to type my key value. I do this by the prefix of the name of the key in INI file.
str_
: string
int_
: integer bool_
: boolean path_
: path filename list_
: path filename combo_
: an index in a list font_
: a font color_
: a color
My INI file should be like:
[FirstSection]
str_Name=titi
int_CacheMegaByte=0
path_FilePath=titi
[SecondSection]
combo_ChooseInCombo=0
ChooseInCombo.value=tutu:toto:titi
path_OtherPath=C:/Qt/2010.05/QsettingUI-build-desktop/Makefile.Release
And I finally get this:
But I also want to have some parameters for some preference, like when it's a path on filesystem
, I want to be sure it exists, or for an integer preference, I want to set the minimum and maximum value. So my solution is to eliminate the type of the key and add like a member of class like this:
int_CacheMegaByte=0
CacheMegaByte.min=0
CacheMegaByte.max=10
min
and max
describe the minimum and the maximum of the preference CacheMegaByte
and the type of this preference is int
. If there's an error, then there's a messageBox
when user wants to save.
Using the Code
So in the MainWindow
, there's a method call:
void MainWindow::buildUIFromQSetting(QSettings *settings)
I use a QToolBlox to add section of INI, and in the widget added, I add GUI preference INI widgets. In the above example, there are two sections (FirstSection
and SecondSection
) and I store the widget in a FormLayout
, to have a coherent layout between entries.
This parses the INI file and creates a widget in its function:
void MainWindow::buildUIFromQSetting(QSettings *settings)
{
QWidget *wid = new QWidget(ui->toolBox);
QFormLayout *layout = new QFormLayout();
wid->setLayout(layout);
ui->toolBox->addItem(wid,s);
settings->beginGroup(s);
QStringList lstKeys = settings->childKeys();
foreach(QString k,lstKeys)
{
IprefWidget *prefW=NULL;
QStringList split = k.split("_");
if (split.length()>1)
{
if (split[0]=="str")
{
prefW = new strPrefWidget(settings,s,k,layout);
}
if (split[0]=="int")
{
prefW = new intPrefWidget(settings,s,k,layout);
}
if (split[0]=="path")
{
prefW = new pathPrefWidget(settings,s,k,layout);
}
if (split[0] == "combo")
{
prefW = new comboPrefWidget(settings,s,k,layout);
}
if (split[0] == "font")
{
prefW = new fontPrefWidget(settings,s,k,layout);
}
if (split[0] == "color")
{
prefW = new colorPrefWidget(settings,s,k,layout);
}
if (split[0] == "bool")
{
prefW = new boolPrefWidget(settings,s,k,layout);
}
if (split[0] == "file")
{
prefW = new filePrefWidget(settings,s,k,layout);
}
}
if (prefW != NULL)
{
prefWidgetsList.append(prefW);
}
}
settings->endGroup();
}
}
All widgets for the GUI preference setting are inherited from IprefWidget
and have to implement:
virtual QVariant getValue() =0;
For example: the GUI for a simple string
implementation is:
#include <QLineEdit>
#include "prefWidget/iprefwidget.h"
class strPrefWidget : public IprefWidget
{
public:
strPrefWidget(QSettings *settings,const QString &group,
const QString &nameKey,QWidget *parent = 0);
virtual QVariant getValue();
protected:
QLineEdit *edit;
};
strPrefWidget::strPrefWidget(QSettings *setting,const QString &group,
const QString &nameKey,QWidget *parent) : IprefWidget(setting,group,nameKey,parent)
{
edit = new QLineEdit(this);
edit->setText(setting->value(nameKey).toString());
_layout->addWidget(edit);
}
QVariant strPrefWidget::getValue()
{
QVariant result;
if (_regexp.isEmpty() == false)
{
if (_regexp.exactMatch(edit->text()) == false)
{
return result;
}
}
QVariant result;
result.setValue(edit->text());
return result;
}
The different options of type INI with possible restrictions are:
path | .pathMustExist verifies if path exists |
file | .pathMustExist verifies if file exists |
int | .min .max test id the value enter is superior of min or inferior of max |
str | .regexp verifies if entry is exact match with regexp |
bool | |
font | |
color | |
combo | .value gives value of list in combo |
The object architecture is:
Later when you want to save the object, you have to do:
void MainWindow::saveSettings()
{
QSettings settings("settings.ini", QSettings::IniFormat );
for (int n=0;n<prefwidgetslist.length();n++) {
settings.setValue( prefWidgetsList[n]->groupKey(), prefWidgetsList[n]->getValue());
}
}
And that does the job. Your settings are saved according to the GUI.
Points of Interest
It's interesting to have a GUI automatically generated, but it's limited ... I know that. But this method is more a tip to make a GUI fast. I hope you will find it useful.
History
I made modifications from message of The Code Project community. I hope my article is better now, not perfect of course, but better.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.