QAbstractItemDelegate and editing
-
I wrote a class which based on QItemDelegate. It presents a combo box with some data. When I applying it on QTreeView or QTableView item i can change the value by double clicking on it and choosing the new value, than I must hit Enter key or click on any other item to change the value in item. If I close window, without hitting Enter key, or without clicking on other item, the value in item will not change. Is there any solution to solve this problem ? Here is the code of my delegate:
@class ComboBoxDelegate : public AItemDelegate { Q_OBJECT
//--------------------------------------------------------------------------------------------------
public: ComboBoxDelegate(QObject * parent = 0) : AItemDelegate(parent) {
}
public: ComboBoxDelegate(QObject * parent, DescriptionPtr description) : AItemDelegate(parent, description) {
}
//--------------------------------------------------------------------------------------------------
public: virtual ~ComboBoxDelegate() {
}
//--------------------------------------------------------------------------------------------------
public: virtual QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & /option/, const QModelIndex & /index/) const {
if (m_description == NULL)
return NULL;QComboBox * cb = new QComboBox(parent); const Choices & choices = m_description->getChoices(); int n = choices.getCount(); for (int i = 0; i < n; i++) { const Choice & item = choices.getItem(i); cb->addItem(item.getDisplayName(), item.getValue()); } return cb; }
//--------------------------------------------------------------------------------------------------
public: void setEditorData(QWidget * editor, const QModelIndex & index) const {
QComboBox * cb = static_cast<QComboBox *>(editor);
// QVariant value = index.data(Qt::EditRole);
QString s = index.data(Qt::DisplayRole).toString();
//int i = cb->findData(value);
int i = cb->findText(s);
// if(i == -1)
// cb->setCurrentIndex(0);
// else
cb->setCurrentIndex(i);}
//--------------------------------------------------------------------------------------------------
public: void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const {
QComboBox * cb = static_cast<QComboBox *>(editor);
int ndx = cb->currentIndex();
if (ndx >= 0) {
QVariant value = cb->itemData(ndx);
model->setData(index, value, Qt::EditRole);
}
}
//--------------------------------------------------------------------------------------------------
};@AItemDelegate:
@class AItemDelegate : public QItemDelegate {
//--------------------------------------------------------------------------------------------------
protected: DescriptionPtr m_description;
//--------------------------------------------------------------------------------------------------
public: AItemDelegate(QObject * parent) : QItemDelegate(parent) {
m_description = NULL;
}
//--------------------------------------------------------------------------------------------------
public: AItemDelegate(QObject * parent, DescriptionPtr description) : QItemDelegate(parent) {
m_description = description;
}
//--------------------------------------------------------------------------------------------------
public: virtual ~AItemDelegate() {
}
//--------------------------------------------------------------------------------------------------
public: DescriptionPtr getDescription() {
return m_description;
}
//--------------------------------------------------------------------------------------------------
public: void setDescription(DescriptionPtr description) {
m_description = description;
}
//--------------------------------------------------------------------------------------------------
public: virtual void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & /index/) const {
editor->setGeometry(option.rect);
}
//--------------------------------------------------------------------------------------------------
};@ -
Connect an appropriate signal of the widget containing your item view to a slot endEdit() in you item view subclass:
@
void MyItemViewSubclass::endEdit()
{
QModelIndex index = currentIndex();
currentChanged( index, index );
}
@This simulates clicking on an item and thus ends the editing process of the combobox.
You should call this slot too, if you are going to commit the data via some save button or the like. It works well and we use it all the time.
-
This delegate is using by more then one item View sub class. I can't even imagine how many times it will be used in project in feature and by how many people, because it not so small. So I need some local solution in my delegate or in AItemDelegate class. Is there any other ideas ?
-
There is one more simple solution that I find. In my delegate I need to add connect @ public: void setEditorData(QWidget * editor, const QModelIndex & index) const {
QComboBox * cb = static_cast<QComboBox *>(editor);
QString s = index.data(Qt::DisplayRole).toString();
int i = cb->findText(s);
cb->setCurrentIndex(i);connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); }@
And add a slot onCurrentIndexChanged : @public slots: void onCurrentIndexChanged(int index) {
QComboBox * cb = static_cast<QComboBox *>(sender());
emit commitData(cb);
emit closeEditor(cb);
}@
So it solved locally and works pretty well. -
Just want to thanks for this trick, I modified it a little bit so it works with every QWidget editor
1- In createEditor, connect a custom signal in your QWidget Editor to a custom slot in the Delegate
@QWidget *IntervalDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const{
else if (index.column() == 3 ) {
CadenceEditor *editor = new CadenceEditor(parent);
connect (editor, SIGNAL(endEdit()), this, SLOT(closeWidgetEditor()) );
return editor;
}@2- close the editor in the custom delegate slot :
@void IntervalDelegate::closeWidgetEditor() {qDebug() << "CLOSE EDITOR NOW!"; QWidget *editor = qobject_cast<QWidget*>(sender()); emit commitData(editor); emit closeEditor(editor);
}@
-
I can now close the editor with a custom "OK" button, show in this image:
https://www.dropbox.com/s/95agb2c38f9p354/customEditors.pngProblem is when I click the OK button, the click get propaged under it and it open another editor, how can I stop the click? I already have setAttribute(Qt::WA_NoMousePropagation); on my custom QWidget editor..
Thanks