Retrieve value of QTableWidget cells which are QLineEdit widgets - c++

I create a QLineEdit,set a validator and put it on the table with this code:
ui->moneyTableWidget->setCellWidget(rowsNum, 1, newQLineEdit);
Then I've got another class for manipulating the table's data doing the sum of every value of a column. Here's the code:
int Calculator::calculatePricesSum(QTableWidget &moneyTableWidget){
double total = 0;
QWidget *tmpLineEdit;
QString *tmpString;
for(int row=0; row<moneyTableWidget.rowCount(); row++){
tmpLineEdit = (QLineEdit*)moneyTableWidget.cellWidget(row,1);
tmpString = tmpLineEdit.text();
total += tmpString->toDouble();
}
return total;
}
But the building fails with this error:
/home/testpec/src/nokia
QT/MoneyTracker-build-simulator/../MoneyTracker/calculator.cpp:11:
error: cannot convert ‘QLineEdit*’ to
‘QWidget*’ in assignment
Why this convertion error?
Another subquestion: passing the table as reference saves memory right? Could this be the problem? Im developing for a Nokia smartphone and I think passing the object by value is a waste of memory...(sorry if is a dumb question but I'm a little rusty with C++ and all the pointers stuff...)

When you declare your tmpLineEdit, you should be declaring it as a QLineEdit* instead of a QWidget*. Your loop grabs the widget, casts it to a QLineEdit* and then tries to put it back into a QWidget*. Also, I'd recommend using qobject_cast<QLineEdit*> (or dynamic_cast) so that you can ensure the cast succeeded.
int Calculator::calculatePricesSum(QTableWidget &moneyTableWidget){
double total = 0;
QLineEdit* tmpLineEdit;
QString tmpString;
for(int row=0; row < moneyTableWidget.rowCount(); row++)
{
tmpLineEdit = qobject_cast<QLineEdit*>(moneyTableWidget.cellWidget(row,1));
if(NULL == tmpLineEdit)
{
// Do something to indicate failure.
}
tmpString = tmpLineEdit->text();
total += tmpString.toDouble();
}
return total;
}
As for your second question, passing by reference is probably a good idea - I know some of the classes in Qt (QImage in particular) use reference counting and implicit sharing so that you can pass around by value without worrying about the implications of large copy operations, but I'm not sure if a QTableWidget is in that category as well.

Related

I'm using qt to design a program and need help because my code is not DRY [duplicate]

I have a gui form, where multiple text boxes are present. I want to put their values inside an array. One way of doing it is by writing something like this
{array element } = ui->text_1->text();
and repeat it for text_2,text_3 upto n.
What I want is to run a loop and replace number portion of text box name in each cycle.
something like this {array element } = ui->text_{This number getting changed }->text();
How can it be done in qt?
There are two ways of doing this.
When you create the UI, instead of using text1, text2, etc. you create an array of QLineEdits (eg. std::vector<QLineEdit>) and then when you want to retrieve their values then simply iterate over this array
Iterate over the children of the container widget. You can get the list of the children using the following (documentation):
QList<QObject *> list = parentWidget->children();
Another option to those listed would be to create an array using an initializer list. Depending on how big the array is (and how often it changes), this might be workable.
QLineEdit* entries[] = { ui->text_0, ui->text_1, ui=>text_2 };
QStringList answers;
for ( int i = 0; i < 3; ++i )
{
answers += entries[i]->text();
}
here is an expanded version of Matyas' solution:
class MyClass : public QWidget
{
QStringList answers;
void FillAnswersList(QObject *base)
{
QLineEdit *lineEdit = qobject_cast<QLineEdit>(base);
if(lineEdit)answers.append(lineEdit->text());
else
{
foreach(QObject *child, base->children())
FillAnswersList(child);
}
}
};
If it is just the number changing, and always incrementing, there is another possible solution using QObject::findChild, which takes a name as a parameter.
QString name_template("text_%1");
QStringList answers;
for(int i = 0; i < MAX_TEXTS; ++i)
{
QLineEdit *edit = ui->findChild<QLineEdit *>(name_template.arg(i));
answers += edit->text();
}

Qt : How to cast QTableRowItem to Object?

I'm new to Qt. i want to cast a row item in the QTableWidget as object.
So far, i've manage to populate the QTableWidget with QList:
header.h
QList<Inventory> inventories;
int row = 0;
int rowCount = ui->tableItems->rowCount();
ui->tableItems->insertRow(rowCount);
foreach(Inventory inventory, this->inventories)
{
QTableWidgetItem *code = new QTableWidgetItem(inventory.getName());
QTableWidgetItem *name = new QTableWidgetItem(inventory.getCode());
QTableWidgetItem *price = new QTableWidgetItem(GlobalFunctions::doubleToMoney(this, inventory.getPrice()));
ui->tableItems->setItem(row,0,code);
ui->tableItems->setItem(row,1,name);
ui->tableItems->setItem(row,2,price);
row++;
}
In my table, i will select the row using this.
void CreateSalesWindow::removeItem()
{
qDebug() << "Remove Item" << ui->tableItems->currentIndex().column();
this->salesdetails.removeAt(ui->tableItems->currentIndex().column() - 1);
this->refreshItemList();
}
I've manage to get the selected row, is there a straightforward way to cast my row back into object. I've come from a C# .Net Background where i could easily cast it back into something like this (just an example). I could not found any good solutions in SO and Documentation.
Inventory selectedInventory = (Inventory) ui->tableItems->selectedItem().getValue();
qDebug() << selectedInventory.getPrice();
// 1699.75
PS. I also want to remove an item from the QList<> from the selected row in the table.
Thanks! I'm new to Qt, i'm open to much better approach in handling this. if something is unclear please raise a comment so i could correct it.
I'm not familiar with the QTableWidget itself, but in general you should use the row method with Qt's model/view classes to access the underlying data row index of the model and then just access your original data from your custom model (depending on the implementation of your model).
In your case something like this:
int rowIndex = ui->tableItems->selectedItems().first().row();
// or this should also work to get the current index directly
int rowIndex = ui->tableItems->currentIndex().row();
Inventory *selectedInventory = ui->tableItems->model()->getInventory(rowIndex);
where the getInventory(int index) method is your custom method to access your object via its index (I guess you have a derived model from QAbstractItemModel or something so save your data and view it in the QTableWidget).
That is at least what I would do, you can read more about general model/view programming with Qt at Introduction to Model/View Programming.

How to initialize over a 100 QLabel in an efficient way

I want to have the ability to update over 100 labels, so I was going to put them in an array like this:
voltage_label_array[0] = this->ui->Voltage_0;
voltage_label_array[1] = this->ui->Voltage_1;
voltage_label_array[...] = this->ui->Voltage_2;
voltage_label_array[...n] = this->ui->Voltage_n;
and then have this method
void MainWindow::updateValue(int i, int voltage){
voltage_label_array[i]->setText(QString::number(voltage));
}
but having 100 lines to set this up seems like a bad idea. Is there a way I can initialize a QLabel array inside a for loop or something?
If you need to do this, something is horribly wrong with your design. But it is possible.
Assuming your labels are named Voltage_0 to Voltage_99:
for(int i = 0; i < 100; ++i) {
auto ptr = this->findChild<QLabel*>(QString("Voltage_%1").arg(i));
voltage_label_array[i] = ptr;
}
This "solution" uses Qt's runtime reflection and carries the expected performance penalties.
But if you need to display several similar values, look up QListWidget and similar classes.

Efficient way to make an array of labels

I'm making a board game and I need to display a 15 x 15 array in my gui. I decided to go with individual labels which contains one element of the array. This means I do have quite a lot of labels. I gave each label the name "tile_0_0" with the first 0 being the row and the second 0 being the column. This was quite easy to do in qt.
The problem however is that I ofcourse can't simply use 2 forloops to access each tile since you can't use variables in names. ("tile_i_j" does not exist.) To solve this I decided to make an array which contains each and every label. I however cannot initialise the array efficient because of the earlier mentioned problem.
So the question is: How can I avoid having to write a giant block of code?
A small piece of the current code:
Ui::BoardView *ui = new UI::BoardView; // BoardView is my class
QLabel* m_boardLbArray[8][8];
m_boardLbArray[0][0] = ui->tile_0_0;
m_boardLbArray[0][1] = ui->tile_0_1;
m_boardLbArray[0][2] = ui->tile_0_2;
m_boardLbArray[0][3] = ui->tile_0_3;
m_boardLbArray[0][4] = ui->tile_0_4;
// ...
Note: Sorry that I didn't post a part of code you could simply copy and run, but I do not know how since it's gui related.
It sounds like you are creating your tiles(QLabels) in Qt Designer; A cleaner way to achieve this is to create them programatically. You can do something like add a Grid Layout to your form in Designer in the location you want them, and then do:
QGridLayout *layout = ui->gridlayout;
QLabel* m_boardLbArray[8][8];
for(int row=0; row<8; row++)
for(int col=0; col<8; col++)
{
m_boardLbArray[row][col] = new QLabel(this);
m_boardLbArray[row][col]->setText(tr("This is row %1, col %2")
.arg(row).arg(col));
layout->addWidget(m_boardLbArray[row][col], row, col);
}

How to run a loop using gui object names in qt?

I have a gui form, where multiple text boxes are present. I want to put their values inside an array. One way of doing it is by writing something like this
{array element } = ui->text_1->text();
and repeat it for text_2,text_3 upto n.
What I want is to run a loop and replace number portion of text box name in each cycle.
something like this {array element } = ui->text_{This number getting changed }->text();
How can it be done in qt?
There are two ways of doing this.
When you create the UI, instead of using text1, text2, etc. you create an array of QLineEdits (eg. std::vector<QLineEdit>) and then when you want to retrieve their values then simply iterate over this array
Iterate over the children of the container widget. You can get the list of the children using the following (documentation):
QList<QObject *> list = parentWidget->children();
Another option to those listed would be to create an array using an initializer list. Depending on how big the array is (and how often it changes), this might be workable.
QLineEdit* entries[] = { ui->text_0, ui->text_1, ui=>text_2 };
QStringList answers;
for ( int i = 0; i < 3; ++i )
{
answers += entries[i]->text();
}
here is an expanded version of Matyas' solution:
class MyClass : public QWidget
{
QStringList answers;
void FillAnswersList(QObject *base)
{
QLineEdit *lineEdit = qobject_cast<QLineEdit>(base);
if(lineEdit)answers.append(lineEdit->text());
else
{
foreach(QObject *child, base->children())
FillAnswersList(child);
}
}
};
If it is just the number changing, and always incrementing, there is another possible solution using QObject::findChild, which takes a name as a parameter.
QString name_template("text_%1");
QStringList answers;
for(int i = 0; i < MAX_TEXTS; ++i)
{
QLineEdit *edit = ui->findChild<QLineEdit *>(name_template.arg(i));
answers += edit->text();
}