Dynamic QWidget for QStackedWidget using ID
-
I have an application with a mainwindow and a stackedwidget.
I like to create a widget that displays all the information about a formula 1 circuit, but it needs to be dynamic. I don't want to create a widget for each circuit, but I want it to retreive the data from the database using its ID.
I promoted the first index of the stacked widget to Circuit and already tried this:Circuit.h:
explicit Circuit(int ID,QWidget *parent = nullptr);
Circuit.cpp:
Circuit::Circuit(int ID, QWidget *parent) : QWidget(parent), ui(new Ui::Circuit) { ui->setupUi(this); }
but it gives me this error:
no matching function for call to 'Circuit::Circuit()' no matching constructor for initialization of 'Circuit'
page = new Circuit(); page->setObjectName(QString::fromUtf8("page")); stackedWidget->addWidget(page);
Is there anyone who knows what the proper way to do this is?
-
@hobbyProgrammer said in Dynamic QWidget for QStackedWidget using ID:
page = new Circuit();
Hi
You have to give it the int in the ctor
page = new Circuit(666);
( ps. do you store it in the Circuit class, the code dont show that at all ) -
@mrjj Hi, I don't store it yet. I'd like to create a good setup before starting into the actual coding.
From the MainWindow how do I call this?
QSqlQuery query(db); query.prepare("SELECT DISTINCT(name) FROM circuit WHERE circuit_id = :circuitID"); query.bindValue(":circuitID", circuitID); query.exec(); QSqlQueryModel *model = new QSqlQueryModel(); model->setQuery(query); for(int i = 0; i < model->rowCount(); i++) { QString strCircuitName = model->data(model->index(i,0)).toString(); const char* charCircuitName = strCircuitName.toStdString().c_str(); QAction *circuitAct = new QAction(tr(charCircuitName)); ui->menuCircuits->addAction(circuitAct); connect(circuitAct, &QAction::triggered, this, &MainWindow::goToCircuit); }
void MainWindow::goToCircuit() { qDebug() << "circuitID: " << circuitID; Circuit *circuit = new Circuit(circuitID); ui->stackedWidget->setCurrentWidget(circuit); }
When I start the app it goes straight to the page with index 0 (because of the code below, that was causing the error previously).
Whenever I press either Circuit 1 or Circuit 2, it doesn't seem to do anything. I suspect that my connect isn't the proper way to do this, but how should I do this?page = new Circuit(0); page->setObjectName(QString::fromUtf8("page")); stackedWidget->addWidget(page);
-
@hobbyProgrammer
I'm sorry I don't have time to answer the signal/slot/connect
part, you'll perhaps want to use a C++ lambda for that, there are various ways but you need your slot to gain access to which circuit ID the action is for, in some shape or form.But I couldn't help noticing:
QString strCircuitName = model->data(model->index(i,0)).toString(); const char* charCircuitName = strCircuitName.toStdString().c_str(); QAction *circuitAct = new QAction(tr(charCircuitName));
You don't want to do it this way. At minimum from docs use:
Similarly, you can pass a
QString
to a function that takes aconst char *
argument using theqPrintable()
macro which returns the givenQString
as aconst char *
. This is equivalent to calling<QString>.toLocal8Bit().constData()
.Separately
Circuit *circuit = new Circuit(circuitID); ui->stackedWidget->setCurrentWidget(circuit);
https://doc.qt.io/qt-5/qstackedwidget.html#setCurrentWidget
Sets the current widget to be the specified widget. The new current widget must already be contained in this stacked widget.
You're going to need a https://doc.qt.io/qt-5/qstackedwidget.html#addWidget.
-
@JonB Hi,
thanks for your help.
I really need to know how to load these Circuits in the menu dynamically tho. Is there anyone else who might know how to help me?I thought it could be done using QSignalMap, but I can't seem to find the solution anywhere
-
This post is deleted!
-
Allright, I got it working. It might not be the most beautiful solution so any feedback on how to improve the code is always welcome, but this is what I got so far:
void MainWindow::fillCircuitMenu() { QSqlQuery query(db); query.prepare("SELECT DISTINCT(name), id FROM circuit WHERE circuit_id = :circuitID"); query.bindValue(":circuitID", circuitID); query.exec(); QSqlQueryModel *model = new QSqlQueryModel(); model->setQuery(query); for(int i = 0; i < model->rowCount(); i++) { QString strCircuitName = model->data(model->index(i,0)).toString(); const char* charCircuitName = strCircuitName.toStdString().c_str(); QAction *circuitAct = new QAction(tr(charCircuitName)); this->circuitID = model->data(model->index(i,1)).toInt(); ui->menuCircuits->addAction(circuitAct); Circuit *circuit = new Circuit(circuitID); qvCircuitMenu.insert(i, circuit); QSignalMapper *signalMapper = new QSignalMapper(this); connect(circuitAct, SIGNAL(triggered()), signalMapper, SLOT(map())); signalMapper->setMapping(circuitAct, circuitID); connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(goToCircuit(int))); } }
void MainWindow::goToCircuit(int index) { qDebug() << "goToCircuit: " << index; Circuit *circuit = new Circuit(index); ui->stackedWidget->addWidget(circuit); ui->stackedWidget->setCurrentWidget(circuit); }
-
@hobbyProgrammer
I don't know what is going on here, but I note that for a givencircuitID
you do twonew Circuit(circuitID)
s, one infillCircuitMenu()
and another any time slotgoToCircuit(int index)
is invoked. I don't know if that is correct, no re-use of sameCircuit
instance?Separately, I don't think there is any need to use deprecated
QSignalMapper
any longer. You can replace with new signal/slot syntax (you should get away fromSIGNAL
/SLOT()
macros in all new code) plus a lambda. See e.g. https://doc.qt.io/qt-5/qsignalmapper.html#details for an example of this.