Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. binding QStandardItemModel from C++ with QML
QtWS25 Last Chance

binding QStandardItemModel from C++ with QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlrolesqtquicklistviewmodel binding
3 Posts 2 Posters 4.7k 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.
  • F Offline
    F Offline
    fantaz
    wrote on 28 Feb 2018, 07:41 last edited by
    #1

    Hi all,

    I was wondering why can't I show check boxes in qml's listview when I use QStandardItemModel. Let me give you an example:
    c++ side

    ...
    QStandardItemModel model;
     model.setColumnCount(1);
     const int N = 25;
     model.setRowCount(N);
    for (int r = 0; r < N; ++r)
    {
        QStandardItem* item = new QStandardItem(QString("item %1").arg(r));
        item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
        if (r % 2 == 0)
            item->setData(Qt::Unchecked, Qt::CheckStateRole);
        else
            item->setData(Qt::Checked, Qt::CheckStateRole
    
        model.setItem(r, 0, item);
     }
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("myModel", &model);
    ...
    

    while on the qml's side:

    ListView {
        ...
        model: myModel
        delegate: RowLayout {
            width:  parent.width
                CheckBox {
                    checked: /*what goes in here?*/
                }
                Text {
                    width: 100; height: 32
                    text: model.display
                    Layout.fillWidth: true
                }
        }
    }
    

    I'm perfectly aware that checkboxes can be set via custom roles, that is:

    QStandardItemModel model;
    model.setColumnCount(1);
    const int N = 25;
    model.setRowCount(N);
    // new roles
    enum
    {
        checkedRole = Qt::UserRole,
        nameRole
    };
    QHash<int, QByteArray> names;
    names[checkedRole] = "checked";
    names[nameRole] = "name";
    model.setItemRoleNames(names);
    
    for (int r = 0; r < N; ++r)
    {
        QStandardItem* item = new QStandardItem(QString("item %1").arg(r));
        item->setData(QString("item %1").arg(r), nameRole);
    
        // item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); don't need that anymore
        if (r % 2 == 0)
            item->setData(Qt::Unchecked, checkedRole); // instead of Qt::CheckStateRole
        else
            item->setData(Qt::Checked, checkedRole); // instead of Qt::CheckStateRole
    
        model.setItem(r, 0, item);
    }
    ...
    

    and on the qml's side, i can write this:

    ListView {
        ...
        model: myModel
        delegate: RowLayout {
            width:  parent.width
            CheckBox {
                checked: model.checked
            }
            Text {
                width: 100; height: 32
                text: model.name
                Layout.fillWidth: true
            }
        }
    }
    

    where the name is my custom role instead of Qt::DisplayRole (qml property is display, if I'm not mistaken), and since I can't find qml property for Qt::CheckStateRole, I need to put my custom role, checked.

    Finally, the questions.
    Is it safe to conclude that the Qt::DisplayRole is exposed to QML via display property, while the Qt::CheckStateRole isn't? Why is it? Is there any rational explanation behind this behaviour?
    On the downside, I can't use the same QStandardItemModel code for both QWidgets and QML, since I need to create custom roles for the QML side. Which means, I need to have two different models, one for QWidgets, and one for QML. Yes, I'm aware that I really don't need two instances, but nevertheless, this seems like waste of time and resources. And what's more, the big chunk of the code is practically the same.
    Ideally, I'd like to be able to write model code (now it's the QStandardItemModel, developed on the c++ side, nothing fancy), and use it in the QML, or in QWidgets.
    Maybe I'm missing something, but I couldn't find anything in the docs about that.

    1 Reply Last reply
    0
    • G Offline
      G Offline
      GrecKo
      Qt Champions 2018
      wrote on 28 Feb 2018, 09:34 last edited by
      #2

      QML Views expose data do the delegate based on the role names of the model.

      The default role names for a QStandardItemModel are:

      {
          Qt::DisplayRole: "display",
          Qt::DecorationRole: "decoration",
          Qt::EditRole: "edit",
          Qt::ToolTipRole: "toolTip", 
          Qt::StatusTipRole, "statusTip"
          Qt::WhatsThisRole, "whatsThis"
      }
      

      As you can see there's no mention of Qt::CheckStateRole.
      What you could do is just add it like that :

      QHash<int, QByteArray> roleNames = model.roleNames();
      roleNames[Qt::CheckStateRole] = "checkState";
      model.setRoleNames(roleNames);
      

      Then you access it in your QML delegate like this: checked: model.checkState, and continue using it normally in QWidgets since you still use the same roles.

      1 Reply Last reply
      2
      • F Offline
        F Offline
        fantaz
        wrote on 28 Feb 2018, 12:57 last edited by fantaz
        #3

        Thanks for the feedback.
        I have a follow up question though.

        • Where are QML's default role names documented? I couldn't see the list. It would save me a lot of time. EDIT Here they are: link.
        1 Reply Last reply
        0

        3/3

        28 Feb 2018, 12:57

        • Login

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