tags:

views:

1274

answers:

1

I followed the model/view/controller paradigm. I am pretty sure that the model and view are right, but I think I'm doing some things wrong in my delegate. Everything "works", except the first click to a control just "lights up the control" and the second one interacts with it. Is this how delegates are usually implemented? My implementation requires a lot of construction and destruction (hidden by scoped_ptr) so any tips on that are also helpful.

QWidget *ParmDelegate::createWidget(const QModelIndex &index) const {
    if (!index.isValid())
     return NULL;
    const Parm *p = static_cast<const Parm*>(index.internalPointer());
    QWidget *w = p->createControl();
    w->setAutoFillBackground(true);
    w->setBackgroundRole(QPalette::Base);  // white background instead of grey
    return w;
}

QWidget*
ParmDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    QWidget *retval = createWidget(index);
    if (dynamic_cast<QComboBox*>(retval))
     connect(retval, SIGNAL(activated(int)), this, SLOT(commitAndCloseEditor()));
    else if (dynamic_cast<QSlider*>(retval))
     connect(retval, SIGNAL(sliderReleased()), this, SLOT(commitAndCloseEditor()));
    else if (dynamic_cast<QAbstractButton*>(retval))
     connect(retval, SIGNAL(clicked()), this, SLOT(commitAndCloseEditor()));
    else
     connect(retval, SIGNAL(editingFinished()), this, SLOT(commitAndCloseEditor()));
    retval->setFocusPolicy(Qt::StrongFocus);
    retval->setParent(parent);
    return retval;
}

void
ParmDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
    const Parm *p = static_cast<const Parm*>(index.internalPointer());
    p->setEditorData(editor);
}

void
ParmDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
    ParmControl::Base* base = dynamic_cast<ParmControl::Base*>(editor);
    model->setData(index, base->toQVariant());
}

void
ParmDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    editor->setGeometry(option.rect);
}

void
ParmDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    scoped_ptr<QWidget> w(createWidget(index));
    if (!w)
     return;
    const Parm *p = static_cast<const Parm*>(index.internalPointer());
    setEditorData(w.get(), index);
    w->setGeometry(option.rect);
    w->render(painter, option.rect.topLeft());
}

QSize
ParmDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
    scoped_ptr<QWidget> w(createWidget(index));
    if (!w)
     return QSize(0,0);
    return w->sizeHint();
}

void
ParmDelegate::commitAndCloseEditor() {
    QWidget *editor = static_cast<QWidget *>(sender());
    ParmControl::Base* base = dynamic_cast<ParmControl::Base*>(editor);
    emit commitData(editor);
    emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
}
+3  A: 

If you are interested in changing the conditions that your custom editor is shown, use QAbstractItemView::setEditTriggers(). Although your delegate is responsible for passing information to and from the custom editor, the view determines when the editor is launched.

Documentation reference: http://doc.trolltech.com/4.5/qabstractitemview.html#editTriggers-prop.

swongu
I tried that, but there are no edit triggers for the first click. There's only SelectedClicked and DoubleClicked, so I thought I would force the editing on the first click using editorEvent. Wrong way?
Neil G
Try CurrentChanged. That will begin editing when the cell selection changes.
swongu
Wow, that works even though selection is disabled. Awesome, that gets rid of the editorEvent method. I'll remove it in the above code too.
Neil G
Great to hear that it's working out for you. Does my answer also clear up the role of delegates?
swongu
I don't think my question is totally answered. I'd like the first click to go to the created control, but as the code is, the first click causes editing to start, and the second click is sent to the control. Is there some way to forward that click event (using editorEvent?) to the newly created control?Also, is it normal to call createWidget in paint() and sizeHint()?
Neil G
If you'd like a control there, you can try using persistent editors - see QAbstractItemView::openPersistentEditor(). Then, the first click will be sent to the control because the cell is always in editing mode. No, you shouldn't be needing to create widgets in paint() and sizeHint() - your editor should have already been created previously.
swongu