Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Dynamic QWidget for QStackedWidget using ID
QtWS25 Last Chance

Dynamic QWidget for QStackedWidget using ID

Scheduled Pinned Locked Moved Unsolved General and Desktop
qstackedwidgetqwidget
8 Posts 3 Posters 1.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    hobbyProgrammer
    wrote on last edited by
    #1

    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?

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      @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 )

      H 1 Reply Last reply
      0
      • mrjjM mrjj

        @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 )

        H Offline
        H Offline
        hobbyProgrammer
        wrote on last edited by hobbyProgrammer
        #3

        @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);
        
        JonBJ 1 Reply Last reply
        0
        • H hobbyProgrammer

          @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);
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @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 a const char * argument using the qPrintable() macro which returns the given QString as a const 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.

          H 1 Reply Last reply
          1
          • JonBJ JonB

            @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 a const char * argument using the qPrintable() macro which returns the given QString as a const 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.

            H Offline
            H Offline
            hobbyProgrammer
            wrote on last edited by
            #5

            @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

            1 Reply Last reply
            0
            • H Offline
              H Offline
              hobbyProgrammer
              wrote on last edited by
              #6
              This post is deleted!
              1 Reply Last reply
              0
              • H Offline
                H Offline
                hobbyProgrammer
                wrote on last edited by
                #7

                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);
                }
                
                JonBJ 1 Reply Last reply
                0
                • H hobbyProgrammer

                  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);
                  }
                  
                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #8

                  @hobbyProgrammer
                  I don't know what is going on here, but I note that for a given circuitID you do two new Circuit(circuitID)s, one in fillCircuitMenu() and another any time slot goToCircuit(int index) is invoked. I don't know if that is correct, no re-use of same Circuit 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 from SIGNAL/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.

                  1 Reply Last reply
                  3

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved