How can I extract the displayed text from a QTableWidgetItem? - c++

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 …

Related

How do I check whether an index of array is empty and then, if it is, skip to the next?

I'm trying to build a program that can register a user to the database (still learning cpp, I hope that in the near future I'll be able to work with database).
What I'm trying to do with this code is to check whether an index of array is empty for the user to store an ID in it. If it isn't empty, I want the program to keep looking for an empty index of array, for the new info to be stored in.
Here is the code:
void registro() {
std::string userid[3];
userid[0] = "Houkros"; // eventually I'll try to have this being read from a file or server database..
std::string userpass[3];
std::string usermail[3];
std::string userkey[3];
std::string getUid[3];
std::string getUpass[3];
std::string getUmail[3];
std::string getUkey[3];
std::cout << std::endl << " >>>> REGISTRATION <<<< " << std::endl;
std::cout << " =============================================== " << std::endl;
std::cout << std::endl;
std::cout << "Please, enter the desired user id: " << std::flush;
if (userid[0].empty())
{
std::cin >> userid[0];
}
else {
std::cin >> userid[1];
}
for (int i = 0; i < 2; i++)
{
std::cout << " Element of array: " << i << " is > " << userid[i] << std::endl;
}
Please consider the following definitions for an "empty" array element:
a) not initialised (unhelpful, cannot be checked)
b) never yet written to (same as a) )
c) contains "" (possible, but means that "" must not be accepted as an actual content)
d) is empty according to a second array in which that info is maintained (this is what I almost recommend)
e) contains a struct with a string and a maintained "empty" flag (this I recommend)
Whatever you do, make sure that you init all variables and array elements before first read-accessing them; i.e. in all cases first write something meaningful to it.

QTextStream write data in file

I'm learning QtCreator and having troubles writing data in file. Here's some code :
char *str;
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2) {
str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
std::cout << str << std::endl;
out << str << "\n";
i += 2;
}
getItem returns a QWidget * from a QFormLayout filled with QLineEdit (that explains the dynamic cast). Anyway, when I pass str into std::cout it works fine, the data is printed, but when I pass str into out, it writes only the first char of str in the file.
I don't get what I'm doing wrong, I really would appreciate any tips.
This line is a problem: str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
dynamic_cast<QLineEdit *>(this->getItem(i))-> is OK
->text() creates a temporary QString
.toLocal8Bit() creates a temporary QByteArray
.data() returns a pointer to the internal data of the QByteArray
As soon as the line is passed the QByteArray will be destroyed and you have a dangling pointer. str points to invalid data.
Everything you do with this pointer afterwards (except letting it point to somewhere else) is undefined behaviour.
Try to use something like this:
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2)
{
QLineEdit* lineEdit = dynamic_cast<QLineEdit *>(this->getItem(i));
if (lineEdit)
{
QByteArray str = lineEdit->text().toLocal8Bit();
std::cout << str.data() << std::endl;
out << str.data() << "\n";
i += 2;
}
else
{
std::cerr << "Item at " << i << " is no QLineEdit*" << std::endl;
}
}
out.close();
Also please check whether QFile is actually open and whether QTextStream reports some errors when writing.

My application is crashing using Do/While loop to parse table

I have 2 QCheckbox tables, each contains 11 elements.
I declare them as following in my class :
QCheckBox *sectionTable[10];
QCheckBox *postTable[10];
For each QCheckBox, I do this
QCheckBox* checkboxA = new QCheckBox("A");
sectionTable[0] = checkboxA;
Through my test method, I would like to return the content of each element of my QCheckbox tables.
To do so, I've done this test :
/** TEST() **/
void VGCCC::test()
{
sectionTable[0]->setText("A");
sectionTable[1]->setText("B");
sectionTable[2]->setText("C");
sectionTable[3]->setText("D");
postTable[0]->setText("E");
postTable[1]->setText("F");
postTable[2]->setText("G");
postTable[3]->setText("H");
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
}
My application is compiling, and also running. But when I call the test function, my application crash.
How can we explain this problem ?
I would like to notify that I get a result in my console. It seems my test is half working, but is crashing at the end of the 1st do/while loop, when I get out of my condition.
With regard to the 11 elements: QCheckBox *sectionTable[10]; defines only 10 slots (0 through 9) for elements.
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
Has the potential to reach past ten or eleven elements. Unless the terminating condition is found earlier, there is nothing to stop sectionTable[i] from trying to read sectionTable[11] to call its text method. If it manages to survive the call to the out-of-range sectionTable[11]->text(), it will then try calling sectionTable[11]->text().isNull(). Possibly this will be survivable as well and not be NULL. In this case sectionTable[12] will be tested. This will continue until the program hits really bad memory and crashes, a null is found, or pigs become the terror of the airways we all know they truly wish to be.
Note that i is not set back to 0 after this loop, so the first postTable to be inspected in the next loop will be at the same index as the last sectionTable.
So if sectionTable[5]->text().isNull() was NULL, postTable[5] will be the first postTable indexed and inspected.
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
This loop has the same error in the exit condition as the sectionTable loop.
I find out how to solve the problem. As said in the answer before (#user4581301), I didn't set back my iterator i to 0.
Also, to avoid the "out of range" crash, I put a second condition which is i<sizeof(sectionTable[i]);
This is my fonctional test function :
/** TEST() **/
void VGCCC::test()
{
int i = 0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << m_materialMap[sectionTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull() && i<sizeof(sectionTable[i]));
i = 0;
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
std::cout << "POST TABLE " << m_materialMap[postTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty() && i<sizeof(postTable[i]));
}

Access to html table retrieved with QNetworkReply

I want to read the suffix column of the table that I see at http://finance.yahoo.com/exchanges.
I read the page with QNetworkManager. storing data in QNetworkReply *reply. If I read all the page with reply->readAll() I obtain the page, so it's retrieved correctly. I set it inside a QWebPage and then I want to retrieve all tables that are inside.
In order to obtain the table I want to use QWebElement but I'm not be able to read it. I read all tables at the same level of the one that I want but the QWebElementCollection that I obtain is empty.
What I'm doing wrong and that I must do in order to read the table?
void getMarketListFromReply(QNetworkReply *reply) {
std::cout << "Reading page" << std::endl;
const QString html(reply->readAll()); // html contain the code
QWebPage page;
std::cout << "Setting page." << std::endl;
page.mainFrame()->setHtml(html);
std::cout << "Retrieving tables" << std::endl;
QWebElementCollection tables = page.mainFrame()->documentElement().findAll("html body div.screen div.content table");
const int size = tables.count(); // size it's 0 :-(
std::cout << "size: " << size << std::endl;
for (int i = 0; i < size; i++) {
std::cout << i << ": " << tables.at(i).toPlainText().toStdString() << std::endl;
}
}
Dot in findAll() selector denotes tag class. However, in your case "screen" and "content" are element ids that can be selected by sharp (#). So, the following selectors should work
.findAll("html body div#screen div#content table");
.findAll("#content table");

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.