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. Use QTreeWidget with non-static data.
Qt 6.11 is out! See what's new in the release blog

Use QTreeWidget with non-static data.

Scheduled Pinned Locked Moved Solved General and Desktop
30 Posts 4 Posters 10.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.
  • Z Offline
    Z Offline
    ZiketCPP
    wrote on last edited by
    #21

    @VRonin take a care that all u did is before the show() function or is inside the Signal/Slot button function that you created.

    mrjjM 1 Reply Last reply
    0
    • Z ZiketCPP

      @VRonin take a care that all u did is before the show() function or is inside the Signal/Slot button function that you created.

      mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #22

      in the main loop of the render for example.

      What render do you mean ?

      Qt is controlled by events which are distributed with this function
      return app.exec(); << loops around here
      http://doc.qt.io/qt-5/qapplication.html#exec

      So if you mean it only works if you let the the event loop run, you are correct.
      if you make a tight for loop and never leave it, it cannot work.

      If you create a button

      void MainWindow::on_pushButton_clicked()
      {
          for(;;);
      
      }
      
      

      You will have 100% killed the program and it cant move or draw itself.

      Also its perfectly fine to show the widget first then add Items.

      int main(int argc, char *argv[])
      {
              QApplication app(argc,argv);
              QWidget wid;
              wid.show(); // show first
      
              QTreeWidget* treeWid=new QTreeWidget(&wid);
              treeWid->setColumnCount(2);
              treeWid->setHeaderLabels(QStringList() << "Name" << "Type");
             for(int i=0;i<10;i++){
                  insertRow(treeWid->model());
              }
              QVBoxLayout* widlay=new QVBoxLayout(&wid);
              widlay->addWidget(treeWid);
      
              return app.exec(); // first here it will be drawn anyway
      }
      

      Also a slot function is a normal c++ function.
      There is no difference.

      So if you call it insertRow from somewhere and its not working, its either a
      plain bug OR you are blocking the event loop by use for/while statement that
      never terminates. ( as VRonin says)

      Inserting rows works outside constructors and member functions used as slot.

      If you see otherwise, please post the whole code where you call
      insertRow and we can try help spot what is going on.

      1 Reply Last reply
      3
      • Z Offline
        Z Offline
        ZiketCPP
        wrote on last edited by
        #23

        @mrjj no, i am not blocking the update. One question, with the @VRonin code, is there a possibilitty to call via c++ the pushButton->clicked() function? If you connect the click function to the lambda and then u call PushButton->clicked() nothing will appear in the tree (supposedly it would have to appear one row).
        If this can be, how can I pass user data throw the function, as a parameter? Thank you!!!!

        mrjjM 1 Reply Last reply
        0
        • Z ZiketCPP

          @mrjj no, i am not blocking the update. One question, with the @VRonin code, is there a possibilitty to call via c++ the pushButton->clicked() function? If you connect the click function to the lambda and then u call PushButton->clicked() nothing will appear in the tree (supposedly it would have to appear one row).
          If this can be, how can I pass user data throw the function, as a parameter? Thank you!!!!

          mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by mrjj
          #24

          @ZiketCPP

          Hi
          The button clicked() is a signal ánd is called internally by
          emit Clicked()
          one dont call like a normal functions as its a signal and emit must be use.

          Not sure you can emit it from outside and why would you ?
          I think its possible with meta calls but i never tried.
          You can call it like

          QMetaObject::invokeMethod(addTreeBtn, "clicked",
             Qt::QueuedConnection,
             Q_ARG(QString, "p1"),
             Q_ARG(QString, "p2"));
          

          But it will say
          QMetaObject::invokeMethod: No such method QPushButton::clicked(QString,QString)
          Candidates are:
          clicked(bool)
          clicked()

          Only
          QMetaObject::invokeMethod(addTreeBtn, "clicked", Qt::QueuedConnection );
          will work.

          Clicked() do not have parameters so you cannot add new ones as then
          the buttons real clicked() could not work. How would it get the parameters?

          Can I ask what you are trying ? it seems sort of reverse.

          If you want to be able to call it both from a function and use with a button, simply use
          a normal slot function and not a lambda. Then you can both call the slot or let a button do it.
          But i repeat. The clicked() signal has no parameters and you cannot just add some.

          so the void insertRow(QAbstractItemModel* const mdl) seems like a good idea.

          Also, if you want to use slot & Signals, the main is not a good place as moc only runs on .h files.
          (hax included, see last line)

          But since it causing you so much issues there must be something going on we don't see.

          i also wondered about

          • if you don't insert the elements using the Signal/Slot this does not work

          So in what way are you trying then ?

          Also all ways are possible

          
          void insertRow(QAbstractItemModel* const mdl, const QString& ColData1, const QString& ColData2) {
            const int rowCount = mdl->rowCount();
            if(mdl->insertRow(rowCount)) {
              qDebug("Row Inserted!");
              mdl->setData(mdl->index(rowCount, 0), ColData1);
              mdl->setData(mdl->index(rowCount, 1), ColData2);
            }
          }
          
          class SlotHolder : public QObject {
            Q_OBJECT
          public slots:
            void AddRowsWithParam(QAbstractItemModel* const mdl, const QString& ColData1, const QString& ColData2) {
              insertRow(mdl, ColData1, ColData2);
            }
          };
          
          int main(int argc, char* argv[]) {
            QApplication app(argc, argv);
            QWidget wid;
            QPushButton* addTreeBtn = new QPushButton("Add Row", &wid);
            QTreeWidget* treeWid = new QTreeWidget(&wid);
            treeWid->setColumnCount(2);
            treeWid->setHeaderLabels(QStringList() << "Name" << "Type");
            QObject::connect(addTreeBtn, &QPushButton::clicked, treeWid, [treeWid]() {
              insertRow(treeWid->model(), "From Lambda", "From Lambda");
          
            });
          
            insertRow(treeWid->model(), "FROM MAIN as function", "NO SLOT");
          
            SlotHolder dummy;
            dummy.AddRowsWithParam(treeWid->model(), "As function call via slot", "YEAH");
          
            QVBoxLayout* widlay = new QVBoxLayout(&wid);
            widlay->addWidget(addTreeBtn);
            widlay->addWidget(treeWid);
            wid.show();
            return app.exec();
          }
          
          #include "main.moc" // HAX TO MAKE MOC RUN ON . CPP run qmake manually
          
          

          alt text

          1 Reply Last reply
          2
          • Z Offline
            Z Offline
            ZiketCPP
            wrote on last edited by
            #25

            @mrjj ok, I am trying to create a custom Graphic Engine (like Unreal 4), at this moment I have a big structure to use all the OpenGL functionality without the knowledge about it (user interface communicates with the Opengl class).
            I have one class that inherits from QOpenGLWidget & QOpenglFunctions.
            The real problem is that I have to insert rows AFTER the app.exec() call, that means if the user wants to create a simple cube and drag it to the "scene"(the render widget), it has to appear in the QTreeWidget. That is my problem, I don't want the functionality inside this button CreateCube, I want, for example: If the user clicks on the CreateCube button,inside the class QOpenglFunction that I have, create a simple function that receives a simple insertRow(void userdata)*.
            That seems impossible, the function won't work. And I repeat, I don't pause the updates with an infinite loop.

            At this moment of the discussion, I have a TreeNodesManager.ui with the correspondent .h that has the function InsertRow(void* UserData), and inside the ui file I have the QTreeWidget pointer.
            In the other side I have my InterfaceRender.h that inherits from QOpenglWidget & OpenGL and if I want to test something: I override the PaintGL() function and put this

            class InterfaceRender : public QOpenglFunctions, public QOpenglWidget {
            public:
             //THE CLASS IS NOT COMPLETE
            void PainGL()override {
              //And here insert one row per frame (only to test my case) with my own data
              PointerTo TreeNodesManager->insertRow(&cubeWithParallaxMapping);
            }
            
            }
            

            And here my class that manages the QTreeWidget, keep in mind that the QTreeWidget is in the UI file:

            class TreeNodesManager : public QWidget {
            public:
              
             TreeNodesManager(QWidget* parent), QWidget(parent) {
                ui->setupUi(this);
                ui->treeWidget->setColumnCount(2);
                ui->treeWidget->setHeaderLabels(QStringList() << "Name" << "Type");
                
              }
              //And the fantastic function
              void InsertRow(void* UserData) {
                //Cast the user data to anything, I don't care
                QAbstractItemModel* const mdl= ui->treeWidget->model();
                 const int rowCount =mdl->rowCount();
                 if(mdl->insertRow(rowCount)){
                    qDebug("Row Inserted!");
                    if(mdl->setData(mdl->index(rowCount,0), UserData->name))
                       qDebug("name Written");
                    if(mdl->setData(mdl->index(rowCount,1),UserData->description))
                       qDebug("description Written");
                 }
              }
            }
            

            Look the last function insertData, ALL THE qDEBUG is called.
            Please explain me how can I insert data AFTER the app.exec() is called (at runtime). I try this in the PainGL() function that is called one time per frame and it doesn't work

            mrjjM 1 Reply Last reply
            0
            • Z ZiketCPP

              @mrjj ok, I am trying to create a custom Graphic Engine (like Unreal 4), at this moment I have a big structure to use all the OpenGL functionality without the knowledge about it (user interface communicates with the Opengl class).
              I have one class that inherits from QOpenGLWidget & QOpenglFunctions.
              The real problem is that I have to insert rows AFTER the app.exec() call, that means if the user wants to create a simple cube and drag it to the "scene"(the render widget), it has to appear in the QTreeWidget. That is my problem, I don't want the functionality inside this button CreateCube, I want, for example: If the user clicks on the CreateCube button,inside the class QOpenglFunction that I have, create a simple function that receives a simple insertRow(void userdata)*.
              That seems impossible, the function won't work. And I repeat, I don't pause the updates with an infinite loop.

              At this moment of the discussion, I have a TreeNodesManager.ui with the correspondent .h that has the function InsertRow(void* UserData), and inside the ui file I have the QTreeWidget pointer.
              In the other side I have my InterfaceRender.h that inherits from QOpenglWidget & OpenGL and if I want to test something: I override the PaintGL() function and put this

              class InterfaceRender : public QOpenglFunctions, public QOpenglWidget {
              public:
               //THE CLASS IS NOT COMPLETE
              void PainGL()override {
                //And here insert one row per frame (only to test my case) with my own data
                PointerTo TreeNodesManager->insertRow(&cubeWithParallaxMapping);
              }
              
              }
              

              And here my class that manages the QTreeWidget, keep in mind that the QTreeWidget is in the UI file:

              class TreeNodesManager : public QWidget {
              public:
                
               TreeNodesManager(QWidget* parent), QWidget(parent) {
                  ui->setupUi(this);
                  ui->treeWidget->setColumnCount(2);
                  ui->treeWidget->setHeaderLabels(QStringList() << "Name" << "Type");
                  
                }
                //And the fantastic function
                void InsertRow(void* UserData) {
                  //Cast the user data to anything, I don't care
                  QAbstractItemModel* const mdl= ui->treeWidget->model();
                   const int rowCount =mdl->rowCount();
                   if(mdl->insertRow(rowCount)){
                      qDebug("Row Inserted!");
                      if(mdl->setData(mdl->index(rowCount,0), UserData->name))
                         qDebug("name Written");
                      if(mdl->setData(mdl->index(rowCount,1),UserData->description))
                         qDebug("description Written");
                   }
                }
              }
              

              Look the last function insertData, ALL THE qDEBUG is called.
              Please explain me how can I insert data AFTER the app.exec() is called (at runtime). I try this in the PainGL() function that is called one time per frame and it doesn't work

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by mrjj
              #26

              @ZiketCPP
              One question. this is single threaded correct? None of it runs in other thread?
              All part of UI ? Its forbidden to alter UI stuff from other treads unless using signals and slots.

              Also when you say AFTER the app.exec(), we agree it just means
              when app is running ?

              Why cant u just emit signal from PaintGL() ?
              Why must it be function call?

              But unless there are multiple threads involved, calling the function directly should do it.

              since InterfaceRender is also a widget, if u add Q_OBJECT it can emit signals.

              ¨so

              class InterfaceRender : public QOpenglFunctions, public QOpenglWidget {
              Q_OBJECT
              public:
              void PainGL()override {
                //And here insert one row per frame (only to test my case) with my own data
                emit insertRow(&cubeWithParallaxMapping);
              }
              

              just define it as a signals in .h

              and in

              class TreeNodesManager : public QWidget {
              Q_OBJECT
              public slots:
                void InsertRow(void* UserData)   {...]
              

              then connect them and it should work.
              connect(InterfaceRender, SIGNAL(InsertRow(void* )),TreeNodesManagerPTR, SLOT(InsertRow(void* )), Qt::QueuedConnection );

              Note there might be issue with the cubeWithParallaxMapping since its a void * as QueuedConnection
              wants to be able to copy it

              1 Reply Last reply
              1
              • Z Offline
                Z Offline
                ZiketCPP
                wrote on last edited by
                #27

                @mrjj my program is single threaded, yes, and the problem is not the Q_OBJECT, that was already added.
                I try to emit a signal from PaintGL() and it still doesn't work, is amazing but the insertRow function is called if I emit a signal, but the QTreeWidget is not updated with the row!!!!! That was my problem at the start of the thread.
                Why cannot I use the insertRow without signals and slots?
                If you have a Pointer to the QTreeWidget in the InterfaceRender class this still doesn't work:

                class InterfaceRender : public QOpenglFunctions, public QOpenglWidget {
                Q_OBJECT
                public:
                //The pointer to the TreeWidget
                QTreeWidget* TreePointer;
                
                //The update function
                void PainGL()override {
                  //And here insert one row per frame (only to test my case) with my own data
                  //Cast the user data to anything, I don't care
                    QAbstractItemModel* const mdl= TreePointer->model();
                     const int rowCount =mdl->rowCount();
                     if(mdl->insertRow(rowCount)){
                        qDebug("Row Inserted!");
                        if(mdl->setData(mdl->index(rowCount,0), UserData->name))
                           qDebug("name Written");
                        if(mdl->setData(mdl->index(rowCount,1),UserData->description))
                           qDebug("description Written");
                     }
                  }
                }
                

                Explain me, why I can't use this? Imagine that the pointer exists (is set at any point of the program). If you try something like this, the QTreeWidget won't show ANYTHING, it seems that is empty... That was the main problem.

                mrjjM 1 Reply Last reply
                0
                • Z ZiketCPP

                  @mrjj my program is single threaded, yes, and the problem is not the Q_OBJECT, that was already added.
                  I try to emit a signal from PaintGL() and it still doesn't work, is amazing but the insertRow function is called if I emit a signal, but the QTreeWidget is not updated with the row!!!!! That was my problem at the start of the thread.
                  Why cannot I use the insertRow without signals and slots?
                  If you have a Pointer to the QTreeWidget in the InterfaceRender class this still doesn't work:

                  class InterfaceRender : public QOpenglFunctions, public QOpenglWidget {
                  Q_OBJECT
                  public:
                  //The pointer to the TreeWidget
                  QTreeWidget* TreePointer;
                  
                  //The update function
                  void PainGL()override {
                    //And here insert one row per frame (only to test my case) with my own data
                    //Cast the user data to anything, I don't care
                      QAbstractItemModel* const mdl= TreePointer->model();
                       const int rowCount =mdl->rowCount();
                       if(mdl->insertRow(rowCount)){
                          qDebug("Row Inserted!");
                          if(mdl->setData(mdl->index(rowCount,0), UserData->name))
                             qDebug("name Written");
                          if(mdl->setData(mdl->index(rowCount,1),UserData->description))
                             qDebug("description Written");
                       }
                    }
                  }
                  

                  Explain me, why I can't use this? Imagine that the pointer exists (is set at any point of the program). If you try something like this, the QTreeWidget won't show ANYTHING, it seems that is empty... That was the main problem.

                  mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by
                  #28

                  @ZiketCPP
                  Ok and you are 1000% sure TreePointer points to the UI one ?

                  I cant explain it. seems not right. Also if it triggers the signal and goes into the
                  insertRow function then unless its wrong model or wrong Tree, it should
                  work.
                  Have you tried add a line in Designer and check if the Tree you talk to have 1 item?

                  1 Reply Last reply
                  2
                  • Z Offline
                    Z Offline
                    ZiketCPP
                    wrote on last edited by
                    #29

                    @mrjj thanks to you I found the problem,
                    The QWidget paint was not complete, in my QTreeWidget, that was cause errors displaying the content, it only displays the content inserted via Constructor, all after this won't be shown. I was playing with the bad framebuffer....
                    Sorry about this, and really thank you!
                    How can I mark this thread as Solved?

                    mrjjM 1 Reply Last reply
                    0
                    • Z ZiketCPP

                      @mrjj thanks to you I found the problem,
                      The QWidget paint was not complete, in my QTreeWidget, that was cause errors displaying the content, it only displays the content inserted via Constructor, all after this won't be shown. I was playing with the bad framebuffer....
                      Sorry about this, and really thank you!
                      How can I mark this thread as Solved?

                      mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by
                      #30

                      @ZiketCPP
                      Ooh but you found it \o/ \o/ \o/ \o/

                      On first post, in Topic Tool button, you can mark solved

                      1 Reply Last reply
                      2

                      • Login

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