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 :
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 :
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. Am I misunderstanding the return role in the setData method or is it a bug ?
For reference, I'm using PySide 1.2.1, not PyQt4.
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:
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 andQDataWidgetMapper
to map the contents of the form to your model. Let's also suppose thatQDataWidgetMapper::SubmitPolicy
is set toAutoSubmit
. InAutoSubmit
mode, every time theQLineEdit
is edited and then loses focus, the model is updated. If the model also rejects the change, and the current data (sans change) is repopulated into theQLineEdit
, this would have the effect of the user having to start over (rather than fixing up their entry).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:
setData
->false
by emitting a customdataRejected
signal that the view could connect to and use to update itself.dataChanged
signal, in which case the view will retrieve current state and update itself.From the Qt documentation:
Yet, you seem to emit the dataChanged() signal even if the data is not successfully set based on the return value. Also, the tutorial you seem to refer to, is using the
self.__colors
set in your code for therowCount()
, `data(), and other methods. If you would like to avoid the update, you will need to return False before any such statement.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.Based on the knowledge above, you should have written this code for your second attempt to make it work as you expect it to:
To quote from the video tutorial regarding
setData
: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; 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. But there are literally dozens of things that can trigger an update, so the return value ofsetData
is in no way essential for updating items.Perhaps it would have been more accurate to say that
setData
should return true, otherwise the view may not update itself (under certain circumstances).