简体   繁体   English

Qt : QAbstractItemModel 中的 setData 方法

[英]Qt : setData method in a QAbstractItemModel

I'm new to model view and I have been following this tutorial while checking the documentation at the same time and I stumbled upon this little detail : The code of the tutorial which can be downloaded here has in the QAbstractItemModel class (here QAbstractListModel) the setData method which code is :我是模型视图的新手,我一直在关注本教程,同时检查文档,我偶然发现了这个小细节:可以在此处下载的教程代码包含在 QAbstractItemModel 类(此处为 QAbstractListModel)中setData 方法的代码是:

def setData(self, index, value, role = QtCore.Qt.EditRole):
    if role == QtCore.Qt.EditRole:

        row = index.row()
        color = QtGui.QColor(value)

        if color.isValid():
            self.__colors[row] = color
            self.dataChanged.emit(index, index)
            return True
    return False

According to the explanations in the tutorial and from what I understood from the documentation, if the function returns True, then the view is updated, if it returns false, nothing happens, but when I changed the code to :根据教程中的解释以及我从文档中理解的内容,如果函数返回 True,则更新视图,如果返回 false,则什么也没有发生,但是当我将代码更改为:

def setData(self, index, value, role = QtCore.Qt.EditRole):
    if role == QtCore.Qt.EditRole:

        row = index.row()
        color = QtGui.QColor(value)

        if color.isValid():
            self.__colors[row] = color
            self.dataChanged.emit(index, index)
            return False # This is what I changed in the code
    return False

I realized that the view still gets updated if color.isValid() even if the function returns False.我意识到即使函数返回 False,如果 color.isValid() 视图仍然会更新。 Am I misunderstanding the return role in the setData method or is it a bug ?我误解了 setData 方法中的返回角色还是错误?

For reference, I'm using PySide 1.2.1, not PyQt4.作为参考,我使用的是 PySide 1.2.1,而不是 PyQt4。

To quote from the video tutorial regarding setData :引用有关setData的视频教程:

...this function needs to return true if the operation was successful, or else the view will not update itself. ...如果操作成功,此函数需要返回 true,否则视图将不会自行更新。

Strictly speaking, this statement is false.严格来说,这种说法是错误的。 The documentation for QAbstractItemModel only says that setData returns true if the data was set successfully, and false otherwise; QAbstractItemModel的文档只说如果数据设置成功,则setData返回 true,否则返回 false; it does not mention what the consequences of this might be.它没有提到这可能产生的后果。 Specifically, it does not mention anything about updating the view.具体来说,它没有提到关于更新视图的任何内容。

Looking at the Qt source code, the return value of setData does get checked in a few places, and some of those checks can sometimes help trigger an update.查看 Qt 源代码, setData的返回值确实在一些地方被检查,其中一些检查有时可以帮助触发更新。 But there are literally dozens of things that can trigger an update, so the return value of setData is in no way essential for updating items.但是实际上有很多东西可以触发更新,所以setData的返回值对于更新项目来说并不是必不可少的。

Perhaps it would have been more accurate to say that setData should return true, otherwise the view may not update itself (under certain circumstances).也许说setData应该返回 true 会更准确,否则视图可能不会自行更新(在某些情况下)。

Am I misunderstanding the return role in the setData method or is it a bug ?我误解了 setData 方法中的返回角色还是错误?

From the Qt documentation :从 Qt 文档

bool QAbstractItemModel::setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) [virtual] bool QAbstractItemModel::setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) [虚拟]

Sets the role data for the item at index to value.将索引处项目的角色数据设置为值。

Returns true if successful;成功则返回真; otherwise returns false.否则返回false。

The dataChanged() signal should be emitted if the data was successfully set.如果成功设置了数据,则应发出 dataChanged() 信号。

The base class implementation returns false.基类实现返回 false。 This function and data() must be reimplemented for editable models.必须为可编辑模型重新实现此函数和 data()。

Yet, you seem to emit the dataChanged() signal even if the data is not successfully set based on the return value.然而,即使未根据返回值成功设置数据,您似乎也会发出 dataChanged() 信号。 Also, the tutorial you seem to refer to, is using the self.__colors set in your code for the rowCount() , `data(), and other methods.此外,您似乎参考的教程正在使用代码中为rowCount() 、`data() 和其他方法设置的self.__colors If you would like to avoid the update, you will need to return False before any such statement.如果您想避免更新,则需要在任何此类语句之前返回 False。

You need to pay attention to these criterias because the signal and the colors are managed internally while the return value is used by the caller to see if the setData() method had been successfully set.您需要注意这些标准,因为信号和颜色是内部管理的,而调用者使用返回值来查看setData()方法是否已成功设置。

Based on the knowledge above, you should have written this code for your second attempt to make it work as you expect it to:根据上述知识,您应该编写此代码以进行第二次尝试,使其按预期工作:

def setData(self, index, value, role = QtCore.Qt.EditRole):
    if role == QtCore.Qt.EditRole:

        row = index.row()
        color = QtGui.QColor(value)

        if color.isValid():
            return False
    return False

I couldn't find much info on this.我找不到这方面的太多信息。 That said, this forum post by a "Qt Specialist" suggests that this behavior is a design choice by the Qt developers:也就是说,“Qt 专家”的这个论坛帖子表明这种行为是 Qt 开发人员的设计选择:

http://qt-project.org/forums/viewthread/31462 http://qt-project.org/forums/viewthread/31462

More specifically, the views do not lose your input if it gets rejected by the model.更具体地说,如果被模型拒绝,视图不会丢失您的输入。 This may seem weird in the context of the tutorial you are following (where the color changes out of sync with the model), but in some contexts this might be desirable.在您所关注的教程的上下文中,这可能看起来很奇怪(颜色的变化与模型不同步),但在某些上下文中,这可能是可取的。

As an example, let's say you have designed a form using QLineEdit s and QDataWidgetMapper to map the contents of the form to your model.例如,假设您已经使用QLineEditQDataWidgetMapper设计了一个表单,以将表单的内容映射到您的模型。 Let's also suppose that QDataWidgetMapper::SubmitPolicy is set to AutoSubmit .我们还假设QDataWidgetMapper::SubmitPolicy设置为AutoSubmit In AutoSubmit mode, every time the QLineEdit is edited and then loses focus, the model is updated.AutoSubmit模式下,每次编辑QLineEdit然后失去焦点时,都会更新模型。 If the model also rejects the change, and the current data (sans change) is repopulated into the QLineEdit , this would have the effect of the user having to start over (rather than fixing up their entry).如果模型也拒绝更改,并且当前数据(无更改)重新填充到QLineEdit ,这将导致用户必须重新开始(而不是修复他们的条目)。

The alternative design choice is to allow the view to be out of sync with the model and, if this is undesirable, to push the responsibility to change this behavior onto the programmer.另一种设计选择是允许视图与模型不同步,如果这是不可取的,则将更改此行为的责任推给程序员。

Two ways that I can think of off-hand to change this behavior would be to:我可以想到的两种改变这种行为的方法是:

  1. Create a custom delegate that handles setData -> false by emitting a custom dataRejected signal that the view could connect to and use to update itself.创建一个自定义委托,通过发出自定义dataRejected信号来处理setData -> false ,视图可以连接到该信号并用于更新自身。
  2. Create a "stateless" view for your model: force the view to retrieve data from the model any time it updates itself.为您的模型创建一个“无状态”视图:强制视图在其自身更新时从模型中检索数据。 In this manner, submitting a potential change to the model will not update the view unless that model emits a dataChanged signal, in which case the view will retrieve current state and update itself.以这种方式,向模型提交潜在更改不会更新视图,除非该模型发出dataChanged信号,在这种情况下,视图将检索当前状态并更新自身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM