在Qt中,如何正确实现委托?

3

我遵循了模型/视图/控制器范例。我相信我的模型和视图是正确的,但我认为我在代理方面做错了一些事情。所有的东西“运作”得很好,除了第一次点击控件只会“点亮控件”,第二次才与它交互。这是代理通常实现的方式吗?我的实现需要大量的构建和销毁(由scoped_ptr隐藏),所以任何关于此方面的提示都是有帮助的。

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);
}

您可能指的是模型-视图-控制器(Model-View-Controller)。不存在所谓的模型/视图/代理范例。 - shoosh
1个回答

4

我尝试过了,但第一次点击没有编辑触发器。只有SelectedClicked和DoubleClicked,所以我想使用editorEvent在第一次点击时强制进行编辑。这样做是错误的吗? - Neil G
1
尝试使用CurrentChanged。这将在单元格选择更改时开始编辑。 - swongu
哇,即使选择被禁用,它也能正常工作。太棒了,这样就可以摆脱editorEvent方法了。我也会在上面的代码中将其删除。 - Neil G
很高兴听到它对你有用。我的回答是否也澄清了代表的角色? - swongu
我觉得我的问题还没有完全得到解答。我希望第一次点击将会定位到创建的控件,但是根据目前的代码,第一次点击会导致编辑开始,而第二次点击才会发送到控件上。有没有一种方法可以将该点击事件(使用editorEvent?)转发给新创建的控件?另外,在paint()和sizeHint()中调用createWidget是正常的吗? - Neil G
如果您想在那里放置一个控件,可以尝试使用持久编辑器 - 参见QAbstractItemView :: openPersistentEditor()。然后,第一次单击将发送到控件,因为单元格始终处于编辑模式。不,您不应该需要在paint()和sizeHint()中创建小部件 - 您的编辑器应该已经先前创建好了。 - swongu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接