[PyQt] decorator for QAbstractItemModel::dataChanged()
maurizio.berti at gmail.com
Sun Aug 12 02:05:45 BST 2018
I just did a test, it seems that the behavior is slightly different from
PyQt4, which fires the signal only once.
According to https://bugreports.qt.io/browse/QTBUG-30672 it's the intended
dataChanged() is emitted immediately when a new change is cached and also
> when the record is refreshed from the database table after submitting. A
> connected view needs to know about both. The record's values after
> refreshing are not necessarily the same as the values in the cache before
According to my tests, the signal is indeed emitted the first time when the
data is actually changed, while the second time the signal is emitted even
if no actual data has actually changed, with the first and last column of
the affected row as arguments of the slot, as the data is actually
submitted (as in commit) to the database.
This can be demonstrated as also related to the EditStrategy of the
QSqlTableModel: when the strategy is set to OnManualSubmit, the signal is
emitted only the first time.
As expected, using QSqlTableModel.revertAll() obviously fires the signal
with the reverted data.
Strangely enough (I can try and understand why, but it still seems a bit
inconsistent), after manually calling submitAll() with this strategy,
dataChanged is not emitted.
If you don't want this "duplicate" behaviour, I can see three possibilities:
1. Add topLeft/bottomRight arguments to the slot method and ignore changes
applied to topLeft != bottomRight. In simple case scenarios, this shouldn't
be a problem, as 99% of dataChange are usually related to a single index
(meaning that topLeft and bottomRight arguments are the same). You could
eventually be thorough by checking indexes' row() and column() properties.
2. Change the strategy to OnManualSubmit and manually submitAll() data in
the onDataChanged slot. I wouldn't suggest this one.
3. Subclass QSqlTableModel with a custom signal, implement setData() and
manually emit the custom signal when role == QtCore.Qt.EditRole. In this
case, it might be better to ensure that the data is actually submitted
before sending the signal:
myDataChanged = QtCore.Signal(QtCore.QModelIndex, object)
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
result = QtSql.QSqlTableModel.setData(self, index, value, role)
return QtSql.QSqlTableModel.setData(self, index, value, role)
2018-08-11 11:34 GMT+02:00 J Barchan <jnbarchan at gmail.com>:
> On 11 August 2018 at 05:31, Zhao Lee <redstone-cold at 163.com> wrote:
>> The sample code as following
>> @pyqtSlot(QModelIndex, QModelIndex) # ,QVector:name 'QVector' is not
>> def onDataChanged(self):
>> each time when I edit a cell in the table view,
>> the QAbstractItemModel::dataChanged() was triggered two times , I guess
>> my decorator for QAbstractItemModel::dataChanged() may be wrong , so
>> what's the right decorator for it ?
>> PyQt mailing list PyQt at riverbankcomputing.com
> I'm a PyQt user but not an expert. Whether your decorator is right or
> wrong I cannot see it would make any difference to how often a slot is
> called. I presume it's called twice for some other reason.
> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> Virus-free.
> PyQt mailing list PyQt at riverbankcomputing.com
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the PyQt