Insert the value on certain line and column of text file - c++

I want to insert the value of double spin box on 14th line and 19th column of my large text file. I have created loop to insert the value on 14th line, but it is just placed on first column of the line. Can anyone help me to move the value after text, parameter PW_x = ?
This is the portion of my text file.
parameter PW_x = "i want to insert value here this is 14th line and 19th column"
parameter PW_y =
parameter PD =
parameter PC =
This is my code
void MainWindow::on_doubleSpinBox_6_editingFinished()
{
QString file("D:\\my text file name");
QFile outputFile(file);
if (outputFile.open(QIODevice::ReadWrite | QIODevice::Text))
{
for (int i=0;i<13;i++) {
outputFile.readLine();
}
QTextStream stream(&outputFile);
stream << QString::number(ui->doubleSpinBox_6->value());
}
}

As I advised in my comment, you should parse->edit->save
you can for sure use other ways to insert the value in the file, like trying to match and replace the string in each line of the file (be aware that this is very inefficient..) but here an example:
in the for loop, try to replace the string "PW_x = " with the value PW_x = 'your spinbox double', the replace action will leave intact all the lines that dont match the string you are looking for...
here an example
QString l1{"parameter PW_x = " };
QString l2{"parameter PW_y = " };
QString l3{"parameter PD = " };
QString l4{"parameter PC = " };
QString doubleAsString{"3.1415"};
l1.replace("PW_x = ", "PW_x = " + doubleAsString);
l2.replace("PW_x = ", "PW_x = " + doubleAsString);
l3.replace("PW_x = ", "PW_x = " + doubleAsString);
l4.replace("PW_x = ", "PW_x = " + doubleAsString);
qDebug() << "v1: " << l1;
qDebug() << "v2: " << l2;
qDebug() << "v3: " << l3;
qDebug() << "v4: " << l4;

Related

Value disappears from QVector

I have the QMap with QVector inside:
QMap<QString, QMap<QGraphicsView*, QVector<float>>> graphs;
I'm trying to execute this code:
QVector<float>* graphValues = &(graphs.values()[i - values.count()].values()[0]);
graphValues->push_back(1234);
qDebug() << "=== Debug messages ===\r\n";
qDebug() << "i - values.count() = " << i - values.count();
qDebug() << "graphValues = " << graphValues;
qDebug() << "*graphValues = " << *graphValues;
qDebug() << "graphs = " << graphs;
qDebug() << "graphs.values()[i - values.count()].values()[0] = " << graphs.values()[i - values.count()].values()[0];
It gives me output:
i - values.count() = 0
graphValues = 0x2000e90
*graphValues = QVector(1234)
graphs = QMap(("tempgraph", QMap((QGraphicsView(0x1fb1920) , QVector() ) ) ))
graphs.values()[i - values.count()].values()[0] = QVector()
So, where is my value? Using pointer i wait for my value in graphs, but it disappears.
QMap::values() method returns temporary object. You cannot change original data, by changing it. You should use iterators, or QMap::operator[] somehow.

Variable change without any direct action

I have wrote an API as defined below. This API is used to find the index of a filename in a file system. The filesystem is coming from an Android device through mtp. What I'm doing is to request a list of files stored on the Android device and compare each file listed to the one I'm looking for 'name2look'
I have created a vector table to store what I'm doing but it's not mandatory. My concerns is that the variable name2look contain the right name I'm looking for "Pictures"
uint32_t USBDevice::GetIndexFromName(LIBMTP_mtpdevice_t *dev, uint32_t storage,const char *name2look)
{
uint32_t idx_fold = 1;
std::vector<MyFileTreeItem*> FSimage;
LIBMTP_file_t *files;
LIBMTP_file_t *file;
std::cout << "NAME : " << name2look << "\n";
files = this->GetFileAndFolder(dev, storage,0);
file = files;
while (file != NULL) {
MyFileTreeItem* FSitem = new MyFileTreeItem();
FSitem->filename = file->filename;
FSitem->index = file->item_id;
FSitem->FileType = file->filetype;
FSimage.push_back(FSitem);
std::cout << "NAME : " << name2look << "\n";
std::cout << "FS NAME : " << file->filename << "\n";
if(std::strcmp(file->filename, name2look)==0) {
std::cout << "FIND IDX : " << file->item_id << "\n";
return file->item_id;
}
file = file->next;
}
return 0;
}
The Log is showing that the first display 'std::cout' is ok. the variable name is still 'Pictures' but when I ask to display it after in the "while" the variable name2look change and is not the same anymore.
First display
NAME : Pictures
second one in the while
NAME : Martin).mp3
FS NAME : Music
How is it possible to be corrupted ??
The function is called by a Qt C++ code:
void MyButtonGroup::buttonClick(QAbstractButton *button)
{
uint32_t status;
QList<QTreeWidgetItem *> itemList;
uint32_t index = 0;
if (button->text() == "Create Folder") {
itemList = this->MyTree->selectedItems();
QString str = itemList[0]->text(0);
char *utf8_text = str.toLatin1().data();
if(utf8_text != NULL)
{
std::cout << "A CHERCHER " << utf8_text << "\n";
index = this->MyDevice.GetIndexFromName(this->dev_id, storage->id, utf8_text);
}
else
index = 0;
CreateFolderDialog *dialog = new CreateFolderDialog(this->MyTree, this->MyDevice, this->dev_id, this->storage, index);
dialog->show();
}
utf8_text report the right value.
Any idea ?
This might be the problem. I am not sure. Check it out.
This line:
char *utf8_text = str.toLatin1().data();
What does the documentation say toLatin1() does? It creates a new QByteArray object and then you call data() on that and you get a pointer to character and then the QByteArray is destroyed at the end of the line because it was TEMPORARY.
And now you have an invalid pointer to freed memory that you then pass into your function. It probably gets overwritten by the first call to new() in your function.
I think you should change it to something like this:
QByteArray latin_str = str.toLatin1();
char *utf8_text = latin_str.data();
Your name utf8_text is weird since you just converted it to Latin1 which isn't UTF8.

Path is wrong, what to do?

I'd like to write something to my path.
My code is following
QString Log::logPacketsPath = QDir::currentPath() + "/logs/Packets/";
int userID = 1;
QString text = "test 1 2 3";
QFile logPacketFile(logPacketsPath + "UserID: " + userID + " - " + QDateTime::currentDateTime().toString("dd.MM.yy") + ".log");
if (logPacketFile.open(QFile::WriteOnly | QFile::Text | QFile::Append))
{
QTextStream out(&logPacketFile);
out << "[" << QDateTime::currentDateTime().toString("dd.MM.yy, hh:mm:ss") << "]: " << text << "\n";
logPacketFile.close();
}
But it only creates the file named "UserID" with nothing in it.
Do you know where the mistake is?
I'm not sure which OS you're using, but ':' is invalid in a Windows filename.
Next, you should flush the QTextStream before closing the file:
out.flush();
logPacketFile.close();
or create additional scope:
{
QTextStream out(&logPacketFile);
out << "[" << QDateTime::currentDateTime().toString("dd.MM.yy, hh:mm:ss") << "]: " << text << "\n";
}
logPacketFile.close();
Also, as Chemobyl has pointed out, you can get into trouble by concatinating the int userID to your filepath. I'd suggest using string formatting to create the filename:
QString logPacketFile("%1UserID%2 - %3.log")
.arg(logPacketsPath)
.arg(userID)
.arg(QDateTime::currentDateTime().toString("dd.MM.yy"));
Convert int to QString:
Use QString::number().
Output with your current code:
"C:/.../logs/Packets/UserID [bad symbols here] - 17.11.14.log"
Output with
QFile logPacketFile(logPacketsPath + "UserID " + QString::number(userID) + " - " + QDateTime::currentDateTime().toString("dd.MM.yy") + ".log");//removed colon
is:
"C:/.../logs/Packets/UserID 1 - 17.11.14.log"
It is source of big troubles. See next:
int userID = 70;
QString text = "test 1 2 3";
QFile logPacketFile(logPacketsPath + "UserID " + userID + " - " + QDateTime::currentDateTime().toString("dd.MM.yy") + ".log");
Output:
.../UserID F - 17.11.14.log"
Note F, not a 70 because operator+ thought that you use simple char and 70 in char is F:
http://www.asciitable.com/
So I strongly suggest you to use QString::number to prevent errors.

C++ Arabica (over Xerces-c) getNodeValue() method does not return the actual value

I am using Arabica wrapping over Xerces-c to parse XML. The sample code below returns correct names when using .getNodeName() method, but not the correct value when using .getNodeValue() method:
bool readXML(bfs::path xmlfullfile)
{
// first check to see if the file exists
if (!bfs::is_regular_file(xmlfullfile)) return false;
Arabica::SAX2DOM::Parser<std::string> domParser;
Arabica::SAX::CatchErrorHandler<std::string> eh;
Arabica::DOM::Document<std::string> xmlDoc;
Arabica::SAX::InputSource<std::string> is;
domParser.setErrorHandler(eh);
is.setSystemId(xmlfullfile.string());
domParser.parse(is);
if(!eh.errorsReported())
{
xmlDoc = domParser.getDocument();
xmlDoc.normalize();
Arabica::DOM::NodeList<string_type> objects = xmlDoc.getElementsByTagName("object");
for (size_t t = 0; t < objects.getLength(); t++)
{
Arabica::DOM::Node<std::string> object = objects.item(t);
Arabica::DOM::NodeList<std::string> values = object.getChildNodes();
for (size_t u = 0; u < values.getLength(); u++)
{
values.item(u).normalize();
string name = values.item(u).getNodeName();
string val = values.item(u).getNodeValue();
cout << "Node streaming = \"" << values.item(u) << "\", meaning that name = \"" << name << "\" and value = \"" << val << "\"" << endl;
}
}
return true;
} else {
std::cerr << eh.errors() << std::endl;
eh.reset();
return false;
}
}
The sample XML I'm trying to parse is:
<annotation>
<filename>1a.jpg</filename>
<folder>Sample</folder>
<source>
<database>Some database</database>
<annotation>Annotator</annotation>
<image>Some source</image>
</source>
<size>
<width>3264</width>
<height>1840</height>
<depth>0</depth>
</size>
<segmented>0</segmented>
<object>
<name>somename</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<occluded>0</occluded>
<bndbox>
<xmin>48</xmin>
<ymin>671</ymin>
<xmax>3213</xmax>
<ymax>1616</ymax>
</bndbox>
</object>
</annotation>
The output looks similar to this:
Node streaming = "
", meaning that name = "#text" and value = "
"
Node streaming = "<name>somename</name>", meaning that name = "name" and value = ""
Node streaming = "
", meaning that name = "#text" and value = "
"
Node streaming = "<pose>Unspecified</pose>", meaning that name = "pose" and valu
e = ""
Node streaming = "
", meaning that name = "#text" and value = "
"
Node streaming = "<truncated>0</truncated>", meaning that name = "truncated" and
value = ""
Node streaming = "
", meaning that name = "#text" and value = "
"
Node streaming = "<difficult>0</difficult>", meaning that name = "difficult" and
value = ""
Node streaming = "
", meaning that name = "#text" and value = "
"
Node streaming = "<occluded>0</occluded>", meaning that name = "occluded" and va
lue = ""
Node streaming = "
", meaning that name = "#text" and value = "
"
Node streaming = "<bndbox>
<xmin>48</xmin>
<ymin>671</ymin>
<xmax>3213</xmax>
<ymax>1616</ymax>
</bndbox>", meaning that name = "bndbox" and value = ""
Node streaming = "
", meaning that name = "#text" and value = "
"
Not quite sure what I'm doing wrong. Since getNodeName() returns the correct name (when it's not #text of course), the fact that getNodeValue() doesn't return anything makes me wonder.
you are counting the white-space only text-nodes as well.
Adding a DTD that doesn't allow text-nodes at that place could be helpful.
A non-validating parser has to report all the white-space nodes,
and is not allowed to make assumptions on what is ignorable and what not.
Bottomline, if you want to get rid of the white-space text nodes,
you ll have to program that yourself in your DOM program
I found a solution after comparing my code with some other XML libraries. Apparently the value of a node is not a simple text field, and one has to get the first child of that simple leaf node to be able to access the text value. Not sure if the way I'm doing it is the best way, but here is the code in case someone else has the same problem:
for (size_t u = 0; u < values.getLength(); u++)
{
string name = values.item(u).getNodeName();
if (name == "#text") continue;
string val = values.item(u).getFirstChild().getNodeValue();
cout << "Node streaming = \"" << values.item(u) << "\", meaning that name = \"" << name << "\" and value = \"" << val << "\"" << endl;
}
Note: The production code should take into account the fact that not all nodes are simple leaf nodes. So my code is only half of the solution.

How can I extract the displayed text from a QTableWidgetItem?

I have a subclass of QTableWidget with the following code:
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(pushCellChange(int, int)), Qt::QueuedConnection);
...
void MyTableView::pushCellChange(int row, int column)
{
QString text(item(row, column)->text());
QByteArray data = text.toAscii();
cout << data.length() << endl;
const char* cellData = text.toAscii().constData();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
}
When I change the upper-right cell to anything this outputs:
2
Cell (0, 0) changed to: ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌░▬∟C▌▌
However, while this corrupt data is spewed out on the console, the table widget itself seems to behave normally and shows the correct string. Does anyone know what is going on here?
The call toAscii() is storing the QString's data to a QByteArray. In your code, you do this twice:
QByteArray data = text.toAscii();
const char* cellData = text.toAscii().constData();
_____________^ <-- temporary QByteArray
The const char* is actually pointing to the data within a temporary variable, which goes out of scope at the semicolon, at which point the pointer becomes invalid. If instead you were to make use of the local variable data, you'd be OK:
const char* cellData = data.constData();
___^ <-- still-in-scope QByteArray
Alternatively, you can do this all in-line with the cout and the data will still be valid when it is copied to the output stream:
cout << "Cell ("<<row<<","<<column<<") changed to: " << text.toAscii().constData() << endl;
std::string cellData = text.ToStdString();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
That should work fine. As for why toAscii doesn't work, I have no clue.
If it's just about the console output, you could also use qDebug() (available after #include <QDebug>) and pass the QString directly:
void MyTableView::pushCellChange(int row, int column)
{
qDebug() << item(row, column)->text().length();
qDebug() << "Cell (" << row << ", " << column << ") changed to: "
<< item(row, column)->text();
}
This way, you don't have to mess with data conversion …