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
Forum Updated to NodeBB v4.3 + New Features

Dynamic QWidget for QStackedWidget using ID

Scheduled Pinned Locked Moved Unsolved General and Desktop
qstackedwidgetqwidget
8 Posts 3 Posters 1.5k Views 1 Watching
  • 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 12 Dec 2019, 15:29 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
    • M Offline
      M Offline
      mrjj
      Lifetime Qt Champion
      wrote on 12 Dec 2019, 15:56 last edited by mrjj 12 Dec 2019, 15:58
      #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 13 Dec 2019, 11:18
      0
      • M mrjj
        12 Dec 2019, 15:56

        @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 13 Dec 2019, 11:18 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);
        
        J 1 Reply Last reply 13 Dec 2019, 13:23
        0
        • H hobbyProgrammer
          13 Dec 2019, 11:18

          @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);
          
          J Offline
          J Offline
          JonB
          wrote on 13 Dec 2019, 13:23 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 17 Dec 2019, 07:57
          1
          • J JonB
            13 Dec 2019, 13:23

            @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 17 Dec 2019, 07:57 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 17 Dec 2019, 08:25 last edited by
              #6
              This post is deleted!
              1 Reply Last reply
              0
              • H Offline
                H Offline
                hobbyProgrammer
                wrote on 17 Dec 2019, 08:33 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);
                }
                
                J 1 Reply Last reply 17 Dec 2019, 09:09
                0
                • H hobbyProgrammer
                  17 Dec 2019, 08:33

                  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);
                  }
                  
                  J Offline
                  J Offline
                  JonB
                  wrote on 17 Dec 2019, 09:09 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

                  1/8

                  12 Dec 2019, 15:29

                  • Login

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