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
Related
I am having issues with an assignment from class. We are provided with website that on the backend has several images of various animals. We are supposed to be able to type in the name of the animal and the pictures corresponding to the name of the animal will appear below. This is all within a search.h file and in C++.
The professor went over the topic very quickly in lecture with not much explanation on how to continue. I have been searching for possible solutions to get data from a vector and have tried using map operations but to no avail. I am not very familiar with C++. I will provide the code below. What steps shall I take next?
#include <server.h>
ucm::json big5;
std::vector<std::string> lions = {"lion-1.jpeg", "lion-2.jpeg", "lion-3.jpeg", "lion-4.jpeg"};
std::vector<std::string> rhinos = {"rhino-1.jpeg", "rhino-2.jpeg", "rhino-3.jpeg", "rhino-4.jpeg"};
std::vector<std::string> buffalos = {"buffalo-1.jpeg", "buffalo-2.jpeg", "buffalo-3.jpeg", "buffalo-4.jpeg"};
std::vector<std::string> elephants = {"elephant-1.jpeg", "elephant-2.jpeg", "elephant-3.jpeg", "elephant-4.jpeg"};
std::vector<std::string> leopards = {"leopard-1.jpeg", "leopard-2.jpeg", "leopard-3.jpeg", "leopard-4.jpeg"};
void init(){
big5["lion"] = lions;
big5["rhino"] = rhinos;
big5["buffalo"] = buffalos;
big5["elephant"] = elephants;
big5["leopard"] = leopards;
}
ucm::json search(std::string key){
// Provide your code here
// This function should return a specific animal category, specified by key
// The function should return an appropriate message if the key is not found
}
ucm::json getAll(){
// This should return all the data we have
ucm::json temp;
temp["lion"] = big5["lion"];
return big5;
}
Again I'm not asking for the solution but just a starting point.
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.
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.
I have a QList which contains string, int, double and date values. I want to convert the QList to a QString and return it within a QString returning function. Is there a static function I can use or what am I missing here? My current code:
QString Product::toString()
{
QStringList listString;
QString outString;
for(int i =0; i < size(); i++)
{
listString << at(i)->toString();
}
outString = listString.join("\n");
return outString;
}
Notes:
I am assuming Product::at(int)is returning a Transaction, given a previous question.
I am also assuming OP mean "built-in" when he or she wrote"static"
The for can be removed using built-in functions. Some (many?) will find the new syntax less understandable, though.
QString Product::toString()
{
QStringList aggregate;
std::transform(m_transactions.begin(),
m_transactions.end(),
std::back_inserter(aggregate),
std::bind(std::mem_fn(&Transactions::toString), std::placeholders::_1));
// or : [](const Transaction& transaction){ return transaction.toString(); });
return aggregate.join("\n");
}
std::transform will transform every m_transactions elements using Transaction::toString(), and place the results into aggregate.
std::back_inserter means "use QStringList::push_bask to record the results". If QStringList had a resize(int) like QVector does, we could have used aggregate.begin() instead.
The unary function is a bit tricky, as it needs to be converted into a unary function, which what std::bind/std::mem_fn is doing. If you are using C++11, you can use a lambda instead.
Also from the previous question, #SingerOfTheFall's remark is valid:
I also find it a little odd to save transactions inside of products. A
better design would be having a separate class that could store them.
If you keep this design, Transaction Product::at(int) and int Product::size() should be renamed to make the link with Transaction explicit, like getTransaction and getNumberOfTransactions.
After reading Save QList<int> to QSettings, I'm tring to do the same with QMap<QString,int>. I would like the configuration file to look like this:
1111=1
2222=3
4444=0
But I'm getting a compilation error:
Q_DECLARE_METATYPE(QMap<QString,int>)
Warning C4002: too many actual parameters for macro 'Q_DECLARE_METATYPE'
ConfigSettings.h(5) : error C2976: 'QMap' : too few template arguments
The error message you're getting is caused by the fact that the preprocessor doesn't know about templates. So it's parsing that macro call is if it had two arguments - QMap<QString and int>, which makes no sense.
To save the data as you want it, you're better of serializing it yourself to your QSettings. Something like this for writing:
settings.beginGroup("Whatever");
QMap<QString, int>::const_iterator i = map.constBegin();
while (i != map.constEnd()) {
settings.setValue(i.key(), i.value());
++i;
}
settings.endGroup();
To read the settings, use the same approach with the help of the childKeys() function.
settings.beginGroup("Whatever");
QStringList keys = settings.childKeys();
foreach (QString key, keys) {
map[key] = settings.value(key).toInt();
}
settings.endGroup();
Like Mat said, the error is caused by the preprocessor not understanding templates. However, you can easily fix this via a simple typedef.
typedef QMap<QString,int> QIntMap
Q_DECLARE_METATYPE(QIntMap)
QSetting accept QVariant type to pass into setValue method, so it means that you can store QMap<QString, QVarint> map directly to settings
// Store
QMap<QString, QVariant> storeMap;
QMapIterator it(myMap);
// iterate through the map to save the values in your chosen format
while(it.hasNext())
{
storeMap[it.key()] = QVariant(it.value());
it.next();
}
settings.setValue("myKey", storeMap);
..
// Read
QMap<QString, QVariant> readMap = settings.value("myKey").toMap();
QMapIterator it(readMap);
while(it.hasNext())
{
myMap[it.key()] = it.value().toInt();
it.next();
}
I understand the accepted answer, but I think the original question was how to store the QMap. It devolved into how to make the compiler behave.
QSettings mySettings...
QMapIterator it(myMap);
// iterate through the map to save the values in your chosen format
while(it.hasNext())
{
it.next();
mySettings.setValue(it.key(), it.value());
}
If however you wish to store this along with a bunch of other settings or data structures, you might consider using "beginGroup()" and "endGroup()" to group a bunch of different data structures into one file. Very tidy and readable.