The example demonstrates the use of QSortProxyModel, QStandardItemModel and QTreeView. One standard item model is used to create two views containing the same data. The second view uses a proxy model to allow sorting and filtering. Changes in the second view are not reflected in the first view even though the underlying models are the same.
Part 1 creates the basic GUI.
#!/usr/bin/env python3 # -*- coding: utf-8 -*- ''' PyQt4 conversion of Qt Basic Sort/Filter Example The Basic Sort/Filter Model example illustrates how to use QSortFilterProxyModel to perform basic sorting and filtering. BEHAVIOUR: ========= GUI is laid out. The initial conditions for each widget are in place. Both the case sentivity checkboxes are checked. The Filter Column combobox is set to 'Sender'. NOTES: ===== Create Window class and implement methods to build the GUI (refactored the original C++ to split the creation of the various screen areas up for easier reading.) Create signal/slot connections, adding stub methods for the slots. last modified: 2012-01-30 jg ref: http://developer.qt.nokia.com/doc/qt-4.8/itemviews-basicsortfiltermodel.html ''' from PyQt4.QtGui import (QApplication, QWidget, QGroupBox, QHBoxLayout, QLabel, QVBoxLayout, QGridLayout, QTreeView, QSortFilterProxyModel, QCheckBox, QLineEdit, QComboBox, QStandardItemModel) from PyQt4.QtCore import (Qt, pyqtSlot, QRegExp) class Window(QWidget): def __init__(self, parent=None): # initialise base class super(Window, self).__init__(parent) layout = QVBoxLayout() layout.addWidget(self._createSourcePanel()) layout.addWidget(self._createProxyPanel()) self.setLayout(layout) # private methods --------------------------------------------------------- def _createSourcePanel(self): sourceGroupBox = QGroupBox(self.tr("Original Model")) sourceView = QTreeView() sourceView.setRootIsDecorated(False) sourceView.setAlternatingRowColors(True) sourceLayout = QHBoxLayout() sourceLayout.addWidget(sourceView) sourceGroupBox.setLayout(sourceLayout) return sourceGroupBox def _createProxyPanel(self): proxyGroupBox = QGroupBox(self.tr("Sorted/Filter Model")) proxyView = QTreeView() proxyView.setRootIsDecorated(False) proxyView.setAlternatingRowColors(True) proxyView.sortByColumn(1, Qt.AscendingOrder) proxyModel = QSortFilterProxyModel() proxyModel.setDynamicSortFilter(True) proxyView.setModel(proxyModel) proxyView.setSortingEnabled(True) # click col hdr to sort proxyLayout = QVBoxLayout() proxyLayout.addWidget(proxyView) proxyLayout.addLayout(self._createProxyFilterPanel()) proxyGroupBox.setLayout(proxyLayout) return proxyGroupBox def _createProxyFilterPanel(self): sortCaseSensitivityCheckBox = QCheckBox(self.tr("Case sensitive sorting")); sortCaseSensitivityCheckBox.setChecked(True) filterCaseSensitivityCheckBox = QCheckBox(self.tr("Case sensitive filter")); filterCaseSensitivityCheckBox.setChecked(True) filterPatternLineEdit = QLineEdit(); filterPatternLabel = QLabel(self.tr("&Filter pattern:")); filterPatternLabel.setBuddy(filterPatternLineEdit); filterSyntaxComboBox = QComboBox(); filterSyntaxComboBox.addItem(self.tr("Regular expression"), QRegExp.RegExp); filterSyntaxComboBox.addItem(self.tr("Wildcard"), QRegExp.Wildcard); filterSyntaxComboBox.addItem(self.tr("Fixed string"), QRegExp.FixedString); filterSyntaxLabel = QLabel(self.tr("Filter &syntax:")); filterSyntaxLabel.setBuddy(filterSyntaxComboBox); filterColumnComboBox = QComboBox(); filterColumnComboBox.addItem(self.tr("Subject")); filterColumnComboBox.addItem(self.tr("Sender")); filterColumnComboBox.addItem(self.tr("Date")); filterColumnComboBox.setCurrentIndex(1) filterColumnLabel = QLabel(self.tr("Filter &column:")); filterColumnLabel.setBuddy(filterColumnComboBox); # connect signals/slots for event handling filterPatternLineEdit.textChanged.connect(self._filterRegExpChanged) filterSyntaxComboBox.currentIndexChanged.connect(self._filterRegExpChanged) filterColumnComboBox.currentIndexChanged.connect(self._filterColumnChanged) filterCaseSensitivityCheckBox.toggled.connect(self._filterRegExpChanged) sortCaseSensitivityCheckBox.toggled.connect(self._sortChanged) grid = QGridLayout() grid.addWidget(filterPatternLabel, 0, 0) grid.addWidget(filterPatternLineEdit, 0, 1) grid.addWidget(filterSyntaxLabel, 1, 0) grid.addWidget(filterSyntaxComboBox, 1, 1) grid.addWidget(filterColumnLabel, 2, 0) grid.addWidget(filterColumnComboBox, 2, 1) grid.addWidget(filterCaseSensitivityCheckBox, 3, 0) grid.addWidget(sortCaseSensitivityCheckBox, 3, 1, Qt.AlignRight) return grid # private slots ----------------------------------------------------------- @pyqtSlot() def _filterRegExpChanged(self): pass @pyqtSlot() def _filterColumnChanged(self): pass @pyqtSlot() def _sortChanged(self): pass # main ======================================================================== def main(): import sys app = QApplication(sys.argv) mw = Window() mw.setWindowTitle("Basic Sort/Filter Model - Part 1") mw.resize(500, 450) mw.show() sys.exit(app.exec_()) if __name__ == '__main__': main()