[Qt-interest] Custom model and delegate for QComboBox

Wolfgang Pausch wolfgang.pausch at uibk.ac.at
Mon Nov 2 11:52:58 CET 2009


Hello,

> > Thanks for the answer, however that sounds a bit odd to me: My
> > QDataWidgetMapper has some model.  It has fields A, B, C.  Assume field A
> > is mapped to my QComboBox.  Then, the QComboBox itself offers items A1, A2,
> > A3, using a QComboBox-internal model.
> >
> > Now, if some of those items is chosen, the model of the QDataWidgetMapper
> > should be updated with exactly this item.
> >
> > If I would set this delegate in the QDataWidgetMapper, it would need to
> > know all choices A1, A2, A3, as the QComboBox must be able to display them
> > all in a correct way.  And as I have more QComboBoxes than just one in this
> > mapper, it would need to know about all choices of all QComboBoxes around
> > there, plus the data of other widgets used in the mapping.
> 
> The mapper has to use the combobox to translate the values to whatever it 
> needs.  check the implementation of QSqlRelationalDelegate (or something).  
> This implements foreign key relations on tables in model/views

Ok, I´m trying to use them for figuring out how things should work.  However one question:  What is the role of the createEditor method of some delegate, if one uses a QDataWidgetMapper?  I mean, the usual pattern when using a QDataWidgetMapper is that I create the widget and then call addMapping for binding the widget to the model.  But this means that I create the widget, and not the delegate, doesn´t it?  Or is the idea that I call createEditor manually?

Thanks,

Wolfgang

> > > > sorry for asking again.  I´ve spent several hours trying to figure out
> > > > where my mistake is, but I didn´t make it work yet :-(
> > > >
> > > > What do I have?
> > > > - A QComboBox
> > > > - A custom model for the QComboBox
> > > > - A custom delegate implementing setEditorData for the QComboBox
> > > > - Optionally a QDataWidgetMapper which maps the QComboBox and some
> > > > other widgets.  (the problem doesn´t disappear if I remove the
> > > > QComboBox from the mapper).
> > > >
> > > > Am I right that those objects should interact in the following way:
> > > > - The QComboBox has some items
> > > > - Each of them corresponds to one QModelIndex in my QComboBox-internal
> > > > custom model - The setEditorData method in my QComboBox-inter-1
> nal custom
> > > > delegate should translate the values from the custom model into the
> > > > values displayed by the QComboBox - The mapping enforced by the
> > > > QDataWidgetMapper at each time only knows about the current item,
> > > > mapping it to some QModelIndex entry of the model of the widget
> > > > containing my QComboBox
> > > >
> > > > Problem:
> > > > - I see the entries of my custom model 1:1 in the QComboBox, i.e. I see
> > > > 1, 2, 3. - My custom delegates setEditorData would translate 1,2,3 into
> > > > some human readable strings FOO, BAR, etc. - But it is not called, and
> > > > I have no idea why not.
> > > >
> > > > What I could debug:
> > > > - After setting the delegate, it actually is being set.
> > > > - The only setEditorData methods in any *Delegate classes are called
> > > > from my QDataWidgetMapper during toFirst(). - However, my problem
> > > > doesn´t disappear if I remove my QComboBox from the mapper.
> > > >
> > > > Does anyone have some hint for me?
> > > >
> > > > Thanks,
> > > >
> > > > Wolfgang
> > > >
> > > > On Fri, 23 Oct 2009 15:03:50 +0200
> > > >
> > > > Wolfgang Pausch <wolfgang.pausch at uibk.ac.at> wrote:
> > > > > Hello,
> > > > >
> > > > > I am trying to implement a custom model and a custom delegate for a
> > > > > QComboBox.  What I want to do is:
> > > > >
> > > > > - the model contains some codes loaded from a datamodel
> > > > > - the delegate transforms them into human-readable strings
> > > > >
> > > > > However, my implementation so far simply doesn´t call setModelData.
> > > > > It seems to ignore the delegate. Can anyone, based on the code
> > > > > snippets below, give me a hint regarding what is my mistake?
> > > > > Especially: I don´t want to edit anything in my ComboBox, just choose
> > > > > one of several choices. Am I correct that I only need to overwrite
> > > > > setEditorData?
> > > > >
> > > > > Do I have to do something special in order to use this delegate?  Do
> > > > > I have to take care about the view?  Is my assumption correct that
> > > > > once the model is set, it should call the delegate itself, so I don´t
> > > > > have to call some dataChanged signals etc. explicitely in the code
> > > > > below (e.g. in addChoice)?
> > > > >
> > > > > I once became problems because I missed a const keyword when
> > > > > overwriting some model method, but as far as I see, the signature of
> > > > > ComboBoxDelegate::setEditorData is correct.  Do you see any problem
> > > > > here? (if this method would be called anything would be fine).
> > > > >
> > > > > Thanks,
> > > > >
> > > > > Wolfgang
> > > > >
> > > > > Where I set things up:
> > > > >
> > > > > QComboBox*
> > > > > MitgliedAttributeWidgetFactory::constructMitgliedsartComboBox(Databas
> > > > >eCon text *databaseContext) { CodeManager *codeManager =
> > > > > databaseContext->getCodeManager();
> > > > >
> > > > > 	ComboBoxModel *model = new ComboBoxModel();
> > > > > 	model->addChoice(codeManager, "LANDESVERBAND_ORDENTLICH");
> > > > > 	model->addChoice(codeManager, "LANDESVERBAND_AUSSERORDENTLICH");
> > > > > 	model->addChoice(codeManager, "LANDESVERBAND_VEREINSMITGLIED");
> > > > >
> > > > > 	ComboBoxDelegate *delegate = new ComboBoxDelegate(databaseContext);
> > > > >
> > > > > 	QComboBox* mitgliedsartComboBox = new QComboBox();
> > > > > 	mitgliedsartComboBox->setItemDelegate(delegate);
> > > > > 	mitgliedsartComboBox->setModel(model);
> > > > > 	return mitgliedsartComboBox;
> > > > > }
> > > > >
> > > > > The model:
> > > > >
> > > > > class ComboBoxModel : public QAbstractListModel {
> > > > >
> > > > > public:
> > > > > 	ComboBoxModel();
> > > > > 	~ComboBoxModel();
> > > > >
> > > > > 	void addChoice(CodeManager *codeManager, QString name);
> > > > >
> > > > >     int rowCount(const QModelIndex &parent) const;
> > > > >     QVariant data(const QModelIndex &index, int role) const;
> > > > >
> > > > > private:
> > > > > 	std::vector<CodeValue*> choices;
> > > > >
> > > > > };
> > > > >
> > > > > ComboBoxModel::ComboBoxModel() {
> > > > > 	choices = std::vector<CodeValue*>();
> > > > > }
> > > > >
> > > > > ComboBoxModel::~ComboBoxModel() {
> > > > > 	for (std::vector<CodeValue*>::const_iterator it = choices.begin();
> > > > > it != choices.end(); it++) { CodeValue* choice = *it;
> > > > > 		delete choice;
> > > > > 	}
> > > > > }
> > > > >
> > > > > void ComboBoxModel::addChoice(CodeManager *codeManager, QString name)
> > > > > { CodeValue* choice = codeManager->getCodeValueByName(name);
> > > > > 	choices.push_back(choice);
> > > > > }
> > > > >
> > > > > int ComboBoxModel::rowCount(const QModelIndex &parent) const {
> > > > > 	return choices.size();
> > > > > }
> > > > >
> > > > > QVariant ComboBoxModel::data(const QModelIndex &index, int role)
> > > > > const { if (!index.isValid()) {
> > > > >         return QVariant();
> > > > >     }
> > > > >
> > > > >     if (role == Qt::TextAlignmentRole) {
> > > > >         return int(Qt::AlignRight | Qt::AlignVCenter);
> > > > >     } else if (role == Qt::DisplayRole || role == Qt::EditRole) {
> > > > >         int row = index.row();
> > > > > 		CodeValue *choice = choices[row];
> > > > > 		int choiceId = choice->getId();
> > > > > 		return QVariant(choiceId);
> > > > >     } else {
> > > > >         return QVariant();
> > > > >     }
> > > > > }
> > > > >
> > > > >
> > > > > The delegate:
> > > > >
> > > > > class ComboBoxDelegate : public QItemDelegate {
> > > > > 	Q_OBJECT
> > > > >
> > > > > public:
> > > > > 	ComboBoxDelegate(DatabaseContext *ndatabaseContext);
> > > > > 	void setEditorData(QWidget *editor, const QModelIndex &index )
> > > > > const; void setModelData(QWidget *editor, QAbstractItemModel *model,
> > > > > const QModelIndex &index ) const;
> > > > >
> > > > > private:
> > > > > 	DatabaseContext *databaseContext;
> > > > > };
> > > > >
> > > > > ComboBoxDelegate::ComboBoxDelegate(DatabaseContext *ndatabaseContext)
> > > > > { databaseContext = ndatabaseContext;
> > > > > }
> > > > >
> > > > > void ComboBoxDelegate::setEditorData(QWidget *editor, const
> > > > > QModelIndex &index ) const { std::cout << "called setEditorData" <<
> > > > > std::endl;
> > > > >
> > > > > 	QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
> > > > >
> > > > > 	const QAbstractItemModel *model = index.model();
> > > > > 	QVariant data = model->data(index, Qt::DisplayRole);
> > > > > 	bool transformOk;
> > > > > 	int codeBehindCombobox = data.toInt(&transformOk);
> > > > >
> > > > > 	if (comboBox == NULL) {
> > > > > 		std::cerr << "ComboBoxDelegate::setEditorData says: comboBox is
> > > > > NULL. Maybe this is a bug." << std::endl; } else if (!transformOk) {
> > > > > std::cerr << "ComboBoxDelegate::setEditorData says: Value behind
> > > > > comboBox is not an int.  Maybe this is a bug." << std::endl; } else {
> > > > > CodeManager *codeManager = databaseContext->getCodeManager();
> > > > > CodeValue *codeValue =
> > > > > codeManager->getCodeValueById(codeBehindCombobox);
> > > > >
> > > > > 		int row = index.row();
> > > > > 		int column = index.column();
> > > > > 		std::cout << "ComboBoxDelegate::setEditorData called for row " <<
> > > > > row << " and column " << column << std::endl;
> > > > >
> > > > > 		comboBox->setItemText(row, codeValue->getKurzText());
> > > > > 		delete codeValue;
> > > > > 	}
> > > > > }
> > > > >
> > > > >




More information about the Qt-interest-old mailing list