PDA

View Full Version : Editable QComboBox with QItemDelegate



Jmgr
8th July 2008, 20:13
Hi all :)

I am trying to customize my QTreeView to get an editable QComboBox into a column.
There are some example on the Net, but I haven't seen any with an editable QComboBox, and mine does not work properly...

Let me explain : if I click into the cell and select an item from the list it works : the selection is saved. But if I enter free text and change the focus, then the text is lost, and my DisplayRole role contains nothing. But if I enter some text again, then it will be saved...

I searched without success some hours but didn't find any clue, so I'm posting here, maybe someone has a good idea about this...

Now, some code :

QWidget *ActionDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QComboBox *comboBox = new QComboBox(parent);
comboBox->setEditable(true);
comboBox->setInsertPolicy(QComboBox::NoInsert);
comboBox->addItems(index.model()->data(index, CustomRoles::ValueRole).toStringList());

connect(comboBox, SIGNAL(activated(int)), this, SLOT(emitCommitData()));
connect(comboBox->lineEdit(), SIGNAL(editingFinished()), this, SLOT(emitCommitData()));

QString currentText = index.model()->data(index, Qt::DisplayRole).toString();
int selectedItem = comboBox->findText(currentText);
if(selectedItem == -1)
comboBox->setEditText(index.model()->data(index, Qt::DisplayRole).toString());
else
comboBox->setCurrentIndex(selectedItem);

return comboBox;
}


void ActionDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);

comboBox->clear();
comboBox->addItems(index.model()->data(index, CustomRoles::ValueRole).toStringList());

QString currentText = index.model()->data(index, Qt::DisplayRole).toString();
int selectedItem = comboBox->findText(currentText);
if(selectedItem == -1)
comboBox->setEditText(index.model()->data(index, Qt::DisplayRole).toString());
else
comboBox->setCurrentIndex(selectedItem);
}


void ActionDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox* comboBox = qobject_cast<QComboBox*>(editor);

QStringList value;
for(int i=0;i<comboBox->count();++i)
value.append(comboBox->itemText(i));

int selectedItem = comboBox->findText(comboBox->currentText());
if(selectedItem == -1)
{
model->setData(index, -1, CustomRoles::SelectedItemRole);
model->setData(index, comboBox->currentText(), Qt::DisplayRole);
}
else
{
model->setData(index, selectedItem, CustomRoles::SelectedItemRole);
model->setData(index, comboBox->itemText(selectedItem), Qt::DisplayRole);
}

model->setData(index, value, CustomRoles::ValueRole);
}


void ActionDelegate::emitCommitData()
{
emit commitData(qobject_cast<QWidget *>(sender()));
}


CustomRoles::SelectedItemRole represents the currently selected item, or -1 if it's free text
CustomRoles::ValueRole represents all the items of the combo box

wysota
8th July 2008, 20:25
You have to play a bit with event filters, so that for example when you focus out of the editor or when you press the enter key, the contents is saved into the model.

Jmgr
8th July 2008, 20:36
But why does
connect(comboBox->lineEdit(), SIGNAL(editingFinished()), this, SLOT(emitCommitData())); not save the data from the QLineEdit ?

I also noticed that setEditorData is called twice after an edition...

wysota
8th July 2008, 21:08
What is emitCommitData()? Is it a slot? The line edit is not the editor widget, but part of it, so your emitCommitData() doesn't make much sense.

Jmgr
8th July 2008, 21:10
Well, as I posted on the first post it's a slot which calls

emit commitData(qobject_cast<QWidget *>(sender()));

EDIT : Yes, it's a slot :)

wysota
8th July 2008, 21:11
Yeah, but it doesn't make much sense, as the line edit is not the editor.

Jmgr
8th July 2008, 21:16
Huh, that is true :)

Ok, I will look how to use the event filter.

Jmgr
8th July 2008, 21:32
It is probably a noobish question, but how do I installEventFilter within createEditor, because since createEditor is const, calling myLineEdit->installEventFilter(this) produces an error...

I doesn't know why it is so complicated to put a simple QComboBox into a cell :confused:

Anyway, I tested with having persistent editors : it seems to work, but the method of showing an editor when needed is much better...

wysota
8th July 2008, 21:54
You have to cheat using const_cast(). You can take a look at the implementation of QItemDelegate and the factory class it uses to see how it is internally implemented. With all the event filters and stuff.

Jmgr
8th July 2008, 21:57
I will look at it, thanks :)

faraslacks
10th December 2008, 09:11
Excuse me, may be it's easy, but what is CustomRoles?

wysota
10th December 2008, 09:21
Excuse me, may be it's easy, but what is CustomRoles?

Custom item roles in ItemViews