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

Posted

技术标签:

【中文标题】在 Qt 中,如何正确实现委托?【英文标题】:In Qt, how do you properly implement delegates? 【发布时间】:2009-05-12 03:33:30 【问题描述】:

我遵循模型/视图/控制器范式。我很确定模型和视图是正确的,但我认为我的代表做错了一些事情。一切都“正常工作”,除了第一次单击控件只是“点亮控件”并且第二个与之交互。这就是代表通常的实现方式吗?我的实现需要大量的构造和破坏(由 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);

【问题讨论】:

你可能是指模型-视图-控制器。没有模型/视图/委托范式之类的东西。 【参考方案1】:

如果您有兴趣更改自定义编辑器的显示条件,请使用QAbstractItemView::setEditTriggers()。虽然您的委托负责在自定义编辑器之间传递信息,但视图决定了编辑器的启动时间。

文档参考:http://doc.qt.digia.com/4.5/qabstractitemview.html#editTriggers-prop。

【讨论】:

我试过了,但第一次点击没有编辑触发器。只有 SelectedClicked 和 DoubleClicked,所以我想我会在第一次点击时使用 editorEvent 强制编辑。走错路了? 试试 CurrentChanged。当单元格选择发生变化时,它将开始编辑。 哇,即使选择被禁用,它也能正常工作。太棒了,这摆脱了 editorEvent 方法。我也会在上面的代码中删除它。 很高兴听到它对您有用。我的回答是否也明确了代表的角色? 我认为我的问题没有得到完全回答。我希望第一次单击转到创建的控件,但正如代码所示,第一次单击会导致编辑开始,第二次单击会发送到控件。有没有办法将该点击事件(使用editorEvent?)转发到新创建的控件?还有,在paint()和sizeHint()中调用createWidget正常吗?

以上是关于在 Qt 中,如何正确实现委托?的主要内容,如果未能解决你的问题,请参考以下文章

QT中级QTableView自定义委托实现QSpinBoxQDoubleSpinBox委托

QT QTableView 使用委托

QT 模型/视图 编程 委托篇

如何存储在 Qt 设置中?

Qml c++ 不同的委托 qt mvc

82.QT实现委托构造