Qt: setData method in QAbstractItemModel

I am new to modeling, and I am following this guide while checking the documentation, and I came across this small detail: The code tutorial, which can be downloaded here , has in the QAbstractItemModel class (here QAbstractListModel) the setData method, whose code is:

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 

In accordance with 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:

 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 is still updating if color.isValid (), even if the function returns False. Am I misunderstanding the return role in the setData method or is this an error?

For reference, I am using PySide 1.2.1, not PyQt4.

+6
source share
3 answers

To quote a video regarding setData :

... this function should return true if the operation was successful, or the view itself will not be updated.

Strictly speaking, this statement is false. The documentation for QAbstractItemModel states that setData returns true if the data was set successfully, and false otherwise; he does not mention the consequences of this. In particular, he does not mention anything about updating the view.

Looking at the Qt source code, the return value of setData checked in several places, and some of these checks can sometimes trigger an update. But there are literally dozens of things that can trigger an update, so the return value of setData has nothing to do with updating the elements.

Perhaps it would be more correct to say that setData should return true, otherwise the view may not be updated (under certain circumstances).

+2
source

Am I really misunderstanding the return role in the setData method or is this an error?

From the Qt documentation:

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

Sets the role data values ​​for an index in an index.

Returns true if successful; otherwise returns false.

The dataChanged () signal must be removed if the data has been successfully set.

The base class implementation returns false. This function and data () must be redefined for editable models.

However, you seem to be emitting a dataChanged () signal, even if the data has not been successfully set based on the return value. In addition, this tutorial uses self.__colors in your code for rowCount() , `data (), and other methods. If you want to avoid updating, you will need to return False before any such expression.

You need to pay attention to these criteria because the signal and colors are internally controlled, and the return value is used by the caller to check if the setData() method has been set successfully.

Based on the above knowledge, you should write this code for your second attempt to get it to work the way you expect:

 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 
+2
source

I could not find much information about this. However, this post on the Qt specialist forum indicates that this behavior is the design choice of the Qt developers:

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

More specifically, views do not lose your input if it is rejected by the model. This may seem strange in the context of the tutorial you are following (where the color changes are not synchronized with the model), but in some contexts this may be desirable.

As an example, suppose you created a form using QLineEdit and QDataWidgetMapper to map the contents of the form to your model. Assume also that QDataWidgetMapper::SubmitPolicy is set to AutoSubmit . In AutoSubmit mode AutoSubmit every time a QLineEdit edited and then loses focus, the model is updated. If the model also rejects the change, and the current data (without changes) is populated in QLineEdit , this will lead to the fact that the user starts working (instead of fixing his record).

An alternative design option is to allow the view not to synchronize with the model and, if this is undesirable, to push the responsibility for changing this behavior to the programmer.

Two ways in which I can think of this can be changed as follows:

  • Create a custom delegate that handles setData false , giving a custom dataRejected signal that the view can connect to and use for updating.
  • Create a stateless view for your model: make the view retrieve data from the model anytime it is updated. Thus, transmitting a potential change to a model will not update the view if this model does not emit a dataChanged signal, in which case the view will retrieve the current state and the update itself.
+1
source

All Articles