BeginResetModel () and endResetModel () doesn’t work when data contained in QStringListModel changed



  • beginResetModel () and endResetModel () doesn’t work when data contained in QStringListModel changed in my code here ,anyone can explain why ?
    @
    import sys

    from PyQt4.QtGui import *
    from PyQt4.QtCore import *

    class BoxLayout(QWidget):
    def init(self, parent=None):
    QWidget.init(self, parent)

        self.view = QTableView()
        hbox = QHBoxLayout()
        hbox.addWidget(self.view)
        self.setLayout(hbox)
        self.resize(800, 600)
    
        self.lst=[]
        self.stringListModel=QStringListModel (self.lst)
        self.view.setModel(self.stringListModel)
        
        self.timer = QTimer(self);
        self.timer.timeout.connect(self.timerHit)
        self.timer.start(1000)
        
    def timerHit(self):
        self.stringListModel.beginResetModel ()
        self.lst.append(QTime.currentTime().toString())
        print(self.lst)
        self.stringListModel.endResetModel ()
    

    app = QApplication(sys.argv)
    qb = BoxLayout()
    qb.show()
    sys.exit(app.exec_())

    @



  • Hi, begin/endResetModel() are protected memeber of QAbstractItemModel. They shouldn't be used in such way.

    BTW, seems what you want is QStringListModel::setStringList()



  • QStringListModel is a subclass of QAbstractItemModel ,so I think it could be used like this .
    [quote author="1+1=2" date="1382941707"]Hi, begin/endResetModel() are protected memeber of QAbstractItemModel. They shouldn't be used in such way.

    BTW, seems what you want is QStringListModel::setStringList()[/quote]



  • Yes, you can use it. but they are designed for implementation the subclass of QAbstractItemModel. For example, they will be called inside QStringListModel::setStringList() by the QStringListModel's writer.

    However, as python have no private/protect access control as such C++, you can call them outside the QAbstractItemModel or its subclass. But you must get and change the internal data of the Model between you can begin and endResetModel().



  • hey ,where can I see the C++ implementation of QStringListModel::setStringList() ?

    [quote author="1+1=2" date="1382943996"]Yes, you can use it. but they are designed for implementation the subclass of QAbstractItemModel. For example, they will be called inside QStringListModel::setStringList() by the QStringListModel's writer.

    However, as python have no private/protect access control as such C++, you can call them outside the QAbstractItemModel or its subclass. But you must get and change the internal data of the Model between you can begin and endResetModel(). [/quote]


  • Lifetime Qt Champion

    Hi,

    You can see all implementations in Qt's sources, search for qtstringlistmodel.cpp



  • I agree with 1+1=2, the solution is setStringList(), I only post the following as I was PM'ed by redstoneleo for help. So, the simple solution is as follows:

    @
    import sip
    sip.setapi('QString',2)
    sip.setapi('QVariant',2)

    from PyQt4.QtCore import *
    from PyQt4.QtGui import *

    class Widget(QWidget):
    def init(self, parent=None, **kwargs):
    QWidget.init(self, parent, **kwargs)

        l=QHBoxLayout(self)
    
        self._model=QStringListModel(self)
    
        table=QTableView(self)
        table.setModel(self._model)
        l.addWidget(table)
    
        self._timerId=self.startTimer(1000)
    
    def timerEvent(self, event):
        if not event.timerId()==self._timerId: return
    
        stringList=self._model.stringList()
        stringList.append(QTime.currentTime().toString())
        self._model.setStringList(stringList)
    

    if name=="main":
    from sys import argv, exit

    a=QApplication(argv)
    w=Widget()
    w.show()
    w.raise_()
    exit(a.exec_())
    

    @

    The downside with this solution is that the model is being set and reset every time a value is inserted, the overhead for which will become onerous for large models. The correct solution therefore would be to insert a single new row as follows:

    @
    import sip
    sip.setapi('QString',2)
    sip.setapi('QVariant',2)

    from PyQt4.QtCore import *
    from PyQt4.QtGui import *

    class Widget(QWidget):
    def init(self, parent=None, **kwargs):
    QWidget.init(self, parent, **kwargs)

        l=QHBoxLayout(self)
    
        self._model=QStringListModel(self)
    
        table=QTableView(self)
        table.setModel(self._model)
        l.addWidget(table)
    
        self._timerId=self.startTimer(1000)
    
    def timerEvent(self, event):
        if not event.timerId()==self._timerId: return
    
        row=self._model.rowCount()
        if self._model.insertRows(row, 1):
            index=self._model.index(row, 0)
            if not index.isValid(): return
            self._model.setData(index, QTime.currentTime().toString())
    

    if name=="main":
    from sys import argv, exit

    a=QApplication(argv)
    w=Widget()
    w.show()
    w.raise_()
    exit(a.exec_())
    

    @

    Hope this helps ;o)



  • so protected method in C++ is designed for implementing class ,not used for an object method ,right ?

    [quote author="1+1=2" date="1382943996"]Yes, you can use it. but they are designed for implementation the subclass of QAbstractItemModel. For example, they will be called inside QStringListModel::setStringList() by the QStringListModel's writer.

    However, as python have no private/protect access control as such C++, you can call them outside the QAbstractItemModel or its subclass. But you must get and change the internal data of the Model between you can begin and endResetModel(). [/quote]



  • [quote author="jazzycamel" date="1382971018"]
    The downside with this solution is that the model is being set and reset every time a value is inserted, the overhead for which will become onerous for large models.
    [/quote]

    thanks , jazzycamel .You always help me a lot !!!

    how do you know seting and reseting large models take large overhead ?
    How do you evaluate the overload ?

    Besides , why index.isValid() in your code ? is it necessary ?



  • Experience and common sense tells me that it's better to add a single item than to reset the whole model each time, particularly if there is a view attached. If you really want to test this, try putting a few thousand items in your list and then try and interact with the associated view as you update it: you'll find that whilst resetting the GUI will hang briefly.

    I think we've discussed my use of index.isValid() before. I always ensure that an index that I have either created or got a reference to is valid before using it as it is more than possible to be legitimately given an invalid index, particularly if the models dimensions are changing, and this check prevents illegal accesses or simply wasting time.



  • [quote author="jazzycamel" date="1383398039"] I always ensure that an index that I have either created or got a reference to is valid before using it as it is more than possible to be legitimately given an invalid index, particularly if the models dimensions are changing, and this check prevents illegal accesses or simply wasting time. [/quote]
    Good idea ! but "here":https://qt.gitorious.org/qt/qt/source/fbf11a9584c011e5fb10bf008cc3c8ad99c3103f:src/gui/itemviews/qstringlistmodel.cpp#L130-248 the implementation of setData() in QStringListModel already does some index checking.



  • Actually, that goes to prove my point as setData() is one of the methods you would overload if you were implementing your own model based on one of the abstract model classes (and would, therefore, do your own index checking). Anywho, I guess it comes down to personal preference: I would rather check the index validity and save the call to setData (or other methods), but its up to you and your application's requirements.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.