自定义QStyledItemDelegate - 将修改应用于模型

时间:2016-12-30 03:52:45

标签: c++ qt qstyleditemdelegate

在我的项目中,我将QStyledItemDelegate子类化,并从createEditor函数返回了一个自定义编辑器。

QWidget* TagEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    TagEditWidget* tagEditWidget = new TagEditWidget(parent, index.data(Qt::UserRole+4).toInt(), index.data(Qt::UserRole+2).toByteArray(), index.data(Qt::UserRole+3).toByteArray(), index.parent().data(Qt::UserRole+4).toInt() == 9, parent->width());
    return tagEditWidget; //tagEditWidget is my custom QWidget
}

编辑完成后,我想将新数据写回模型。所以我覆盖了setModelData

void TagEditDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
    TagEditWidget * tagEditWidget = qobject_cast<TagEditWidget*>(editor);
    if (!tagEditWidget)
    {
        QStyledItemDelegate::setModelData(editor, model, index);
        return;
    }

    //Edit model here?
}

这样可行,但问题是无论编辑器如何关闭,setModelData都会被调用。如果编辑器使用EndEditHintQAbstractItemDelegate::SubmitModelCache关闭,我只想编写新数据。所以我将closeEditor信号连接到我所做的名为editFinished的插槽。

connect(this, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), this, SLOT(editFinished(QWidget*,QAbstractItemDelegate::EndEditHint)));

所以现在我可以看到编辑器如何通过EndEditHint关闭,如果我应该将数据写回模型。 Buuuuut,setModelDatacloseEditor信号之前被称为。当最后调用closeEditor信号时,如何将数据写回模型?我在这里错过了什么吗?

2 个答案:

答案 0 :(得分:1)

基本答案:

你的概念几乎到最后似乎都很好。我会专注于TagEditDelegate::setModelData方法。

如果您实际上不想更新模型中的数据,请检查它是否发生了变化。这意味着当oldData == newDatareturn;时跳过模型更新。

附加说明:

查看您的编辑器创建时,我得到的印象是它不会保存呈现给用户的单个值。为了使参数传递更友好并且比较编辑器数据更容易考虑为它创建单独的class/struct。所以你可以打电话:

new TagEditWidget(parent, editorData, parent->width())

其中EditorData将是您的类/结构,可能由一个单独的函数获取:

EditorData editorData = readEditorData(index);

可以在setModelData方法中重用该函数来检查条件:

if (tagEditWidget->getEditorData() == readEditorData(index)) return;

同时避免使用像Qt::UserRole+2这样的幻数。创建自己的枚举以指定所需的角色。例如:

enum class MyRole
{
    Data1 = Qt::UserRole,
    Data2,
    Data3,
};
根据评论

中的讨论,

编辑

如果你想要的是发现用户是否实际上没有以某种方式取消版本,你可以在编辑器或代理中覆盖eventFilter。 在构造函数中创建编辑器调用installEventFilter时。您的eventFilter实施可能如下所示:

bool eventFilter(QObject *object, QEvent *event) override
{
    if (event->type() == QEvent::KeyPress)
    {
        const auto key = static_cast<QKeyEvent *>(event)->key();
        if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Tab)
            submitted = true;
    }
    else if (event->type() == QEvent::FocusAboutToChange &&
             static_cast<QFocusEvent*>(event)->reason() == Qt::MouseFocusReason)
    {
        submitted = true;
    }
    // extetend the conditions (add else if) to include
    // events which you might want to treat as submitted

    return QLineEdit::eventFilter(object, event);
}

其中submittedbool编辑器成员,在构造函数中初始化为false。然后你可以创建一个getter方法isSubmitted(),然后你就可以检查setModelData方法中的状态。

if (tagEditWidget->isSubmitted())
{
    // process data or update model here
}

答案 1 :(得分:0)

我只是以自己的方式回答了我自己的问题。杜斯特的解决方案是更正确的#34;我想虽然。

我在名为shouldCommit的委托类中创建了一个bool,并将其设置为false。

然后在setModelData我检查是否应该将数据写入模型。

void TagEditDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
    TagEditWidget * tagEditWidget = qobject_cast<TagEditWidget*>(editor);
    if (!tagEditWidget)
    {
        QStyledItemDelegate::setModelData(editor, model, index);
        return;
    }

    if(shouldCommit)
    {
        //write data here
    }
}

然后,当发出closeEditor信号时,我检查提示并暂时将shouldCommit设置为true并再次呼叫commitData。现在shouldCommit为真,数据就会被写入。

void TagEditDelegate::editFinished(QWidget * editor, QAbstractItemDelegate::EndEditHint hint)
{
    if(hint == QAbstractItemDelegate::SubmitModelCache)
    {
        TagEditWidget * tagEditWidget = qobject_cast<TagEditWidget*>(editor);
        if(tagEditWidget)
        {
            shouldCommit = true;
            commitData(editor);
            shouldCommit = false;
        }
    }
}

虽然这对我的用例非常有用,但它可能不适合所有人,而Dusteh的评论部分可能对某些人更有用。他的方法是覆盖eventFilter并在何时调用commitData编写自己的实现。对于想要更多控制的人来说,这可能是更合适的解决方案。

但是对于任何想要使用默认eventFilter实现并只看EndEditHint的人来说,这是我的解决方案。