mvc(QSortFilterProxyModel)中的自定义排序仅适用一次

时间:2012-06-26 07:22:39

标签: qt pyqt pyqt4 pyside

我正在尝试为PySide中的模型/视图结构设置自定义排序行为。 所有项目都是字典,我需要按其键过滤(我不是在查看这些词典的表格视图,而是需要将它们作为一个实体呈现)。

我从QSortFilterProxyModel继承并重新实现了lessThan方法。它在第一次更改排序小部件时会正常工作(触发代理的sort()方法),但之后不再调用lessThan方法。我不知道为什么和希望在这里得到一些帮助。如果解决方案所在,我非常乐意考虑如何以不同的方式解决这个问题。

这是我的代理人:

class ProxyModel ( QSortFilterProxyModel ):
    def __init__( self, parent=None ):
        super( ProxyModel, self).__init__( parent )
        self.setFilterCaseSensitivity( Qt.CaseInsensitive )
        self.setSortCaseSensitivity( Qt.CaseInsensitive )
        self.setDynamicSortFilter( True )

    def sortBy( self, attr ):
        print 'sorting by', attr
        self.__sortBy = attr
        self.sort( 0, Qt.AscendingOrder ) # THIS DOES NOT GET CALLED WHEN THE COMBO BOX CHANGES A SECOND TIME

    def lessThan( self, left, right ):
        '''Custom sorting behaviour'''
        leftTool = ( self.sourceModel().itemFromIndex( left ) )
        rightTool = ( self.sourceModel().itemFromIndex( right ) )
        leftData = leftTool.data()[ self.__sortBy ]
        rightData = rightTool.data()[ self.__sortBy ]
        return leftData < rightData

这是完整的测试代码:     导入系统     来自PySide.QtGui进口*     来自PySide.QtCore import *

class MainWidget( QWidget ) :
    def __init__( self, parent=None ):
        super( MainWidget, self ).__init__()

        self.listView = MyListView()
        model = MyModel()

        # MODELS AND VIEWS
        self.proxyModel = ProxyModel()
        self.proxyModel.setSourceModel( model )
        self.listView.setModel(self.proxyModel)

        # LAYOUTS
        verticalLayout = QVBoxLayout()
        filterLayout = QHBoxLayout()

        # SORTING WIDGET
        sortLayout = QHBoxLayout()
        sortLabel = QLabel( 'sort:' )
        self.sortWidget = QComboBox()
        self.sortWidget.addItems( ['title', 'author', 'downloads'] )
        self.sortWidget.currentIndexChanged.connect( self.sortTools )

        sortLayout.addWidget( sortLabel )
        sortLayout.addWidget( self.sortWidget )

        verticalLayout.addLayout( filterLayout )
        verticalLayout.addLayout( sortLayout )
        verticalLayout.insertWidget(0, self.listView)

        self.setLayout( verticalLayout )

    def sortTools( self ):
        text = self.sortWidget.currentText()
        self.proxyModel.sortBy( text )

class ProxyModel ( QSortFilterProxyModel ):
    def __init__( self, parent=None ):
        super( ProxyModel, self).__init__( parent )
        self.setFilterCaseSensitivity( Qt.CaseInsensitive )
        self.setSortCaseSensitivity( Qt.CaseInsensitive )
        self.setDynamicSortFilter( True )

    def sortBy( self, attr ):
        print 'sorting by', attr
        self.__sortBy = attr
        self.sort( 0, Qt.AscendingOrder ) # THIS DOES NOT GET CALLED WHEN THE COMBO BOX CHANGES A SECOND TIME

    def lessThan( self, left, right ):
        '''Custom sorting behaviour'''
        leftTool = ( self.sourceModel().itemFromIndex( left ) )
        rightTool = ( self.sourceModel().itemFromIndex( right ) )
        leftData = leftTool.data()[ self.__sortBy ]
        rightData = rightTool.data()[ self.__sortBy ]
        return leftData < rightData


class MyListView( QListView ):
    def __init__( self, parent=None ):
        super( MyListView, self).__init__( parent )
        self.setEditTriggers( QListView.NoEditTriggers )
        self.setViewMode( QListView.IconMode )
        self.setMovement( QListView.Static )
        self.setResizeMode( QListView.Adjust )
        self.setDragEnabled( True )


class MyModel( QStandardItemModel ):
    def __init__( self, parent=None ):
        super( MyModel, self).__init__( parent )
        self.init_data()

    def init_data(self):
        row = 0
        toolData = [ {'title':'ToolA', 'author':'John Doe', 'downloads':123, 'category':'color'},
                     {'title':'ToolB', 'author':'me', 'downloads':13, 'category':'color'},
                     {'title':'ToolC', 'author':'you', 'downloads':321, 'category':'transform'},
                     {'title':'ToolD', 'author':'unknown', 'downloads':2, 'category':'transform'}]

        for tool in toolData:
            item = QStandardItem( '%(title)s by %(author)s (%(category)s) - %(downloads)s downloads' % tool )
            item.setData( tool )
            self.setItem( row, 0, item )
            row += 1




if __name__ == '__main__':
    app = QApplication( sys.argv )

    mainWidget = MainWidget()
    mainWidget.resize( 400, 400 )
    mainWidget.show()

    sys.exit( app.exec_() )

1 个答案:

答案 0 :(得分:2)

基本上Qt“认为”您的代理已经排序。确切地说,它检查C ++是否:

(d->dynamic_sortfilter && 
 d->proxy_sort_column == column && 
 d->sort_order == order)

因此,要解决您的问题,您可以将dynamic_sortfilter设置为False(它会产生副作用),或者更好的是,使您的排序无效:

def sortBy( self, attr ):
    print 'sorting by', attr
    self.__sortBy = attr
    self.invalidate() #invalidate helps 
    self.sort( 0, Qt.AscendingOrder )