In my project, I have a QTreeView
displaying items from a QStandardItemModel
. Each item has data stored in several UserRoles.
QStandardItem* item = new QStandardItem();
item->setIcon(iconByte);
item->setData(3, Qt::UserRole+1);
item->setData(name, Qt::UserRole+2);
item->setData(data, Qt::UserRole+3);
... and so on
When the user double clicks on an item, a dialog with two line edits displays allowing the user to edit parts of the UserRole data. When editing ceases, the edits run through some logic and a display name is generated based on the new UserRole data.
However, this gets very tedious very quickly. With dialogs constantly popping up and whatnot, it's a slow and ugly solution.
I now would like to remove the dialog completely and show the line edit widgets WITHIN the item itself. By default, double clicking an item to edit it only shows one line edit widget to change the DISPLAY role. However I want two line edits to change the two USER roles. And then the normal logic continues.
How would I go about modifying the edit item portion of a QTreeView
?
Thanks for your time!
I would use a custom subclass of QStyledItemDelegate to solve this. Somewhere near your QTreeView
you could have a QComboBox
switching between the user roles; your custom delegate would somehow be informed which user role is currently selected and would intercept the method updating the data in the model to set the proper role.
An example implementation (not tested, may contain typos and errors):
class RoleSwitchingDelegate: public QStyledItemDelegate
{
public:
explicit RoleSwitchingDelegate(QComboBox * roleSwitcher, QObject * parent = 0);
virtual void setEditorData(QWidget * editor, const QModelIndex & index) const Q_DECL_OVERRIDE;
virtual void setModelData(QWidget * editor, QAbstractItemModel * model,
const QModelIndex & index) const Q_DECL_OVERRIDE;
private:
QComboBox * m_roleSwitcher;
};
RoleSwitchingDelegate::RoleSwitchingDelegate(QComboBox * roleSwitcher, QObject * parent) :
QItemDelegate(parent),
m_roleSwitcher(roleSwitcher)
{}
void RoleSwitchingDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
{
// Assuming the model stores strings for both roles so that the editor is QLineEdit
QLineEdit * lineEdit = qobject_cast<QLineEdit*>(editor);
if (!lineEdit) {
// Whoops, looks like the assumption is wrong, fallback to the default implementation
QStyledItemDelegate::setEditorData(editor, index);
return;
}
int role = m_roleSwitcher->currentIndex();
QString data = index.model()->data(index, role).toString();
lineEdit->setText(data);
}
void RoleSwitchingDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
// Again, assuming the model stores strings for both roles so that the editor is QLineEdit
QLineEdit * lineEdit = qobject_cast<QLineEdit*>(editor);
if (!lineEdit) {
// Whoops, looks like the assumption is wrong, fallback to the default implementation
QStyledItemDelegate::setModelData(editor, model, index);
return;
}
int role = m_roleSwitcher->currentIndex();
QString data = lineEdit->text();
model->setData(index, data, role);
}
Once you have the delegate, you just need to set it to the view:
view->setItemDelegate(new RoleSwitchingDelegate(roleSwitchingComboBox, view));