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. Is it possible to Convert a QSqlQuery Model to a QsqlTableModel
Forum Updated to NodeBB v4.3 + New Features

Is it possible to Convert a QSqlQuery Model to a QsqlTableModel

Scheduled Pinned Locked Moved Solved General and Desktop
20 Posts 3 Posters 6.2k Views 2 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.
  • VRoninV Offline
    VRoninV Offline
    VRonin
    wrote on last edited by
    #6

    I'm afraid you have to do it manually. there is no way for the framework to find out what record to update in the db so I doubt it will ever be implemented.

    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
    ~Napoleon Bonaparte

    On a crusade to banish setIndexWidget() from the holy land of Qt

    1 Reply Last reply
    0
    • AsimovA Offline
      AsimovA Offline
      Asimov
      wrote on last edited by Asimov
      #7

      Thanks Ronin I have worked out how to use the QStandardItemModel.

      void DbManager::boxList(Ui::MainWindow* ui){
      
          QSqlQuery* query=new QSqlQuery(mydb);
          query->prepare("select `boxID`,`boxName`,`boxLocation` from `boxes`");
          query->exec();
          modelBox= new QStandardItemModel(sqlSize(query), 3);
          int i=0;
          while (query->next())
          {
              modelBox->setData(modelBox->index(i, 0), query->value("boxID"));
              modelBox->setData(modelBox->index(i, 1), query->value("boxName"));
              modelBox->setData(modelBox->index(i, 2), query->value("boxLocation"));
              i++;
          }
          modelBox->setHeaderData(1, Qt::Horizontal, QObject::tr("Box ID / Name"));
          modelBox->setHeaderData(2, Qt::Horizontal, QObject::tr("Box Location"));
          ui->boxTable->setModel(modelBox);
          ui->boxTable->setColumnHidden(0, true);
      }
      

      So now I can use this to do my query. Good thing is that most of my functions work, but I am still having a small problem.
      I have got delete to work, but getting the id of the clicked line and then doing a query that is good, but I am having trouble with the enter key.

      I have it set that when I double click on a line it goes into edit mode. Obviously I have to handle saving to the database on my own, but I don't know how to run my event when the enter/return key is pressed.

      Basically I need to catch the return key event, and run my code to add the line to the database. I have looked through the list of slots for the table key, and tried a few but none of them seem to work when the return is pressed.

      I have tried:
      entered(QModelIndex)
      pressed(QModelindex)

      but none of these work.
      So how do I catch the enter/return key in edit mode in a QTableView?
      (I haven't started a new post to ask this question because it is on the same subject, but I can if I am supposed to)

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #8

        Hi,

        You can use the dataChanged signal so you can retrieve the modified data and do what you need with it.

        On a side note, you have a memory leak. You never delete your query object. Not that there's no need to create it on the heap at.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • AsimovA Offline
          AsimovA Offline
          Asimov
          wrote on last edited by Asimov
          #9

          Hi SGaist,

          I have looked through the slots for the QTableView and I can't see a slot that says datachanged.
          eg

          activated
          clicked
          doubleClicked
          entered
          iconSize
          pressed
          viewportEntered
          destroyed
          objectNameChanged
          customerContextMenuRequested
          windowIconChanged
          windowIconChanged
          windowIconTextChanged
          windowTitleChanged
          

          And the documents are not very clear how to implement a datachange. There is a lot in the docs that show you what the command does, and does not give an example.

          I didn' t know I had to delete the query object. In php you have query->close(), but I didn't know there was a similar thing in QT. I am going to have to look up how to do this now.

          I have recently spent more time in php and mysql coding than I have doing C++, so I am a bit rusty and new to QT. In the past I have used visual studio and Codeblocks.

          Thanks for the tip. Going to look into this now.

          PS. I put this into my mainwindow.cpp constructor, but it didn't do anything

           connect(ui->boxTable, SIGNAL(dataChanged(QStandardItem*)),this,SLOT(on_edit_clicked()));
          

          So still searching for an answer why it isn't working.

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #10

            Because it's not a slot from QTableView but a signal from your model base class.

            You are allocating the query object on the heap, you have to delete it once you're done using it. It's nothing Qt specific, it's C++ object life time management. Like I wrote, in your case the simple solution is to allocate it on the stack.

            The connect statement will show a warning at run time. I'd recommend moving to the new Qt 5 notation. Also the signal matches a QTableWidget but not a QTableView.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            1
            • AsimovA Offline
              AsimovA Offline
              Asimov
              wrote on last edited by Asimov
              #11

              Hi SGaist,

              I have tried again this time I am using my model which is created in DbManager class. In the header file the class is set up DbManager myDatabase; and modelBox which is my model is created in that class.

              connect(myDatabase.modelBox, SIGNAL(dataChanged(const QModelIndex&)),this,SLOT(test()));
              

              I am just getting it to respond, but it isn't

              void MainWindow::test(){
                  qDebug() << "signal";
              }
              

              So the signal does not seem to be working. I am very perplexed.
              I have tried to look at the new qt5 format and that is even more confusing. I don't even now where to put the callback on that. Once I have got the old one to work, I might look into the new one again.

              On another note I am now using

              delete query;
              

              Which should free up the memory on the stack hopefully.

              PS. I am getting this error

              QObject::connect: No such signal QStandardItemModel::dataChanged(const QModelIndex&)
              QObject::connect:  (receiver name: 'MainWindow')
              
              1 Reply Last reply
              0
              • AsimovA Offline
                AsimovA Offline
                Asimov
                wrote on last edited by Asimov
                #12

                Hi,

                After making my last post I decided to call connect from my DbManager class like this

                void DbManager::boxList(Ui::MainWindow* ui){
                    QSqlQuery* query=new QSqlQuery(mydb);
                    query->prepare("select `boxID`,`boxName`,`boxLocation` from `boxes`");
                    query->exec();
                
                    modelBox= new QStandardItemModel(sqlSize(query), 3);
                    int i=0;
                    while (query->next())
                    {
                        modelBox->setData(modelBox->index(i, 0), query->value("boxID"));
                        modelBox->setData(modelBox->index(i, 1), query->value("boxName"));
                        modelBox->setData(modelBox->index(i, 2), query->value("boxLocation"));
                        i++;
                    }
                    modelBox->setHeaderData(1, Qt::Horizontal, QObject::tr("Box ID / Name"));
                    modelBox->setHeaderData(2, Qt::Horizontal, QObject::tr("Box Location"));
                    ui->boxTable->setModel(modelBox);
                    ui->boxTable->setColumnHidden(0, true);
                    delete query;
                    QObject::connect(modelBox, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),modelBox,SLOT(updateBoxList(ui,const QModelIndex & , const QModelIndex &)));
                }
                

                The good news is that I have now got rid of the signal error, but now I am getting a slot error like this

                QObject::connect: No such slot QStandardItemModel::updateBoxList(ui,const QModelIndex & , const QModelIndex &)
                

                In my DbManager class header I have

                public slots:
                        void updateBoxList(Ui::MainWindow *ui,const QModelIndex & , const QModelIndex &);
                
                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #13

                  Then, why do you pass modelBox as the object containing that slot ?

                  Again, there's no need to allocate query on the heap, use a local stack variable, that's enough.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  0
                  • AsimovA Offline
                    AsimovA Offline
                    Asimov
                    wrote on last edited by Asimov
                    #14

                    I used modelBox as the container of the slot because originally I used this, but then I got an error by doing this. Then I changed it to modelBox the name of my model. Anyway I changed it back to this, and it still says there is no slot. I am getting a little confused.

                    modelBox is the name of the model, which holds the data for the table. You said in your last post not to use the QTableView but the name of the model. So I used the name of the model instead of ui->boxTable which was the name of the QTableView.

                    I don't know how to use a local stack variable.
                    It has been a couple of years since I have done any C++, and I am trying to get back into it.
                    Also I have only been using QT for about a week, so I am new at all this, and having to learn fast.

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #15

                      From the code you posted, the slot is in DbManager.

                      Note that you are trying to do something wrong here. It seems you try to pass the ui variable in SLOT which is not possible.

                      Since it seems that you manage the model directly in DbManager, there's no need to involve your MainWindow class. Once you update modelBox, it will trigger updates in boxTable automatically.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      0
                      • AsimovA Offline
                        AsimovA Offline
                        Asimov
                        wrote on last edited by Asimov
                        #16

                        Well SGaist you have solved my signal problem. Taking out the ui worked. My signal is now firing and running my update function, thankyou.

                        The problem is that I have been passing the ui so I can update the ui. You see when I call void DbManager::boxList(Ui::MainWindow* ui) I send in the ui because my class has no access to the ui, so if I don't pass it in, I can't update anything on the window. So I pass the ui from MainWindow to my class DbManager. This is why I was sending the ui to my function in the slot.

                        If my function needs to update any ui element then it won't be able to because I have not passed it the ui.
                        Hmm just had an idea, perhaps when I setup my Dbmanager class I can pass the ui in the contructor and then all my functions will have acces to the ui.

                        I think I solved the local stack problem now. I had to change query-> to query. all through the code. Here is my new code.

                        void DbManager::boxList(Ui::MainWindow* ui){
                            QSqlQuery query;
                            query.prepare("select `boxID`,`boxName`,`boxLocation` from `boxes`");
                            query.exec();
                            modelBox= new QStandardItemModel(sqlSize(query), 3);
                            int i=0;
                            while (query.next())
                            {
                                modelBox->setData(modelBox->index(i, 0), query.value("boxID"));
                                modelBox->setData(modelBox->index(i, 1), query.value("boxName"));
                                modelBox->setData(modelBox->index(i, 2), query.value("boxLocation"));
                                i++;
                            }
                            modelBox->setHeaderData(1, Qt::Horizontal, QObject::tr("Box ID / Name"));
                            modelBox->setHeaderData(2, Qt::Horizontal, QObject::tr("Box Location"));
                            ui->boxTable->setModel(modelBox);
                            ui->boxTable->setColumnHidden(0, true);
                            QObject::connect(modelBox, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),this,SLOT(updateBoxList(const QModelIndex & , const QModelIndex &)));
                        }
                        
                        1 Reply Last reply
                        0
                        • SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #17

                          Then your design is not good. You are creating a tight coupling that doesn't do much good.

                          DbManager should not need to know MainWindow nor should it car about it. From what I gathered from your code, it should only operate on the model. If you need your MainWindow to do stuff based on actions from DbManager, then you should implement it through signals and slots. Make your DbManager share information as needed and plug your MainWindow on that. Doing so will make your encapsulation cleaner and if you need to change anything in your MainWindow to modify your GUI then you won't have to change anything in your DbManager class.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          AsimovA 1 Reply Last reply
                          1
                          • SGaistS SGaist

                            Then your design is not good. You are creating a tight coupling that doesn't do much good.

                            DbManager should not need to know MainWindow nor should it car about it. From what I gathered from your code, it should only operate on the model. If you need your MainWindow to do stuff based on actions from DbManager, then you should implement it through signals and slots. Make your DbManager share information as needed and plug your MainWindow on that. Doing so will make your encapsulation cleaner and if you need to change anything in your MainWindow to modify your GUI then you won't have to change anything in your DbManager class.

                            AsimovA Offline
                            AsimovA Offline
                            Asimov
                            wrote on last edited by
                            #18

                            @SGaist

                            Partly I agree with you, but it could cause me a few problems.
                            My DbManager class is to do all database related functions.

                            In my previous post I showed my function boxList which sets up the model from the database and this is in my Dbmanager class, but without the ui, I couldn't run the following line.

                            ui->boxTable->setModel(modelBox);
                            

                            I think I could have more ui functions in MainWindow, and limit my use of ui in my DbManager class.
                            So I agree in principle, but whether I can get it to work is another thing LOL

                            1 Reply Last reply
                            0
                            • SGaistS Offline
                              SGaistS Offline
                              SGaist
                              Lifetime Qt Champion
                              wrote on last edited by
                              #19

                              The request the model from your DbManager through a getter and let the MainWindow set it to whatever widget you want for this task. This will again make the DbManager independent from the GUI.

                              Interested in AI ? www.idiap.ch
                              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                              1 Reply Last reply
                              0
                              • AsimovA Offline
                                AsimovA Offline
                                Asimov
                                wrote on last edited by Asimov
                                #20

                                I think I understand.
                                So I can have a function in DbManager like

                                QStandardItemModel DbManager::getModelBox()
                                {
                                     return modelBox;
                                }
                                

                                Then in Windows Main I can call it like this

                                myDatabase.getModelbox()->setModel(modelBox);
                                

                                I am going to give tihs a go now. Thanks.

                                PS. After playing with it for a while I realise my code above was wrong. So here is the code that worked, in case anyone is following this thread

                                QStandardItemModel* DbManager::getmodelBox()
                                {
                                     return modelBox;
                                }
                                

                                And in MainWindow I can call it like tihs

                                ui->boxTable->setModel(myDatabase.getmodelBox());
                                

                                Thanks SGaist I have learnt a lot. Will mark this thread as solved, even though I got a lot of answers, thanks

                                1 Reply Last reply
                                0

                                • Login

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