How Do I Save and Load Data Using QSettings? - c++

I'm a complete beginner to QT5, I searched YouTube for any QSettings tutorials and only found 2 of them, both in Spanish.
I'm trying to store simple text from a textEdit and then load it on save/load button click. So far I have not been able to accomplish this. Here's my code so far, no errors, it just doesn't work.
Widget.cpp
void Widget::saveText(QString key, QString text)
{
QSettings settings("App", "BillReminder");
settings.beginGroup("Text");
settings.setValue(key + "t", text);
settings.endGroup();
}
QString Widget::loadText(QString key)
{
QSettings settings("App", "BillReminder");
settings.beginGroup("Text");
settings.value(key + "t", text).toString();
settings.endGroup();
return QString(text);
}
void Widget::on_saveButton_clicked()
{
saveText("textEdit", text);
}
void Widget::on_loadButton_clicked()
{
QString text1 = loadText(text);
ui->textEdit->setText(text1);
}
widget.h - class Widget : public QWidget
private:
Ui::Widget *ui;
QString text;
void saveText(QString key, QString text);
QString loadText(QString key);
void SetText(QString key);

The problem is in your loadText() method. QSettings::value() is a function that returns a value retrieved from the QSettings storage. The second parameter is only a default value, that would be returned in case your settings storage doesn't contain the requested key.
QString Widget::loadText(QString key)
{
QSettings settings("App", "BillReminder");
settings.beginGroup("Text");
QString theValue = settings.value(key + "t", text).toString();
settings.endGroup();
return theValue;
}

This code example contains many issues.
don't shadow variable names (e.g. "text" is method argument and member variable); use e.g. underscore to indicate member variables
above answer about reading values as return value solve one issue as well
on_saveButton is using as a settings key a "textEdit" string but on_loadButton is used wrong "text" member variable string as key -> you want use the same string to load stored variable i.e. you are reading something else just now.
you are saving member variable "text" that is not initialised in your example i.e. it may be empty; and later you are setting UI text edit with stored settings (empty string in your example?)
Please go through QSettings Qt documentation for working example.

Related

How to use QStringList to store multiple strings

I'm using QT framework to create an employee interface which stores information of an employee (ID, name, surname, skills, ecc..)
In the widget interface I've used a lineEdit for everything since I need to store string types of information, the only exception of parameter skills that should be a list of strings
In my mainwindow.cpp however I should store a list of different skills, not just one, and that's get me the error when I use my function .addEmployee() because it wants a list of skills, not one string.
I should use QStringList skills but how can I tell the user is inserting different skills and store them as a list?
void MainWindow::on_add_pushButton_clicked()
{
QString id = ui->id_lineEdit->text();
QString nome = ui->name_lineEdit->text();
QString cognome = ui->surname_lineEdit->text();
QString skills = ui->skills_lineEdit->text();
// should be QStringList skills but how can I tell the user is inserting different skills?
manage.addEmployee(id.toStdString(), name.toStdString(), surname.toStdString(), skills.toStdString());
// manage refers to the class manageEmployee.h I already implemented to use function addEmployee(id, name, surname, {skills});
}
The question is a bit unrefined, but I will try my best to answer based on what I could follow.
void MainWindow::on_add_pushButton_clicked()
{
QString id = ui->id_lineEdit->text();
QString name = ui->name_lineEdit->text();
QString surname = ui->surname_lineEdit->text();
QString skills = ui->skills_lineEdit->text();
QStringList skillsList = skills.split(","); // or ";", etc.
std::list<std::string> skillsStdList;
for (const QString& qstr : skillsList) {
skillsStdList.push_back(qstr.toStdString());
}
manage.addEmployee(id.toStdString(), name.toStdString(), surname.toStdString(), skillsStdList);
}
So if you want the user to input list of skills, you wanna be splitting them using a delimiter as well.
Then you can pass the resulting QStringList to .addEmployee assuming it takes a fourth argument std::list<std::string>
By using a delimiter, you allow the user to enter multiple skills as a single input, which simplifies the interface. However, you should make sure to handle any errors that can arise from invalid input, such as an empty or malformed input string.
Edit: Code updated in mind with QList<Qstring> not supporting toStdString method

How to get data in form of QString from QVariant in Qt5?

I have a QVariant with userType QVariantList and the exact format looks like this when i qDebug the qvariant
QVariant(QVariantList, (QVariant(QVariantMap, QMap(("name", QVariant(QString, "UK English Female"))))
I want QString, "UK English Female" from the variant how can i get that i have already tried QVariant.toStringList() but the stringlist is empty.
Thanks.
From what is shown as a debug output, I presume it was produced in a similar manner:
QVariantMap map;
map.insert("name", QVariant("UK English Female"));
qDebug() << QVariant(QVariantList{QVariant(map)});
and as a result you have a string data, which is burried relatively deep in a sequence of containers.
So, how to get there?
As a whole you have a QVariant holding a QVariantList with a single QVariant value, which in turn is a QMap. The map has a key name of type QVariant holding a QString. Chaining the necessary conversions, we end up with:
qDebug() << myVar.value<QVariantList>().first().toMap().value("name").toString();
assuming the whole thing is held in QVariant myVar;.

check/determine if QString contains html

Since I wasn't able to find a suitable solution here, I wanted to Q&A this question:
Is there a way to determine if a QString is made of html, i.e. is rich-text, (or at least, contains html)?
This may be the case for unknown/QVariant calls to setData of data editors in the table/view model.
A solution can be to use Qt::mightBeRichText for QString:
#include <QTextDocument>
QString ensurePlainText(const QString& text)
{
QString out;
if (Qt::mightBeRichText(text))
{
// is html -> convert to plain text
QTextDocument text;
text.setHtml(value.toString());
out = text.toPlainText();
}
else
{
out = text;
}
return out;
}
It is important to note that the presented method uses a heuristic. It may fail to detect html or falsely detect html in a non-html text. The former may return html tags in the string. The latter would, for instance, strip newline characters from the text.

How to save and load a QJsonDocument to a file?

I am trying to learn how to use JSON and the Qt JSON classes. For example I wnat to create a simple QJsonDocument, save it to a file, load it into a different QJsonDocument and compare results.
I managed to create a QJsonDocument. However there is no simple command in the QJsonDocument interface to save it to a file. The same goes for loading the document from a file.
#include <QJsonObject>
#include <QJsonDocument>
#include <QVariant>
int main()
{
QVariantMap map;
map.insert("integer", 1);
map.insert("double", 2.34);
map.insert("bool", QVariant(true));
map.insert("string", "word");
QJsonObject object = QJsonObject::fromVariantMap(map);
QJsonDocument document;
document.setObject(object);
// ?? save document to file
// ?? load file to document
return 0;
}
This answer shows how to load the document by
reading to a QFile
converting QFile to a QString
converting the QString to a QByteArray
constructing the QJsonDocument from the QByteArray
Is there a more straightforward way to do this?
Personally, I think that code [that you linked to] looks a bit messy. Warning: head compiled code follows.
QJsonDocument loadJson(QString fileName) {
QFile jsonFile(fileName);
jsonFile.open(QFile::ReadOnly);
return QJsonDocument().fromJson(jsonFile.readAll());
}
void saveJson(QJsonDocument document, QString fileName) {
QFile jsonFile(fileName);
jsonFile.open(QFile::WriteOnly);
jsonFile.write(document.toJson());
}
This may not be perfect: it assumes QFile instead of QIODevice, but if you're dealing with only local files maybe it won't matter. You can then use these functions instead of repeating the Json load/save code everytime you need to load/save Json.
No need for converting to string and back. With QSettings and QVariant classes you can easily do that. Create QVariant object from QJsonDocument and save it with QSettings. Look at functions QJsonDocument::fromVariant and QJsonDocument::toVariant. Combine them with QSettings class and specifically void QSettings::setValue ( const QString & key, const QVariant & value ) method, that works well with QVariant and that's it.
Also QSettings class has this constructor QSettings::QSettings ( const QString & fileName, Format format, QObject * parent = 0 )
that would allow you to set path to the file - fileName variable

QValidator prevents intermediate typing

I have a QLineEdit that accepts a string that will be evaluated at a javascript expression like "[0,3]" and connected to fire changes using editingFinished(). I added a validator so the user couldn't leave the input with a bad expression, but apparently I'm misunderstanding how the validator works, because if I return QValidator::Invalid, when the expression wouldn't be valid, user's can't type any mistakes (character won't disappear on backspace). For example, temporarily changing "[0,3]" to "[0,]" to fill in another number.
I've tried changing the validator to return to QValidator::Intermediate on bad expressions thinking that would be a happy medium letter users alter text, but setting bad text back to its previous value on unfocused or return, but that seems to let user's put in anything that want. For example, they can type in "[0," and click on something else and the input still has "[0," in it as opposed to jumping back to the way it was. Am I misunderstanding how the intermediate type works?
QValidator::Invalid 0 The string is clearly invalid.
QValidator::Intermediate 1 The string is a plausible intermediate value.
QValidator::Acceptable 2 The string is acceptable as a final result;
i.e. it is valid.
Here is my current validator, which I just put on a QLineEdit:
class PointFValidator : public QValidator
{
QValidator::State validate(QString &input, int &position) const;
void fixup(QString &input) const;
};
QValidator::State PointFValidator::validate(QString &input, int &position) const
{
try {
evalPointF(input);
} catch (std::exception &e) {
return QValidator::Invalid;
}
return QValidator::Acceptable;
}
void PointFValidator::fixup(QString &input) const
{
}
And this is what actually tests the string to see if it's formatted correctly
QPointF evalPointF(QString s)
{
//initGuile();
QScriptEngine engine;
QString program = "function frame() { return 9; }\n\n" + s;
QScriptValue value = engine.evaluate(program);
QStringList pair = value.toString().split(",");
if (pair.length() < 2)
throw std::runtime_error("invalid pointf string");
return QPointF(pair[0].toFloat(), pair[1].toFloat());
}
Is the QValidator not what I need? Is it only for typing prevention? Do I need to listen to the change event, validate it myself, and set it back if it's not valid?
So trying to compile your code didn't work for me. The constness of the virtual functions in QValidator make it pretty much impossible to get your example code to compile.
So I would (like you mentioned at the end of your question) go and set up a signal to respond to the content changes of your QLineEdit, evaluate it, and then put the output somewhere helpful.
But based on the kinds of things you put in your evalPointF function, it looks like you are just writing an IDE for javascript.
Why not use the pattern that most IDE's already have of putting issues in another window, and using font's and formatting to modify the text, instead of actually changing the text?
Hope that helps.