QstringList to Qstring conversion issues - c++

I am working on VS2015 with qt framework. In my source code, I have a function for printing in the GUI screen.
This function is called each time something needs to be printed.
It goes like this.
void Trial::Print_MessageBox(QString string)
{
ui.MessagesScreen->appendPlainText(string);
Cursor_Messagebox.movePosition(QTextCursor::End);
ui.MessagesScreen->setTextCursor(Cursor_Messagebox);
ui.MessagesScreen->ensureCursorVisible();
}
// Output in MessageBox
void Trial::Print_MessageBox(QFlags<QNetworkInterface::InterfaceFlag> flags)
{
QString str = QString("Flag %1").arg(flags);
ui.MessagesScreen->appendPlainText(str);
}
The above function has no problems and running well.
Now I am trying to read a text file. This has set of values in no order or size. An example for this:
231, 54, 4 \n
47777, 2211, 676, 9790, 34236, 7898\n
1, 3\n
Objective is to convert these into integers (line by line) and print them in the GUI and also send them (line by line) to other system. So I tried to do it with the following.
void Trial::ReadFile_Data()
{
QFile file("input.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
Print_MessageBox("Error in reading File");
return;
}
QTextStream in(&file);
while (!in.atEnd())
{
QString line = in.readLine();
Print_MessageBox(line);
int conv = line.toInt();
QString str = QString("%1 %2").arg("Values are: ").arg(conv);
Print_MessageBox(str);
QStringList fields = line.split(",");
}
file.close();
}
When I print the "line", it is just printing the same values as in the file. When I do the conversion and printing, I get an error (which is expected) Now I try to remove "," with the help of split then I get QstringList which I cannot use as I have the Qstring function to print(this cant be changed)
I am not getting any pointers from here. Please help me out as this is bugging me since long time.

Just simple...
QStringList::const_iterator constIterator;
for (constIterator = fonts.constBegin(); constIterator != fonts.constEnd();
++constIterator) {
cout << (*constIterator).toLocal8Bit().constData() << endl;
}
where fonts is your QStringlist

Your question reduces to "How do I iterate over a QStringList".
Like this:
// C++11
for (auto field : fields) Print_messageBox(field);
// C++98
foreach (QString field, fields) Print_messageBox(field);
See here for information about how foreach a.k.a Q_FOREACH was implemented.

Related

Serializing/parsing multiple objects in one file in Qt C++

I need to serialize and parse multiple objects from my project, in order to save/load them when needed.
My objects will have exactly the same components : a QString name, an integer id, a QString description, and two integer x, y.
I'll need something like this :
{"name":"toto", "id":"42", "description":"tata", "x":"20", "y":"50"}
So I'll build my QJsonObject like this :
QJsonObject json;
json["id"] = object_to_serialize.get_id();
json["name"] = object_to_serialize.get_name();
json["description"] = object_to_serialize.get_description();
json["x"] = object_to_serialize.get_x();
json["y"] = object_to_serialize.get_y();
QJsonDocument filedoc(json);
file.write(filedoc.toJson);`
And in the file it will appear like this :
{"name":"toto", "id":"42", "description":"tata", "x":"20", "y":"50"}
{"name":"toto2", "id":"44", "description":"tata2", "x":"25", "y":"547"}
{"name":"toto3", "id":"46", "description":"tata3", "x":"21", "y":"580"}
My serialiser will take in parameter the object, the savefile name, and transform the object into a QJsonObject. It will need then to read the file to check if an object with the same id is here. If it is here, it will need to replace it, and if it is not, it will append it.
I'm a little lost between my serialization options and how to read it ;
Should I make a QJsonArray with multiple QJsonObject inside or QJsonObject with QJsonArrays ?
When I read it, I will need to check for the id ; but will a
foreach(object.value["id"] == 42)
//create the QJsonObject from the one with 42 and change it with the new data
will do to parse the object and not all of them ? Is there a better way ?
Thank you in advance for your answers.
You can have an array of json object, each of them having an ID so you can parse the relevant ones.
Although you could also parse all of them and add them in a map, as long as you don't have very heavy files it should be fine.
void parseJson(const QString &data)
{
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8());
if (doc.isNull())
{
war("invalid json document");
return;
}
QJsonArray jsonArray = doc.array();
foreach (const QJsonValue & value, jsonArray) {
QJsonObject obj = value.toObject();
if (obj.contains("id"))
{
if (obj["id"].toInt() == yourId) parseObject(obj);
}
}
}
void parseObject(const QJsonObject &obj)
{
if (obj.contains("valueA")) valueA = obj["valueA"].toDouble();
if (obj.contains("valueB")) valueB = obj["valueB"].toDouble();
}
This will work just fine if your file is not too big
Bigger Files
Now if you have very large file, it might be an issue to load it all in memory and parse it.
Since your structure is always the same and quite simple, JSON might not be the best choice, one more efficient method would be to do your own parser (or use probably some existing ones) that could read the file and process it as a stream.
Another method, would be to have one JSON entry per line preceded by an ID with a fixed number of digit. Load this in a QHash lookup and then only read id of interest from the file and only parse a small section.
// This code is not tested and is just to show the principle.
#define IDSIZE 5
QHash<int64, int64> m_lookup; // has to be global var
// For very large file, this might take some time and can be done on a separate thread.
// it needs to be done only once at startup (given the file is not modified externally)
void createLookup(const QString &fileName)
{
QFile inputFile(fileName);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
while (!in.atEnd())
{
int position = in.pos(); // store the position in the file
QString line = in.readLine();
int id = line.mid(0,IDSIZE).toInt(); // 5 digit id (like 00001, 00002, etc...
m_lookup[id] = position + IDSIZE;
}
inputFile.close();
}
}
QString getEntry(const QString &fileName, int64 id)
{
if (m_lookup.contains(id))
{
QFile inputFile(fileName);
if (inputFile.open(QIODevice::ReadOnly))
{
inputFile.seek(m_lookup[id]);
QString data = inputFile.readLine();
inputFile.close();
return data;
} else {
return QString(); // or handle error
}
} else {
return QString(); // or handle error
}
}
// use example
QString data = getEntry(id);
if (data.length() > 0)
{
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8());
if (!doc.isNull())
{
// assign your variables
}
}
and your data file looking like this:
00042{"name":"toto", "id":"42", "description":"tata", "x":"20", "y":"50"}
00044{"name":"toto2", "id":"44", "description":"tata2", "x":"25", "y":"547"}
00046{"name":"toto3", "id":"46", "description":"tata3", "x":"21", "y":"580"}
The advantage of this method, it will only read the entry of interest, and avoid having to load MB or GB of data in memory just to get a specific entry.
This could further be improved with a lookup table stored at the beginning of the file.

How do I get the value of text inside of the file using Qt?

The data of my file.txt is as below:
Student_ID=0001
Student_Name=joseph
Student_GradeLevel=2
How do I get the value, let say I want to get the Student_ID using Qt.
Thanks.
Take a look at this function, it can be used to find any value you want in your input file, where all lines are in the format you've posted above (key=value). If the key is not found, it returns an empty QString() object.
QString findValueInFile(QString key, QString filename) {
QFile file(filename);
if(file.open(QIODevice::ReadOnly)) {
QTextStream txtStr(&file);
QStringList fileContent = txtStr.readAll().split('\n');
for(auto &&line : fileContent) {
if(line.contains(key)) return line.split(QChar('='))[1];
}
file.close();
}
return QString(); // not found
}
Now you call it somewhere, e.g.:
qDebug() << findValueInFile("Student_ID", "file.txt");
qDebug() << findValueInFile("Student_Name", "file.txt");
This function can be easily modified if you replace your = sign with other delimiter e.g. => or sth else. However for key=value format there is a special QSettings class (mentioned by sebastian) that can allow you to read those values even easier:
QSettings file("file.txt", QSettings::IniFormat);
qDebug() << file.value("Student_Name").toString(); // et voila!
You can probably also use QSettings, as they are able to read ini files.
There are some caveats though regarding backslashes which might be important to you (though they aren't for the example you posted): http://doc.qt.io/qt-4.8/qsettings.html#Format-enum
QSettings iniFile("myfile.txt", QSettings::IniFormat);
// now get the values by their key
auto studentId = iniFile.value("Student_ID").toString().toInt();
I'm more of a PyQt user, so: apologies if I got some C++ specifics wrong...

Spliting string and displaying in Qtreewidget

My programming knowledge and experience is very poor. I am using this code block to open the desired file when clicked on a push button ;
QString filename = QFileDialog::getOpenFileName();
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
while (!file.atEnd())
{
QByteArray line = file.readLine();
processline(line);
}
And by this line i am showing it on QtextBrowser
void MainWindow::processline(QByteArray paramline)
{
ui->veri_cikis->append(paramline.constData());
}
The data on the file is like this
0;100;0
0;100;24
24;500;24
24;100;6
6;100;6
i have to split the datas by ";" mark and display them on a Qtreewidget columns. How do i do that ? And i have to show each first part on first column and second on second column and so. I have 3 columns in total
I think what you describe is better fit rather to a table view than a tree view. To parse your strings and split them by ';' character you can use QByteArray::split() function. Here is the sample code, that creates and populates table view with items that read from the file:
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTableWidget *table = new QTableWidget;
int row = 0;
while (!file.atEnd()) {
QByteArray line = file.readLine();
QList<QByteArray> tokens = line.split(';');
int column = 0;
row++;
foreach (QByteArray ba, tokens) {
QTableWidgetItem *item = new QTableWidgetItem(ba);
table->setItem(row, column++, item);
}
}

Creating an Efficient Function

I am a beginner in my fourth week learning C++; I had been working on CodeBlocks, but due to my interest in making GUIs I switched to Qt Creator. Back in CodeBlocks I had created a function that would avoid all the repetition in the code below, only changing the "TXT FILE". However, with Qt Creator's "specialized" C++ I am having trouble making sense of how to create a function to avoid all this repetition.
Any ideas? (I'm too far into this Qt project to go back to CodeBlocks.)
The "TXT FILE" changes depending on which RadioButton the user selects.
void MovierRec::on_searchButton_clicked()
{
int randomValue = qrand() % 100;
QList<QString> titles;
if(ui->modernButton->isChecked())
{
QFile myfile(":/classics.txt");
if (myfile.open(QIODevice::ReadOnly))
{
QTextStream in(&myfile);
while (!in.atEnd())
{
QString line = in.readLine();
titles.append(line);
}
myfile.close();
ui->textBrowser->setPlainText (titles[randomValue]);
}
}
else if(ui->romanceButton->isChecked())
{
QFile myfile(":/romance.txt");
if (myfile.open(QIODevice::ReadOnly))
{
QTextStream in(&myfile);
while (!in.atEnd())
{
QString line = in.readLine();
titles.append(line);
}
myfile.close();
ui->textBrowser->setPlainText (titles[randomValue]);
}
}
else if(ui->scifiButton->isChecked())
{
QFile myfile(":/scifi.txt");
if (myfile.open(QIODevice::ReadOnly))
{
QTextStream in(&myfile);
while (!in.atEnd())
{
QString line = in.readLine();
//titles.append(line);
}
myfile.close();
ui->textBrowser->setPlainText (titles[randomValue]);
}
}
This is generic programming issue, could refactor code in a better way:
// I didn't dig into every line of the code. just provide the refactor idea here
void getTitle(const QString& file_name, QList<QString>& titles;)
{
QFile myfile(file_name);
if (myfile.open(QIODevice::ReadOnly))
{
QTextStream in(&myfile);
while (!in.atEnd())
{
QString line = in.readLine();
titles.append(line);
}
myfile.close();
}
}
void MovierRec::on_searchButton_clicked()
{
int randomValue = qrand() % 100;
QList<QString> titles;
if(ui->modernButton->isChecked())
{
getTitle("classics.txt", titles);
}
else if(ui->romanceButton->isChecked())
{
getTitle("romance.txt", titles);
}
else if(ui->scifiButton->isChecked())
{
getTitle("scifi.txt", titles);
}
ui->textBrowser->setPlainText(titles[randomValue]); // move the dup action to the end
}
QT is well known for Signals and Slots. Each button can be connected to a slot. For Example in your case. You can connect each radio button to a slot. in order to do that, Open ur GUI form, right click on the radio button and select "Go To Slot", and select the slot you want to connect to.
This will create an empty function in ur .cpp file.
Now write your code for that button. And this function is called only when that particular Button is pressed/clicked .
example:
void ClassA::on_radioButton_clicked()
{
// write your code inside this function for , when this button is checked
}
I hope this will help you solve your issue. If you have other query , please provide more information.

Qt QTextEdit loading just half text file

I have a problem: my project is a very simple one with a QTextEdit and a QSyntaxHighlighter, I'm trying to load a .cpp file and highlighting just the eighth line of that file, but the QTextEdit can't load the entire file if I ask it to highlight the line.
The following image shows the problem:
The relevant code of the application is the following:
void MainWindow::openFile(const QString &path)
{
QString fileName = path;
if (fileName.isNull())
fileName = QFileDialog::getOpenFileName(this,
tr("Open File"), "", "C++ Files (*.cpp *.h)");
if (!fileName.isEmpty()) {
QFile file(fileName);
if (file.open(QFile::ReadOnly | QFile::Text))
editor->setPlainText(file.readAll());
QVector<quint32> test;
test.append(8); // I want the eighth line to be highlighted
editor->highlightLines(test);
}
}
and
#include "texteditwidget.h"
TextEditWidget::TextEditWidget(QWidget *parent) :
QTextEdit(parent)
{
setAcceptRichText(false);
setLineWrapMode(QTextEdit::NoWrap);
}
// Called to highlight lines of code
void TextEditWidget::highlightLines(QVector<quint32> linesNumbers)
{
// Highlight just the first element
this->setFocus();
QTextCursor cursor = this->textCursor();
cursor.setPosition(0);
cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, linesNumbers[0]);
this->setTextCursor(cursor);
QTextBlock block = document()->findBlockByNumber(linesNumbers[0]);
QTextBlockFormat blkfmt = block.blockFormat();
// Select it
blkfmt.setBackground(Qt::yellow);
this->textCursor().mergeBlockFormat(blkfmt);
}
However if you want to test the project with the cpp file I used (in the directory FileToOpen\diagramwidget.cpp), here's the complete source
http://idsg01.altervista.org/QTextEditProblem.zip
I've been trying to solve this for a lot of time and I'm starting to wonder if this isn't a bug or something similar
The QTextEdit can't accept such a big amount of text at one piece. Split it, for example like this:
if (!fileName.isEmpty()) {
QFile file(fileName);
if (file.open(QFile::ReadOnly | QFile::Text))
{
QByteArray a = file.readAll();
QString s = a.mid(0, 3000);//note that I split the array into pieces of 3000 symbols.
//you will need to split the whole text like this.
QString s1 = a.mid(3000,3000);
editor->setPlainText(s);
editor->append(s1);
}
It seems that the QTextEdit control needs time after each loading, setting a QApplication:processEvents(); after setPlainText() solves the problem although it's not an elegant solution.