Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using a custom data type and editor in QStandardItemModel



  • I'm using a custom data type in the items of a QStandardItemModel, but setting item data for different roles seems to affect the data of all roles, and setting the text for the items seems to overwrite the data as well. What's the correct way of doing this?


  • Lifetime Qt Champion

    How do you set the data? Please show some code.



  • @Christian-Ehrlicher
    Setting the data initially:

        std::function<void(tc_assignable_node_t*, QStandardItem*)> traverse;
        traverse = [=, &traverse](tc_assignable_node_t *node, QStandardItem *item) {
            if (node == NULL) {
                return;
            }
            
            if (node->name != NULL) { 
                qDebug() << node->name;
            }
            
            // List for adding the name and editor on the same row
            QList <QStandardItem*> rowItems;
            
            QStandardItem *nameItem = new QStandardItem;
            nameItem->setText(node->name);
            nameItem->setEditable(false);
            rowItems.append(nameItem);
            
            // Don't add editor item for TC_ASSIGNABLE_NONE nodes
            if (node->value_category != TC_ASSIGNABLE_NONE) {
                QStandardItem *editorItem = new QStandardItem;
                QVariant v;
                AssignableData data(node);
                v.setValue(data);
                editorItem->setData(v, Qt::EditRole);
                //editorItem->setText(node->name);
                rowItems.append(editorItem);
            }
            
            item->appendRow(rowItems);
            
            for (uint32_t i = 0; i < node->children_count; i++) {
                traverse(node->children_nodes[i], nameItem);
            }
        };
    

    setModelData() of my delegate:

        AssignableData data = qvariant_cast<AssignableData>(index.model()->data(index));
        QVariant v;
        QStandardItemModel *s_model = static_cast<QStandardItemModel*>(model);
    ...
    IntRangeEditor *ed = static_cast<IntRangeEditor*>(editor);
                        data.setValue(ed->value());
                        v.setValue(data);
                        s_model->setData(index, v, Qt::EditRole);
                        //s_model->itemFromIndex(index)->setText("");
    

    without the last line uncommented, it seems to overwrite the item's entire data and it becomes ineditable


  • Lifetime Qt Champion

    @Lurkki said in Using a custom data type and editor in QStandardItemModel:

    without the last line uncommented,

    You mean '//s_model->itemFromIndex(index)->setText("");' ?
    This will set the Qt::DisplayRole and Qt::EditRole as explained in the documentation



  • @Christian-Ehrlicher s_model->setData(index,"a", Qt::DisplayRole); has the same effect, it overwrites my custom data


  • Lifetime Qt Champion

    Hi
    I might have missed something but i only see you using
    Qt::EditRole
    so where is this custom data stored and in what way
    "becomes ineditable" its still shown but you can type in it or ?



  • @mrjj My mistake, yeah I can edit it but my custom data disappears. The data is stored in the model.


  • Lifetime Qt Champion

    @Lurkki said in Using a custom data type and editor in QStandardItemModel:

    has the same effect, it overwrites my custom data

    I would say it's a bug if it's not - see the documentation...

    Note: The default implementation treats Qt::EditRole and Qt::DisplayRole as referring to the same data.



  • @Christian-Ehrlicher How should I go about subclassing QStandardItem and reimplementing setData then? I can't seem to find much information about it.


  • Lifetime Qt Champion

    @Lurkki

    Hi
    Can you please make a small example showing this ?,

    I have a bad feeling its just incorrect use / expectations and
    not an actual bug.

    Qt::EditRole and Qt::DisplayRole is the same so that is expected.

    try to use Qt::UserRole for your custom data end see.

    To use custom data, you can use

    setData(index,"a", Qt::UserRole );
    setData(index,"a", Qt::UserRole +1);
    setData(index,"a", Qt::UserRole +2);



  • @mrjj Thanks, that works for my use case

    Setting the data:

            if (node->value_category != TC_ASSIGNABLE_NONE) {
                QStandardItem *editorItem = new QStandardItem;
                QVariant v;
                AssignableData data(node);
                v.setValue(data);
                editorItem->setData(v, Qt::UserRole);
                //editorItem->setText(node->name);
                rowItems.append(editorItem);
            }
    
    

    Setting editor data in the delegate:

    void AssignableEditorDelegate::setEditorData(QWidget* editor, const QModelIndex &index) const {
        AssignableData data = qvariant_cast<AssignableData>(index.model()->data(index, Qt::UserRole));
        
        switch (data.m_valueCategory) {
            case TC_ASSIGNABLE_RANGE:
                switch (data.m_rangeInfo.range_data_type) {
                    case TC_ASSIGNABLE_RANGE_INT: {
                        IntRangeEditor *ed = static_cast<IntRangeEditor*>(editor);
                        ed->setValue(data.value().toInt());
                        break;
                    }
                    default:
                        break;
                }
            default:
                break;
        }
    }
    

    Setting model data:

    void AssignableEditorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
        AssignableData data = qvariant_cast<AssignableData>(index.model()->data(index, Qt::UserRole));
        QVariant v;
        QStandardItemModel *s_model = static_cast<QStandardItemModel*>(model);
        
        switch (data.m_valueCategory) {
            ...
            case TC_ASSIGNABLE_RANGE:
                switch (data.m_rangeInfo.range_data_type) {
                    case TC_ASSIGNABLE_RANGE_INT: {
                        IntRangeEditor *ed = static_cast<IntRangeEditor*>(editor);
                        data.setValue(ed->value());
                        v.setValue(data);
                        s_model->setData(index, v, Qt::UserRole);
                        s_model->setData(index, ed->value(), Qt::DisplayRole);
                        break;
                        }
                    default:
                        break;
                }
            default:
                break;
        }
    }
    

    I also had to do setAutoFillBackground(true); in my editor widget to make the display text not overlap with the editor.


Log in to reply