сортировка по 2-му столбца должна происходить только тогда, когда значения первого сортируемого столбца равны
Работающий, немного избыточный код (извини) приведён ниже.
Основная идея в следующем:
Представь, что в каждой ячейке строки записано по одной цифре от 0 до 9.
Тогда каждая строка таблицы соответствует какому либо числу и сортировка строк сводится к сортировке чисел.
Для сортировки единственное, что нам надо, так это указать для любых двух строк их порядок
(функция def lessThan(self, leftIndex, rightIndex)). Для простоты реализации будем работать в двоичной системе представления.
Делаем следующее:
для двух произвольных строк сравниваем их ячейки принадлежащие одному столбцу
и определяем какая из ячеек больше (меньше) и записываем в ту ячейку либо 1 либо 0 (соответственно в другую ячейку записываем либо 0 либо 1). Если значения в ячейках равны то в обе ячейки записываем по 1.
Python
leftRow = sourceData[leftIndex.row() ][leftIndex.column(): ]
rightRow = sourceData[rightIndex.row()][rightIndex.column():]
xLeft = map( op.truth, map( op.le , leftRow, rightRow))
xRight = map( op.truth, map( op.ge , leftRow, rightRow))
соответственно интерпретируя полученные 0 и 1 как двоичную запись числа соответствующего строке
для определения порядка строк вычисляем значения чисел и сравниваем их величины
Python
return reduce(lambda x, y: 2*x+y, xLeft) < reduce(lambda x, y: 2*x+y, xRight)
Python
#!/usr/bin/env python
## -*- coding: utf-8 -*-
import sys
import operator as op
from PyQt4 import QtGui, QtCore
class TableModel (QtCore.QAbstractTableModel):
def __init__ (self, data, header, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.data = data
self.header = header
def rowCount (self, parent=QtCore.QModelIndex()):
return len(self.data)
def columnCount (self, parent = QtCore.QModelIndex()):
if len(self.data) != 0:
return len(self.data[0])
else:
return 0
def data (self, index, role = QtCore.Qt.DisplayRole):
if index.isValid() or not 0 <= index.row() < self.rowCount():
data = self.data[index.row()][index.column()]
if role == QtCore.Qt.DisplayRole:
return str(data)
elif role == QtCore.Qt.EditRole:
return str(data)
return QtCore.QVariant()
def flags (self, index):
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
def setData (self, index, value, role):
if index.isValid() and role == QtCore.Qt.EditRole:
value_int, ok = value.toInt()
if ok:
self.data[index.row()][index.column()] = value_int
self.dataChanged.emit(index, index)
return True
return False
def sort(self, Ncol, order): # Не пременимо для QSortFilterProxyModel
"""Sort table by given column number.
"""
self.emit(QtCore.SIGNAL("layoutAboutToBeChanged()"))
self.data = sorted(self.data, key = lambda x: x[Ncol:] )
if order == QtCore.Qt.DescendingOrder:
self.data.reverse()
self.emit(QtCore.SIGNAL("layoutChanged()"))
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole and section < len(self.header):
return QtCore.QVariant(self.header[section])
else:
return QtCore.QVariant()
def setHeaderData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole and section < len(self.header):
self.emit(QtCore.SIGNAL('headerDataChanged()'))
return QtCore.QVariant(self.header[section])
else:
return QtCore.QVariant()
def insertRows(self, position, rows, parent=QtCore.QModelIndex()):
self.beginInsertRows(parent, position, position + rows - 1)
for row in range(0, rows):
self.data.insert(position + row, self.row_data[row])
self.endInsertRows()
def removeRows(self, position, rows, parent=QtCore.QModelIndex()):
self.beginRemoveRows(parent, position, position + rows - 1)
del self.data[position:position + rows]
self.endRemoveRows()
def insertColumns(self, position, columns, parent=QtCore.QModelIndex()):
self.beginInsertColumns(parent, position, position + columns - 1)
for row in range(0, self.rowCount(parent=QtCore.QModelIndex())):
for column in range(0, columns):
self.data[row].insert(position + column, self.column_data[row][column])
self.endInsertColumns()
def removeColumns(self, position, columns, parent=QtCore.QModelIndex()):
self.beginRemoveColumns(parent, position, position + columns - 1)
for row in range(0, self.rowCount(parent=QtCore.QModelIndex())):
del self.data[row][position:position + columns]
self.endRemoveColumns()
class HeaderTableModel (TableModel):
def __init__ (self, data, header, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.data = data
self.header = header
def flags (self, index):
if not index.isValid():
return QtCore.Qt.ItemIsEnabled
elif index.row() > 1:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def setData (self, index, value, role):
if index.isValid() and role == QtCore.Qt.EditRole:
value_int, ok = value.toInt()
if ok:
self.data[index.row()][index.column()] = value_int
self.dataChanged.emit(index, index)
self.emit(QtCore.SIGNAL('minmaxValueChange()'))
print "SIGNAL Emited"
return True
return False
class ProxyModel(QtGui.QSortFilterProxyModel):
def __init__( self, parent=None ):
super( ProxyModel, self).__init__( parent )
self.setDynamicSortFilter( True )
self.setSortRole(2) # 6 - double
def lessThan(self, leftIndex, rightIndex):
sourceModel = self.sourceModel()
sourceData = sourceModel.data
leftRow = sourceData[leftIndex.row() ][leftIndex.column(): ]
rightRow = sourceData[rightIndex.row()][rightIndex.column():]
xLeft = map( op.truth, map( op.le , leftRow, rightRow))
xRight = map( op.truth, map( op.ge , leftRow, rightRow))
return reduce(lambda x, y: 2*x+y, xLeft) < reduce(lambda x, y: 2*x+y, xRight)
def filterAcceptsRow(self, sourceRow, sourceParent):
sourceModel = self.sourceModel()
sourceData = sourceModel.data
xVal = [ sourceData[sourceRow][i] for i in self.list[0] ]
xMax = self.list[1]
xMin = self.list[2]
print "filterAcceptsRow", xVal, self.list, op.and_(op.le(xVal, xMax), op.ge(xVal, xMin))
return op.and_(op.le(xVal, xMax), op.ge(xVal, xMin))
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
header = ['Col0', 'Col1', 'Col2', 'Col3'] # Заголовки столбцов
data = [
[0, 1, 3, 1],
[0, 1, 2, 3],
[1, 3, 1, 2],
[1, 2, 4, 4],
[2, 3, 3, 6],
[2, 5, 3, 5],
[3, 1, 3, 1],
[3, 4, 5, 6]
]
sortModel = TableModel( data, header )
self.connect(sortModel, QtCore.SIGNAL('minmaxValueChange()'), self.myPrint)
proxy = ProxyModel()
proxy.dataValue = data
proxy.list = [[0], [ 6 ], [ 0 ]]
proxy.list = [ [0, 1, 3], [5, 5, 5], [2, 2, 2]]
proxy.setSourceModel(sortModel)
proxy.setDynamicSortFilter(True)
sortView = QtGui.QTableView()
sortView.setModel(proxy)
sortView.setSortingEnabled(True)
layout = QtGui.QVBoxLayout()
layout.addWidget(sortView)
self.setLayout(layout)
def myPrint(self):
print "pass the edit of min max value"
app = QtGui.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())