[PyQt] model/view/delegate: data() method called too many times? Performance problem

TP paratribulations at free.fr
Thu May 14 20:21:30 BST 2009


Hi everybody,

I use model/view/delegate architecture of Qt.
I have a problem of slowness in a small example given below. Run the script
from a terminal to see all standard output.
Try to play with the tree: expand items, click on cells, etc. You will find
that the function "data" is called all the time by Qt. Too many times, I
think. For example, we get on standard output sequences as:

data, col=1, row=2
data, col=1, row=2
data, col=1, row=2
data, col=1, row=2
data, col=1, row=2
data, col=1, row=2
data, col=1, row=2

which means that the data function is called several times for the same
cell! Why? It slows down a lot my "real world" application, which is much
more complicated than this simple script.

How to modify this "greedy" behavior of Qt?

Thanks a lot

Julien


######################################"
#!/usr/bin/env python
# -*- coding: utf-8 -*-

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


class CustomProxyModel( QSortFilterProxyModel ):

    def filterAcceptsRow( self
            , source_row
            , source_parent_index ):

        return True


class TreeROModel( QAbstractItemModel ):


    def __init__( self
            , parent = None ):

        super( TreeROModel, self ).__init__( parent )
        self.root = "toto"
        self.children = [
                "coco"
                , "line 1" ]
        self.children_offirstline = [
                "coucou" ]
        self.columncount = 2



    def rowCount( self, parent ):

        node = self.nodeFromIndex( parent )
        if node == self.root:
            return len( self.children )
        elif node == "coco":
            return 1
        else:
            return 0


    def columnCount( self, QModelIndex = None ):

        return 2
        return self.columncount


    def data( self, index, role ):

        content = None
        col = index.column()
        row = index.row()
        print "data, col=%i, row=%i" % (col, row)
        if role == Qt.DisplayRole:
            if col == 0:
                content = self.nodeFromIndex( index )
            elif row == 0:
                content = len( self.children ) - 1

            else:
                content = "nothing in this item"

        elif role == Qt.TextAlignmentRole:

            if col == 0:
                content = int( Qt.AlignTop|Qt.AlignLeft )
            else:
                content = int( Qt.AlignTop|Qt.AlignRight )

        if content != None:
            return QVariant( content )
        else:
            # default choice
            return QVariant()




    def index( self, row, column, parent_index ):

        parent = self.nodeFromIndex( parent_index )
        if parent == "coco":
            child = self.children_offirstline[0]
        else:
            child = self.children[ row ]
        index = self.createIndex( row
                , column
                , child )

        return index



    def nodeFromIndex( self, index ):

        if index.isValid():
            node = index.internalPointer()
            return node
        else:
            node = self.root
            return node


    def parent( self, child_index ):

        node = self.nodeFromIndex( child_index )
        if node == "coucou":
            index = self.createIndex( 0, 0, self.root )
            return index
        else:
            return QModelIndex()


    def allIndex( self ):

        yield QModelIndex()
        index = self.createIndex( 0, 0, self.children[0] )
        yield index
        index = self.createIndex( 0, 0, self.children_offirstline[0] )
        yield index



class TreeROWidget( QWidget ):



    def __init__( self
            , TreeROModel_
            , title = None
            , parent = None ):

        super( TreeROWidget, self ).__init__( parent )

        # central tree view
        self.view = QTreeView( parent )
        self.view.setSelectionBehavior( QTreeView.SelectItems )

        # central tree model
        self.model = TreeROModel_
        self.proxyModel = CustomProxyModel()
        self.proxyModel.setSourceModel( self.model )

        self.view.setModel( self.proxyModel )
        self.view.setAlternatingRowColors( True )


        self.connect( self.view, SIGNAL( "clicked(QModelIndex)" )
                , self.cellClicked )

        # layout
        vboxlayout = QVBoxLayout()
        hboxlayout = QHBoxLayout()
        vboxlayout.addLayout( hboxlayout )
        vboxlayout.addWidget( self.view )
        self.setLayout( vboxlayout )

        self.show()


    def cellClicked( self, qmodelindex ):

        if qmodelindex.isValid():
            qmodelindex = self.proxyModel.mapToSource( qmodelindex )
            print qmodelindex.internalPointer()



class TreeWidget( TreeROWidget ):

    def __init__( self
            , TreeROModel_
            , title = None
            , parent = None ):

        super( TreeWidget, self ).__init__( parent = parent
                , TreeROModel_ = TreeROModel_
                , title = title )



if __name__ == "__main__":

    def add_col():

        for index in widget.model.allIndex():
            print index, index.internalPointer()
            widget.model.beginInsertColumns( index, 2, 2 )
            widget.model.endInsertColumns()

    def add_row():

        index = QModelIndex()
        l = len( widget.model.children )
        widget.model.beginInsertRows( index, l, l )
        widget.model.children.append( "toto %i" % l )
        print widget.model.children
        widget.model.endInsertRows()

    app = QApplication( sys.argv )
    dialog = QDialog( )
    dialog.resize( 750, 550 )

    widget = TreeWidget( TreeROModel() )

    vboxlayout = QVBoxLayout( dialog )
    vboxlayout.addWidget( widget )
    dialog.setLayout( vboxlayout )
    dialog.show()
    widget.view.resizeColumnToContents( 0 )
    widget.view.resizeColumnToContents( 1 )

    pushbutton1 = QPushButton( "Add column in line 1" )
    pushbutton2 = QPushButton( "Add row" )
    vboxlayout.addWidget( pushbutton1 )
    vboxlayout.addWidget( pushbutton2 )

    QObject.connect( pushbutton1, SIGNAL( "clicked()" )
            , add_col )
    QObject.connect( pushbutton2, SIGNAL( "clicked()" )
            , add_row )

    app.exec_()



-- 
python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\
9&1+,\'Z4(55l4('])"

"When a distinguished but elderly scientist states that something is
possible, he is almost certainly right. When he states that something is
impossible, he is very probably wrong." (first law of AC Clarke)



More information about the PyQt mailing list