[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyQt] decorator for QAbstractItemModel::dataChanged()
From:       Maurizio Berti <maurizio.berti () gmail ! com>
Date:       2018-08-12 1:05:45
Message-ID: CAPn+-XQQmn6u0=0uPk=y_XOwwv1h3P0v0nzGyzmemDYR3mvNiw () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


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
behavior:

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
> submitting.


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:

class SubClassModel(QtSql.QSqlTableModel):
    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)
            if result:
                self.myDataChanged.emit(index, value)
            return result
        return QtSql.QSqlTableModel.setData(self, index, value, role)


Maurizio


2018-08-11 11:34 GMT+02:00 J Barchan <jnbarchan@gmail.com>:

> 
> On 11 August 2018 at 05:31, Zhao Lee <redstone-cold@163.com> wrote:
> 
> > The sample code as following
> > 
> > self.tableView.setModel(self.sqlTableModel)
> > self.sqlTableModel.dataChanged.connect(self.onDataChanged)
> > 
> > @pyqtSlot(QModelIndex, QModelIndex)  # ,QVector:name 'QVector' is not
> > defined
> > def onDataChanged(self):
> > print('onDataChanged--------')
> > 
> > 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@riverbankcomputing.com
> > https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> > 
> 
> 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.
> 
> 
> --
> Kindest,
> Jonathan
> 
> 
> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail> \
> Virus-free. www.avast.com
> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
>  <#m_1058783516155111231_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
> 
> _______________________________________________
> PyQt mailing list    PyQt@riverbankcomputing.com
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
> 



-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net


[Attachment #5 (text/html)]

<div dir="ltr">I just did a test, it seems that the behavior is slightly different \
from PyQt4, which fires the signal only once.<div><br></div><div>According to <a \
href="https://bugreports.qt.io/browse/QTBUG-30672">https://bugreports.qt.io/browse/QTBUG-30672</a> \
it&#39;s the intended behavior:<br></div><br><blockquote class="gmail_quote" \
style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex">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&#39;s values after \
refreshing are not necessarily the same as the values in the cache before \
submitting.</blockquote><div><br></div><div>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.<br></div><div><div><br></div><div>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.<br>As expected, using \
QSqlTableModel.revertAll() obviously fires the signal with the reverted \
data.</div><div>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.</div></div><div><br></div><div>If you don&#39;t want this \
&quot;duplicate&quot; behaviour, I can see three possibilities:</div><div>1. Add \
topLeft/bottomRight arguments to the slot method and ignore changes applied to \
topLeft != bottomRight. In simple case scenarios, this shouldn&#39;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&#39; row() and column() properties.<br>2. Change the strategy to \
OnManualSubmit and manually submitAll() data in the onDataChanged slot. I \
wouldn&#39;t suggest this one.<br>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:<br></div><div><br></div><div><font \
face="monospace, monospace">class \
SubClassModel(QtSql.QSqlTableModel):<br></font></div><div><div><font face="monospace, \
monospace">      myDataChanged = QtCore.Signal(QtCore.QModelIndex, \
object)<br></font></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace">      def \
setData(self, index, value, role=QtCore.Qt.EditRole):</font></div><div><font \
face="monospace, monospace">            if role == \
QtCore.Qt.EditRole:</font></div><div><font face="monospace, monospace">               \
result = QtSql.QSqlTableModel.setData(self, index, value, \
role)</font></div><div><font face="monospace, monospace">                  if \
result:</font></div><div><font face="monospace, monospace">                        \
self.myDataChanged.emit(index, value)</font></div><div><font face="monospace, \
monospace">                  return result</font></div><div><font face="monospace, \
monospace">            return QtSql.QSqlTableModel.setData(self, index, value, \
role)</font><br></div></div><div><br></div><div><br></div><div>Maurizio</div><div><br></div></div><div \
class="gmail_extra"><br><div class="gmail_quote">2018-08-11 11:34 GMT+02:00 J Barchan \
<span dir="ltr">&lt;<a href="mailto:jnbarchan@gmail.com" \
target="_blank">jnbarchan@gmail.com</a>&gt;</span>:<br><blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"><div dir="ltr"><div class="gmail_default" \
style="font-family:tahoma,sans-serif"></div><div class="gmail_extra"><br><div \
class="gmail_quote"><div><div class="h5">On 11 August 2018 at 05:31, Zhao Lee <span \
dir="ltr">&lt;<a href="mailto:redstone-cold@163.com" \
target="_blank">redstone-cold@163.com</a>&gt;</span> \
wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px \
0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><div><div \
class="h5"><div><div style="color:rgb(0,0,0);font-family:arial;font-size:14px">The \
sample code as following  </div><div \
style="color:rgb(0,0,0);font-family:arial;font-size:14px"><br></div><div><span \
style="background-color:rgb(255,255,255)">self.tableView.setModel(self.s<wbr>qlTableModel)</span></div><div><span \
style="background-color:rgb(255,255,255)">self.sqlTableModel.dataChanged<wbr>.connect(self.onDataChanged)</span></div><div><br></div><div><div><span \
style="background-color:rgb(255,255,255)">@pyqtSlot(QModelIndex, QModelIndex)   # \
,QVector:name &#39;QVector&#39; is not defined</span></div><div><span \
style="background-color:rgb(255,255,255)">      def \
onDataChanged(self):</span></div><div><span \
style="background-color:rgb(255,255,255)">            \
print(&#39;onDataChanged--------&#39;)</span></div></div><div \
style="color:rgb(0,0,0);font-family:arial;font-size:14px"><br></div><div \
style="color:rgb(0,0,0);font-family:arial;font-size:14px">each time when I edit a \
cell in the table view, the  QAbstractItemModel::dataCh<wbr>anged() was triggered two \
times , I guess my  decorator for QAbstractItemModel::dataChange<wbr>d() may be wrong \
, so what&#39;s the right  decorator for it ?</div><div \
style="color:rgb(0,0,0);font-family:arial;font-size:14px"><br></div><div \
style="color:rgb(0,0,0);font-family:arial;font-size:14px"><br></div><div \
style="color:rgb(0,0,0);font-family:arial;font-size:14px"><br></div></div><br><br><span \
title="neteasefooter"><p>  \
</p></span><br></div></div>______________________________<wbr>_________________<br> \
PyQt mailing list      <a href="mailto:PyQt@riverbankcomputing.com" \
target="_blank">PyQt@riverbankcomputing.com</a><br> <a \
href="https://www.riverbankcomputing.com/mailman/listinfo/pyqt" rel="noreferrer" \
target="_blank">https://www.riverbankcomputing<wbr>.com/mailman/listinfo/pyqt</a><br></blockquote></div><br><div \
class="gmail_default" style="font-family:tahoma,sans-serif">I&#39;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&#39;s called twice for \
some other reason.</div><span class="HOEnZb"><font color="#888888"><br \
clear="all"><br>-- <br><div class="m_1058783516155111231gmail_signature" \
data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><span \
style="font-family:tahoma,sans-serif">Kindest,</span></div><div><span \
style="font-family:tahoma,sans-serif">Jonathan</span></div></div></div></div></div> \
</font></span></div></div><span class="HOEnZb"><font color="#888888"><div \
id="m_1058783516155111231DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2"><br> <table \
style="border-top:1px solid #d3d4de">  <tbody><tr>
        <td style="width:55px;padding-top:13px"><a \
href="https://www.avast.com/sig-email?utm_medium=email&amp;utm_source=link&amp;utm_campaign=sig-email&amp;utm_content=webmail" \
target="_blank"><img \
src="https://ipmcdn.avast.com/images/icons/icon-envelope-tick-round-orange-animated-no-repeat-v1.gif" \
alt="" width="46" height="29" style="width:46px;height:29px"></a></td>  <td \
style="width:470px;padding-top:12px;color:#41424e;font-size:13px;font-family:Arial,Helvetica,sans-serif;line-height:18px">Virus-free. \
<a href="https://www.avast.com/sig-email?utm_medium=email&amp;utm_source=link&amp;utm_campaign=sig-email&amp;utm_content=webmail" \
style="color:#4453ea" target="_blank">www.avast.com</a>  </td>
	</tr>
</tbody></table><a href="#m_1058783516155111231_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2" \
width="1" height="1"></a></div> \
</font></span><br>______________________________<wbr>_________________<br> PyQt \
mailing list      <a \
href="mailto:PyQt@riverbankcomputing.com">PyQt@riverbankcomputing.com</a><br> <a \
href="https://www.riverbankcomputing.com/mailman/listinfo/pyqt" rel="noreferrer" \
target="_blank">https://www.<wbr>riverbankcomputing.com/<wbr>mailman/listinfo/pyqt</a><br></blockquote></div><br><br \
clear="all"><div><br></div>-- <br><div class="gmail_signature" \
data-smartmail="gmail_signature">È difficile avere una convinzione precisa quando si \
parla delle ragioni del cuore. - &quot;Sostiene Pereira&quot;, Antonio Tabucchi<br><a \
href="http://www.jidesk.net" target="_blank">http://www.jidesk.net</a></div> </div>


[Attachment #6 (text/plain)]

_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
https://www.riverbankcomputing.com/mailman/listinfo/pyqt

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic