Dynamically & sequentially naming & instantiating widgets qt - c++

I'm creating a new instance of QTableWidgetItem for each row the user may add, and adding it to a QVector of QTableWidgetItems.
I'd like to do soemthing like the following to name each instance in the following iteration with the row number included in the instance name:
QVector<QCheckBox> *checkBox_array;
for(int r=0;r<user_input;r++)
{
ui->tableWidget->insertRow(r);
*checkBox%1.arg(r) = new QCheckBox; //create an instance "checkBox1" here
checkBox_array->pushBack(checkBox%1.arg(r))
}
or something like the following, which does not compile in its current state:
for(int r=0;r<7;r++)
{
ui->tableWidget->insertRow(r);
checkBox_array->push_back();
checkBox_array[r] = new QCheckBox;
ui->tableWidget->setCellWidget(r,2,checkBox_array[r]);
}
is this possible? How can I work around this issue? All I need is to get the new widgets into the array without having to name them explicitly. Thanks in advance!
Thanks in advance.

Try something like this:
for(int r=0;r<7;r++)
{
ui->tableWidget->insertRow(r);
ui->tableWidget->setCellWidget(r,2,new QCheckBox(QString("checkBox%1").arg(r)));
}
It creates some widgets.
When you want change something in this widget or get data then use cellWidget() method, but don't forget cast it! For example:
for(int r=0;r<7;r++)
{
QCheckBox* curBox = qobject_cast<QCheckBox*>(ui->tableWidget->cellWidget(r,2));
if(curBox)
{
qDebug() << curBox->text() << curBox->isChecked();
curBox->setText("This is new Text");
}
else
qDebug() << "fail";
}

Related

Create a new object from pointer reference C++

So, I've this code below:
foreach (QLineSeries* series, lineSeriesMap.values())
{
// ...
}
And I will modify series objects in this loop and I don't want to modify the original one, but create a new edited one. I'm extremely new to C++ and Qt so, I want something as the Java code below:
QLineSeries editedSeries = new QLineSeries(series);
I'm deleting elements, editing and re-ordering them from series by the way. But, as I said I need them both.
EDIT:
I've tried your answers but best way I believe is putting the code. This is a project made by some co-worker who changed jobs so its not my code, as i said I dont know C++.
chartwidget.h
void fillAreaSeries();
//...
QHash<QString,QLineSeries*> lineSeriesEntersMap;
QHash<QString,QLineSeries*> lineSeriesExitsMap;
chartwidget.cpp
void ChartWidget::fillAreaSeries() {
foreach (QLineSeries* seriesEnter, lineSeriesEntersMap.values())
{
if (lineSeriesExitsMap.contains(seriesEnter->name())) {
QLineSeries* seriesExit = lineSeriesExitsMap.value(seriesEnter->name());
if (!((seriesEnter->points().size() == 1) && (seriesExit->points().size() == 1))) {
for(int i = seriesEnter->points().size() - 1; i > 0; i--)
{
if (seriesEnter->points().at(i - 1).y() > seriesEnter->points().at(i).y())
{
seriesEnter->removePoints(i, 1);
}
}
for (int i = seriesExit->points().size() - 1; i > 0; i--)
{
if (seriesExit->points().at(i - 1).y() < seriesExit->points().at(i).y())
{
seriesExit->removePoints(i-1, 1);
}
}
QVector<QPointF> editPoints = seriesExit->pointsVector();
std::sort(editPoints.begin(),editPoints.end(), [] (const QPointF & p1, const QPointF & p2)
{
return p1.y() < p2.y();
});
seriesExit->replace(editPoints);
qDebug() << "__Swap:__";
qDebug() << seriesEnter->points().at(0).y();
qDebug() << seriesExit->points().at(0).y();
qDebug() << seriesEnter->points().at(1).y();
qDebug() << seriesExit->points().at(1).y();
QAreaSeries* series = new QAreaSeries(seriesEnter, seriesExit);
series->setName(seriesEnter->name());
series->setOpacity(0.50);
series->setPen(Qt::NoPen);
series->setPointLabelsFormat(seriesEnter->name().split("-").at(0));
areaSeriesMap.insert(series->name(), series);
}
}
}
}
Edit 3:
So, QLineSeries contains QPointF list. I've the code below:
foreach (QLineSeries* seriesEnter, lineSeriesEntersMap.values())
{
QLineSeries* entersToBeEdited = new QLineSeries(chart);
entersToBeEdited->setName(seriesEnter->name());
entersToBeEdited->points().append(seriesEnter->points());
//...
append doesnt work and returns 0 points. But I can set a name. I also tried appending by looping through items and adding it by
entersToBeEdited->points().push_back(seriesEnter->points().at(i));
and still nothing. I also tried << and += but no luck.
Looking at the class definition of QLineSeries, I don't see any simple way to copy your instance in order to duplicate it.
Thus you will have first to create a new instance :
QLineSeries editedSeries;
and manually copy the content of your original series in it.
editedSeries.append(originalSeries.points());
As you cannot modify the data once it is in the QLineSeries object, I would recommend to subclass QLineSeries or modify the QList<QPointF> obtained via originalSeries.points() before adding it to your new chart.
QLineSeries is not copyable, so you can't do what you want by modifying a copy. You will need to create a new QLineSeries from scratch.

Getting text values from dynamically created Qline edits in Qt c++

I have created a set of QlineEdits successfully and assigned each LineEdit an Object name but unfortunately when I try to read and get them into a QStringList I get an error stating:
"Textbox was not declared in this scope"
my code is as follows:
for(int i=0;i<5;i++){
f1 = new QFrame();
f2 = new QFrame();
f3 = new QFrame();
a= new QLabel(f1);
b=new QLineEdit(f2);
c=new QLineEdit(f3);
QString oName= QString::number(i);
b->setObjectName("Textbox"+oName);
ui->verticalLayout->addWidget(f1);
ui->verticalLayout_2->addWidget(f2);
ui->verticalLayout_3->addWidget(f3);
a->setText(newList[i]);
}
and from the button click event I won't to get each text in the dynamically created QLineEdits!
void NewOrders::on_pushButton_2_clicked()
{
for(int i=0;i<getList.size();i++){
QString oName= QString::number(i);
getList<<(ui->("Textbox"+oName)->text());
}
}
Here getlist and newlist are QStirngLists are already defined as public!
How can I correct this?
To get the object through the objectName you must use the findChild
void NewOrders::on_pushButton_2_clicked()
{
for(int i=0;i<5;i++){
QLineEdit *le = findChild<QLineEdit*>(QString("Textbox%1").arg(i));
if(le){
getList<<le->text();
}
}
}

Getting variable from widget in a QListWidget

I have a custom QWidget class called VideoWidget. Its source file looks something like this:
VideoWidget::VideoWidget(QWidget *parent, string test) :
QWidget(parent)
{
pathname=test;
QLabel *label= new QLabel(pathname.c_str(), this);
//...
}
string VideoWidget::getFilePath(){
return pathname;
}
In my MainWindow class I add the VideoWidget to a QListWidget through looping through a xml file and getting the string argument from that file like this:
QDomNode node = rootXML.firstChild();
while( !node.isNull() )
{
if( node.isElement() )
{
QDomElement element = node.toElement();
VideoWidget* mytest = new VideoWidget(this, element.attribute( "Pathname", "not set").toStdString());
QListWidgetItem* item = new QListWidgetItem;
item->setSizeHint(QSize(150,100));
ui->myList->addItem(item);
ui->myList->setItemWidget(item,mytest);
}
node = node.nextSibling();
}
This correctly fills my QListWidget with the VideoWidget where all the labels have a different value.
Now I'd like to get the pathname variable everytime I doubleclick on a item in the QListWidget like this:
connect(ui->myList,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(playClip(QModelIndex)));
void MainWindow::playClip(QModelIndex index){
QListWidgetItem* item = ui->myList->itemAt(0,index.row());
VideoWidget* widget = dynamic_cast<VideoWidget*>(ui->myList->itemWidget(item));
cout << widget->getFilePath() << endl;
}
My problem is that widget->getFilePath() always returns the same value for every clicked widget. It is the value of the first time I set pathname=test;. What am I missing here?
This is probably mistake:
QListWidgetItem* item = ui->myList->itemAt(0,index.row());
Method "itemAt" takes x and y coordinates, not indexes. Use "takeItem" instead.
Next thing I want to say is that this part:
ui->myList->itemWidget(item)
is useless. You can convert "item" directly.
And last - use qobject_cast since you use Qt. And never use dynamic_case (especially when you anyway do not check result against NULL).

Qt 5.3: Accessing/returning/calling checkboxes that are created dynamically(?)

So I have reached my ceiling of knowledge when it comes to Qt and C++ in general I guess. I am creating check boxes in a QScrollArea based off the input from a QComboBox. Depending on the value selected in the QComboBox, a specific number of check boxes are created. Once I created those check boxes, I am having a problem understanding how to interact (in my case, simply check to see if they are checked or not) with them outside of the function they are being created and called in. I know how to work with them if the buttons were static, but since the check boxes are dynamic (is that the right word?) and can change, I don't know what to do. Below is a little snippet of code on how the check boxes are created. If I now want to simply check if any of the boxes are checked, how do I do that. Can I "return" or "call" the created check boxes in another function somehow? I know I'll simply need to loop through the array and check, I just simply don't know how to get the array of check boxes into another function or how to return them in the function below.
Thanks for the help!
void MyProgram::create_checkboxes(QString opnum)
{
QWidget* MDAcheckboxes = new QWidget(ui->MDA);
QVBoxLayout* MDAlayout = new QVBoxLayout(MDAcheckboxes);
QCheckBox *MDAmycheckBox[9];
QList<QString> boxes;
if (opnum == "640")
{
boxes << "16-1" << "16-2";
for (int i = 0; i < 2; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
else if (opnum == "645")
{
boxes << "13-01"<<"13-2"<<"13-3"<<"13-4"<<"13-5";
for (int i = 0; i < 5; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
else if (opnum == "650")
{
boxes << "13-6"<<"13-7"<<"13-8"<<"13-9"<<"13-10"<<"13-11"<<"13-12"<<"13-13"<<"13-14";
for (int i = 0; i < 9; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
}
All your checkBoxes should have a parent. In this case you will be able to find it with findChildren. It also can be done without groupBox if you sure that app has no any other checkboxes and findChildren will not return you checkboxes which you don't need.
Try this:
QList<QCheckBox *> allButtons = ui->groupBox->findChildren<QCheckBox *>();
qDebug() <<allButtons.size();
for(int i = 0; i < allButtons.size(); ++i)
{
if(allButtons.at(i)->isChecked())
qDebug() << "Use" << allButtons.at(i)->text()<< i;//or what you need
}
In general case:
QList<QCheckBox*> allButtons = parentOfCheckBoxes->findChildren<QCheckBox *>();
Moreover findChildren allows you to find children with special objectName which can be useful in some cases. Note that you can set the same objectName to the different objects.
http://qt-project.org/doc/qt-5/qobject.html#findChildren

Memory Management in Qt

I have small doubt about Qt memory management.
Let's take an example of Listview, in listview we add each item by allocating memory dynamically. So in this case do we need to delete all the "new"ed items manually.
E.g:
Qlistview *list = new Qlistview;
QStandardItemModel *mModel = new QStandardItemModel();
list ->setModel(mModel);
for(int I =0;i<10;i++)
{
QsandardItem *item = new QsandardItem(“Hi”);
mModel->appendRow(item);
}
In this example, should item be deleted manually?
QStandardItemModel takes ownership of items, so they will be automatically deleted when model is destroyed. You still need to delete the model itself (setModel() doesn't transfer ownership of model to the view, because one model can be used by multiple views).
Agree with chalup's answer , the answer for your question is:
if you called mModel->clear();, it will help you delele all of those items, you don't need to mannually delete items one by one, what's more if you want to totally delete model, you should called delete mModel;.
Run the example code provided by ChrisW67 here, you will have a better understanding:
#include <QCoreApplication>
#include <QDebug>
#include <QStandardItemModel>
class MyItem: public QStandardItem
{
public:
MyItem(const QString & text): QStandardItem(text) {
qDebug() << "Item created" << this;
}
~MyItem() {
qDebug() << "Item destroyed" << this;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QStandardItemModel* model = new QStandardItemModel;
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 4; ++column) {
QStandardItem *item =
new MyItem(QString("row %0, column %1").arg(row).arg(column));
model->setItem(row, column, item);
}
}
qDebug() << "Finished making model";
model->clear();
qDebug() << "Model cleared";
qDebug() << "===================";
QStandardItem *newitem1 = new MyItem(QString("new item"));
qDebug()<<"create new item at"<<newitem1;
QStandardItem *newitem2 = new MyItem(QString("new item"));
QStandardItem *newitem3 = new MyItem(QString("new item"));
QStandardItem *newitem4 = new MyItem(QString("new item"));
//because we didn't delete model so far, we can still append items to model.
model->appendRow({newitem1,newitem2,newitem3,newitem4});
model->clear();
qDebug() << "Model cleared again";
//although the memoty of newitem1 has already been deallocated, but the pointer still point to that address, now newitem1 is a dangling pointer
if(newitem1){
qDebug()<<"newitem1 address is"<<newitem1;
}
else{
qDebug()<<"newitem1 address in null";
}
// delete newitem1;//this will cause program crash because newitem1 acutally has been delete, double delete should not be allowed
newitem1 = nullptr;//Instead of delete, wo could set newitem1 pointet to null, this can avoid wild pinter/dangling pointer
delete model;
qDebug()<<"deleted model";
return a.exec();
I am learing c++ too, if there is something wrong above, please tell me, i will correct it.