How to update two items in an index with use of QStyledItemDelegate and QAbstractItemModel ?
-
I customized a QStyledItemDelegate and QAbstractItemModel for a QTreeView. I have a qwidget that contain a qcolor box and a qlineedit for a given row (index), I'm trying to save color and lineedit text to variables. However I can not update the text into variable... (see code below)
I think the problem is that when the text item is edited, the first "model->setData" for color variable in QStyledItemDelegate "setModelData" function is always executed first, which triggers the "data" function, which returns the original text and QStyledItemDelegate "setEditorData" will overwrite modified text.
I'm thinking I need to tell what is changed in QStyledItemDelegate "setModelData" function so the right setdata can be sent? How can I do that? Or what is the right way to do this?
in QStyledItemDelegate .cpp:
...
void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { MyWidget *widget = static_cast<MyWidget *>(editor); widget->blockSignals(true); widget->setMyText(index.data(Qt::EditRole).toString()); widget->setMyColor(index.data(Qt::UserRole).value<QColor>()); widget->blockSignals(false); } void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { model->setData(index, QVariant(static_cast<MyWidget*>(editor)->getMyColor()), Qt::UserRole); model->setData(index, QVariant(static_cast<MyWidget*>(editor)->getMyText()), Qt::EditRole); }
in QAbstractItemModel .cpp:
QVariant MyModel::data(const QModelIndex &index, int role) const { if (role == Qt::EditRole){ return myTextVariable; } if (role == Qt::UserRole){ return myColorVariable; } return QVariant(); } bool myModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (role == Qt::UserRole){ myColorVariable=value.value<QColor>(); }else if (role == Qt::EditRole){ myTextVariable=value.toString(); } } Q_EMIT dataChanged(index, index); return true; }
-
@Pauly said in How to update two items in an index with use of QStyledItemDelegate and QAbstractItemModel ?:
setEditorData
Here you're already using blockSignals() - you can try this for model too. Or remember in a member that you're currently setting the data.
-
I do not recall why I block the signal... maybe I just copied this from somewhere...
I did not think the createEditor matters to the question so I skip that code. But here is it:
QWidget *MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { MyWidget *editor = new MyWidget(index, parent); editor->setEditorText("text"); editor->setColor(QColor(Qt::black)); return editor; } return new QWidget(parent); }
In reality it is more than one row... I skipped the index here and let's just consider it as one row, it doesn't change the situation, does it? Thank you.
-
Hi,
Since you want to modify two elements in one shot, why not pass aQPair
to the user role with the two values and let the model put that in the correct places ?As @VRonin suggests below: setItemData is the right tool.
[edit: Fixed suggestions SGaist]
-
Great idea! Along with the same thought, I use QList (just in case if more than two variables to be updated) and it works. This is the new code. Thanks!
in QStyledItemDelegate .cpp:
void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { MyWidget *widget = static_cast<MyWidget *>(editor); widget->blockSignals(true); widget->setColor(index.data(Qt::EditRole).toList().at(0).value<QColor>()); widget->setText(index.data(Qt::EditRole).toList().at(1).toString()); widget->blockSignals(false); } void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { listData<<QVariant(static_cast<MyWidget*>(editor)->getColor())<<QVariant(static_cast<MyWidget*>(editor)->getText()); model->setData(index, QVariant(listData), Qt::EditRole); }
in QAbstractItemModel .cpp:
QVariant MyModel::data(const QModelIndex &index, int role) const { QList<QVariant> listData; listData<<QVariant(myColor)<<QVariant(myText); return listData; } bool myModel::setData(const QModelIndex& index, const QVariant& value, int role) { myColor=value.toList().at(0).value<QColor>(); myText=value.toList().at(1).toString(); } Q_EMIT dataChanged(index, index); return true; }
-
@SGaist said in How to update two items in an index with use of QStyledItemDelegate and QAbstractItemModel ?:
Since you want to modify two elements in one shot, why not pass a QPair
Are you suggesting a reinvention of https://doc.qt.io/Qt-5/qabstractitemmodel.html#setItemData ?
-
I knew I was forgetting something !