Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Brainstorm
  4. suggestions for repeating display views
Qt 6.11 is out! See what's new in the release blog

suggestions for repeating display views

Scheduled Pinned Locked Moved Solved Brainstorm
36 Posts 5 Posters 24.7k Views 3 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.
  • mzimmersM mzimmers

    Thanks for the reference. I've taken some of that example and adapted it.

    So, to summarize, I have a QTableView that is associated with a QAbstractItemModel. The table reveals a few details about all the devices (rows) found. Now I'd like to display some additional detail about any device that the user selects.

    A very simple start would be to display the MAC address in a QLineEdit when the user selects a row. I can envision a way to do this, but it's cumbersome and indirect (signalling the model to extract the information and signal it back to the widget). Can someone inform me of a preferred method to do this?

    Thanks...

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by JonB
    #11

    @mzimmers

    but it's cumbersome and indirect (signalling the model to extract the information and signal it back to the widget)

    Why? What do you have in mind by "indirect" & "signalling"? You haven't mentioned threads anywhere, so assuming your UI, view & model are all in the same thread where is there any "signalling" involved (unless you mean the row selected signal, but that does not matter)?

    You just retrieve the data via QAbstractItemModel::data() and plonk it into your widget(s), explicitly.

    Depending, you can already have retrieved the "additional detail" into your model without having to display it in the QTableView, so you can access it without having to do work at that instant if you prefer (perhaps not relevant for your device-model, but often the case when it's a database-model).

    1 Reply Last reply
    0
    • mzimmersM mzimmers

      Thanks for the reference. I've taken some of that example and adapted it.

      So, to summarize, I have a QTableView that is associated with a QAbstractItemModel. The table reveals a few details about all the devices (rows) found. Now I'd like to display some additional detail about any device that the user selects.

      A very simple start would be to display the MAC address in a QLineEdit when the user selects a row. I can envision a way to do this, but it's cumbersome and indirect (signalling the model to extract the information and signal it back to the widget). Can someone inform me of a preferred method to do this?

      Thanks...

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #12

      Well, I'd just fill the model data as it comes. And it'd come as the selection of the selection model changes ... I think just subscribing to the QItemSelectionModel::selectionChanged signal should be enough, no?

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      2
      • mzimmersM Offline
        mzimmersM Offline
        mzimmers
        wrote on last edited by mzimmers
        #13

        Here's what I'm trying to do in my display:

        // in my c'tor.
            QObject::connect(ui->tableView->selectionModel(), QItemSelectionModel::currentRowChanged, this, &Widget::updateDetails);
        }
        
        void Widget::updateDetails(QModelIndex i)
        {
            int row = i.row();
            QVariant qv;
            QString s;
            QModelIndex qmi;
            qmi = m_model->getModel()->index(row, DEV_MACADDR, QModelIndex());
            qv = m_model->getModel()->data(qmi, DEV_MACADDR);
            s = qv.toString();
            ui->macAddr->setText(s);
        
            qmi = m_model->getModel()->index(row, DEV_DEVNAME, QModelIndex());
            qv = m_model->getModel()->data(qmi, DEV_DEVNAME);
            s = qv.toString();
            ui->devName->setText(s);
        
            qmi = m_model->getModel()->index(row, DEV_LATEST_HB, QModelIndex());
            qv = m_model->getModel()->data(qmi, DEV_LATEST_HB);
            s = qv.toString();
            ui->heartbeat->setText(s);
        

        I'm sure this isn't the best way to do this (particularly since it doesn't work), but in any event, the first assignment of qv works, but the others give qv an invalid value. What am I doing wrong?

        EDIT: OK, I just realized I shouldn't be using the 2nd argument to the data() call. It's working now. Not ready to mark this solved yet, though, as I'm going to have other questions in a bit.

        Thanks...

        1 Reply Last reply
        0
        • mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #14

          So far, I've been experimenting entirely with QStrings as elements in my model, like this:

          struct DeviceDetails
          {
              uint8_t macAddr[6];
              char devName[25];
          ...
          } d;
          QAbstractItemModel *m_model;
          ...   
           m_model->setData(m_model->index(row, DEV_DEVNAME), d.devName); /
          

          I'm now trying to work with other data types, such as the macAddr, but I can't figure out how to do this. This is what I'm trying to do (but doesn't compile):

              m_model->setData(m_model->index(row, DEV_MACADDR), d.macAddr);
          

          How do I do this? Thanks...

          kshegunovK 1 Reply Last reply
          0
          • mzimmersM mzimmers

            So far, I've been experimenting entirely with QStrings as elements in my model, like this:

            struct DeviceDetails
            {
                uint8_t macAddr[6];
                char devName[25];
            ...
            } d;
            QAbstractItemModel *m_model;
            ...   
             m_model->setData(m_model->index(row, DEV_DEVNAME), d.devName); /
            

            I'm now trying to work with other data types, such as the macAddr, but I can't figure out how to do this. This is what I'm trying to do (but doesn't compile):

                m_model->setData(m_model->index(row, DEV_MACADDR), d.macAddr);
            

            How do I do this? Thanks...

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #15

            @mzimmers said in suggestions for repeating display views:

            but doesn't compile

            With what error?
            I could imagine QVariant isn't aware of how to serialize that type, but that's just a speculation at this point.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0
            • mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by
              #16
              C:\Qt\5.10.1\mingw53_32\include\QtCore\qvariant.h:471: error: 'QVariant::QVariant(void*)' is private
                   inline QVariant(void *) Q_DECL_EQ_DELETE;
                          ^
              

              and:

              C:\Users\MZimmers\CD desktop apps\Qt projects\wb_utility\model.cpp:36: error: use of deleted function 'QVariant::QVariant(void*)'
              
              kshegunovK VRoninV 2 Replies Last reply
              0
              • mzimmersM mzimmers
                C:\Qt\5.10.1\mingw53_32\include\QtCore\qvariant.h:471: error: 'QVariant::QVariant(void*)' is private
                     inline QVariant(void *) Q_DECL_EQ_DELETE;
                            ^
                

                and:

                C:\Users\MZimmers\CD desktop apps\Qt projects\wb_utility\model.cpp:36: error: use of deleted function 'QVariant::QVariant(void*)'
                
                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by
                #17

                Well, I suggest you convert d.macAddr to QString before you pass it to setData ...

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                2
                • mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #18
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • mzimmersM mzimmers
                    C:\Qt\5.10.1\mingw53_32\include\QtCore\qvariant.h:471: error: 'QVariant::QVariant(void*)' is private
                         inline QVariant(void *) Q_DECL_EQ_DELETE;
                                ^
                    

                    and:

                    C:\Users\MZimmers\CD desktop apps\Qt projects\wb_utility\model.cpp:36: error: use of deleted function 'QVariant::QVariant(void*)'
                    
                    VRoninV Offline
                    VRoninV Offline
                    VRonin
                    wrote on last edited by VRonin
                    #19

                    @mzimmers said in suggestions for repeating display views:

                    'QVariant::QVariant(void*)' is private

                    That is a "safeguard" operator to avoid people using pointers to non-QObjects into a QVariant.
                    Basically macAddr is of type unsigned char* the d will still own the data into d.macAddr and will delete it when it goes out of scope. QVariant needs to own the data and know how to delete it. you should be able to hack your way around it by using a smart pointer but it's probably much easier to store it in a Qt container like QByteArray
                    m_model->setData(m_model->index(row, DEV_MACADDR), QByteArray(d.macAddr,sizeof(d.macAddr));

                    P.S.
                    If the compiler complains about signed/unsigned you can use:
                    QByteArray(static_cast<char*>(d.macAddr),sizeof(d.macAddr))

                    "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

                    mzimmersM 1 Reply Last reply
                    3
                    • VRoninV VRonin

                      @mzimmers said in suggestions for repeating display views:

                      'QVariant::QVariant(void*)' is private

                      That is a "safeguard" operator to avoid people using pointers to non-QObjects into a QVariant.
                      Basically macAddr is of type unsigned char* the d will still own the data into d.macAddr and will delete it when it goes out of scope. QVariant needs to own the data and know how to delete it. you should be able to hack your way around it by using a smart pointer but it's probably much easier to store it in a Qt container like QByteArray
                      m_model->setData(m_model->index(row, DEV_MACADDR), QByteArray(d.macAddr,sizeof(d.macAddr));

                      P.S.
                      If the compiler complains about signed/unsigned you can use:
                      QByteArray(static_cast<char*>(d.macAddr),sizeof(d.macAddr))

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #20

                      @VRonin ah that explains it (in fact, that's exactly what I was trying to do).

                      I like your idea of changing my char array into QByteArray, but there's a snag - I'm attempting to use the same C struct for my target device as my host app, which restricts me to C++11 types.

                      JonBJ 1 Reply Last reply
                      0
                      • mzimmersM mzimmers

                        @VRonin ah that explains it (in fact, that's exactly what I was trying to do).

                        I like your idea of changing my char array into QByteArray, but there's a snag - I'm attempting to use the same C struct for my target device as my host app, which restricts me to C++11 types.

                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by
                        #21

                        @mzimmers
                        But @VRonin is only asking you to make a copy into a QByteArray for passing to m_model->setData(); you're not changing what is actually in your struct d. So how does that affect your use of the struct in the two apps?

                        1 Reply Last reply
                        3
                        • mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by
                          #22

                          Aargh - I still get confused about using setdata() (and in fact the whole model/view paradigm). Let me play with this, and I'll get back with more confusion in a bit.

                          JonBJ 1 Reply Last reply
                          0
                          • mzimmersM mzimmers

                            Aargh - I still get confused about using setdata() (and in fact the whole model/view paradigm). Let me play with this, and I'll get back with more confusion in a bit.

                            JonBJ Offline
                            JonBJ Offline
                            JonB
                            wrote on last edited by
                            #23

                            @mzimmers
                            Maybe it's me who's misunderstanding you:

                            I'm attempting to use the same C struct for my target device as my host app, which restricts me to C++11 types

                            I am taking that as you have two, separate programs which wish to share a struct in a .h file, so you'd like the actual declaration & content to be accessible from a non-Qt program. Maybe you mean something quite different?!

                            1 Reply Last reply
                            0
                            • mzimmersM Offline
                              mzimmersM Offline
                              mzimmers
                              wrote on last edited by
                              #24

                              Yes, you got it exactly. I'm kind of a fanatic when it comes to not duplicating data structures (not because I'm lazy, but because I'm afraid of updating one of them, but forgetting to update the other, down the road). This philosophy has occasionally caused headaches during initial implementation, but usually repays itself in simplified maintenance.

                              1 Reply Last reply
                              1
                              • mzimmersM Offline
                                mzimmersM Offline
                                mzimmers
                                wrote on last edited by
                                #25

                                OK, I've been grinding through this stuff, and I understand it at least a little better now. My worker receives a message, converts it from XML into a struct, and passes the struct to the object containing the model. My model object then does stuff like this:

                                    mac_itoa(d.macAddr, macStr);
                                    m_model->setData(m_model->index(row, DEV_MACADDR), macStr);
                                

                                So, my summary information in the display widget updates automatically. But, as I mentioned, I have a details area. How do I go about updating the values in this area? I can't do a setModel, as they're just edit boxes, not lists, tables or trees.

                                1 Reply Last reply
                                0
                                • VRoninV Offline
                                  VRoninV Offline
                                  VRonin
                                  wrote on last edited by
                                  #26

                                  You have 2 options:
                                  Do it manually: connect(view->selectionModel(),&QItemSelectionModel::selectionChanged and fill your widgets with data

                                  or use QDataWidgetMapper like explained here: http://doc.qt.io/qt-5/qdatawidgetmapper.html#setCurrentModelIndex

                                  "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

                                  mzimmersM 2 Replies Last reply
                                  2
                                  • VRoninV VRonin

                                    You have 2 options:
                                    Do it manually: connect(view->selectionModel(),&QItemSelectionModel::selectionChanged and fill your widgets with data

                                    or use QDataWidgetMapper like explained here: http://doc.qt.io/qt-5/qdatawidgetmapper.html#setCurrentModelIndex

                                    mzimmersM Offline
                                    mzimmersM Offline
                                    mzimmers
                                    wrote on last edited by mzimmers
                                    #27

                                    @VRonin thanks for the link. I looked at one of the mapper examples (simplewidgetmapper), and I think this is the way to go for me.

                                    In fact, I'm thinking about changing the entire UI. Instead of separate summary/detail areas, I could provide the user with two lists: one for the MAC address, and one for the device name. When the user makes a selection, all the details area (contained in a grid like the simplewidgetmapper example) would update. The user could then edit the details and press a "commit" button.

                                    How does this sound so far?

                                    EDIT:

                                    So, I've begun an in-place conversion from QTableView to using individual widgets (and QDataWidgetMapper). (I've only implemented 2 fields so far.) I think I must be missing a step, because the fields don't initialize on startup the way they did with the table view.

                                        mapper = new QDataWidgetMapper(this);
                                        mapper->setModel(d->getModel());
                                        mapper->addMapping(ui->comboBoxMacAddr, 0);
                                        mapper->addMapping(ui->deviceName, 1);
                                    
                                        ui->gridLayout->addWidget(ui->labelMacAddr, 0, 0, 1, 1);
                                        ui->gridLayout->addWidget(ui->comboBoxMacAddr, 0, 1, 1, 1);
                                        ui->gridLayout->addWidget(ui->labelDevName, 1, 0, 1, 1);
                                        ui->gridLayout->addWidget(ui->deviceName, 1, 1, 1, 1);
                                    

                                    Have I indeed left out a step? It may be noteworthy that, once I select a row in my table (I still have the table active), the update properly affects these fields.

                                    Thanks...

                                    VRoninV 1 Reply Last reply
                                    0
                                    • mzimmersM mzimmers

                                      @VRonin thanks for the link. I looked at one of the mapper examples (simplewidgetmapper), and I think this is the way to go for me.

                                      In fact, I'm thinking about changing the entire UI. Instead of separate summary/detail areas, I could provide the user with two lists: one for the MAC address, and one for the device name. When the user makes a selection, all the details area (contained in a grid like the simplewidgetmapper example) would update. The user could then edit the details and press a "commit" button.

                                      How does this sound so far?

                                      EDIT:

                                      So, I've begun an in-place conversion from QTableView to using individual widgets (and QDataWidgetMapper). (I've only implemented 2 fields so far.) I think I must be missing a step, because the fields don't initialize on startup the way they did with the table view.

                                          mapper = new QDataWidgetMapper(this);
                                          mapper->setModel(d->getModel());
                                          mapper->addMapping(ui->comboBoxMacAddr, 0);
                                          mapper->addMapping(ui->deviceName, 1);
                                      
                                          ui->gridLayout->addWidget(ui->labelMacAddr, 0, 0, 1, 1);
                                          ui->gridLayout->addWidget(ui->comboBoxMacAddr, 0, 1, 1, 1);
                                          ui->gridLayout->addWidget(ui->labelDevName, 1, 0, 1, 1);
                                          ui->gridLayout->addWidget(ui->deviceName, 1, 1, 1, 1);
                                      

                                      Have I indeed left out a step? It may be noteworthy that, once I select a row in my table (I still have the table active), the update properly affects these fields.

                                      Thanks...

                                      VRoninV Offline
                                      VRoninV Offline
                                      VRonin
                                      wrote on last edited by
                                      #28

                                      @mzimmers said in suggestions for repeating display views:

                                      the fields don't initialize on startup

                                      What would the expected behaviour be?

                                      "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
                                      • mzimmersM Offline
                                        mzimmersM Offline
                                        mzimmers
                                        wrote on last edited by
                                        #29

                                        I was expecting that the widgets that I mapped to the model would be automatically updated with the model data. (This is how the view table worked.) Could the problem be that I have multiple views setting on the same model? (I still have my view table active.)

                                        If it looks like I misunderstood the correct use of the mapper, please let me know and I'll make whatever changes necessary.

                                        1 Reply Last reply
                                        0
                                        • VRoninV Offline
                                          VRoninV Offline
                                          VRonin
                                          wrote on last edited by VRonin
                                          #30

                                          You just missed the connection.

                                          @VRonin said in suggestions for repeating display views:

                                          like explained here: http://doc.qt.io/qt-5/qdatawidgetmapper.html#setCurrentModelIndex

                                          connect(view->selectionModel(),&QItemSelectionModel::currentRowChanged,mapper,&QDataWidgetMapper::setCurrentModelIndex);

                                          "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

                                          • Login

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