Pyqt qt4 QTableView how to disable sorting for specific columns?

So, I have a QTableView, and I want to enable sorting of columns in column 1, but not in column2.

Naturally, I tried installEventFilteron QHeaderViewor QTableView, but the event is MouseButtonPressnot transmitted if you are not installEventFilteronQApplication

Now, if called eventFilter, the target is objectalways a top-level widget, although it event.pos()actually refers to the header or table, depending on where you click.

Therefore, we can’t use QHeaderView.rect().contains(event.pos())it to find out if the user clicks the header because you get a false positive when you click on the top edge of the very first cell of the table.

However, you can calculate this using globalPos, but then your eventFilter logic should change when you change the layout or add more widgets above the table view.

I believe that this is an error that event.pos () returns relative pos, even the argument objectalways refers to the same top-level view.

A more logical API would be that there is an event.target () method to return the target, where it computes the relative pos.

But I do not see the target () method or the way to find the target in this event filter.

Maybe something is missing for me?

# -*- coding: utf-8 -*-
# pyqt windows 4.10.3
# python 2.7.5 32 bits
from PyQt4.QtCore import *
from PyQt4.QtGui import *

app = None
tableHeader = None

class MyModel(QAbstractTableModel):
    def rowCount(self, QModelIndex_parent=None, *args, **kwargs):
        return 2

    def columnCount(self, QModelIndex_parent=None, *args, **kwargs):
        return 2

    def data(self, modelIndex, role=None):
        if modelIndex.isValid():
            row = modelIndex.row()
            col = modelIndex.column()
            if role == Qt.DisplayRole:
                return "%02d,%02d" % (row, col)

    def flags(self, index):
        if index.isValid():
            return Qt.ItemIsEnabled

    def headerData(self, section, Qt_Orientation, role=None):
        if role == Qt.DisplayRole and Qt_Orientation == Qt.Horizontal:
            return "Column " + str(section+1)

class MyEventFilter(QObject):
    def eventFilter(self, object, event):
        if event.type() == QEvent.MouseButtonPress:
            # object is always app/top level widget
            print 'MouseButtonPress target :' + repr(object)
            # even though event.pos() gives pos relative to the header when you click on header,
            # and pos relative to table cells when you click on table cell
            print repr(event.pos())
            # however we can get the mouse global position
            print repr(event.globalPos())
            # given the top level widget geometry
            print repr(app.activeWindow().geometry())
            # and the table header left, top and height
            print repr(tableHeader.rect())
            # we can find out whether mouse click is targeted at the header
            print repr(event.globalPos().y() - app.activeWindow().geometry().y())
            # BUT WHAT IF THE LAYOUT CHANGE OR WE ADD MORE WIDGETS ABOVE THE TABLEVIEW?
            # WE HAVE TO ADJUST THE CALCULATION ABOVE!
        return False


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    w = QMainWindow()
    t = QTableView()
    tableHeader = t.horizontalHeader()
    t.setModel(MyModel())
    w.setCentralWidget(t)
    ef = MyEventFilter()
    # installing in QMainWindow or QTableView won't catch MouseButtonPress
    # https://qt-project.org/forums/viewthread/9347
    #w.installEventFilter(ef)
    #t.installEventFilter(ef)
    app.installEventFilter(ef)
    w.show()
    sys.exit(app.exec_())
+4
source share
1 answer

: sort .

, sortIndicatorChanged , , .

script:

from PyQt4 import QtGui, QtCore

class TableModel(QtGui.QStandardItemModel):
    _sort_order = QtCore.Qt.AscendingOrder

    def sortOrder(self):
        return self._sort_order

    def sort(self, column, order):
        if column == 0:
            self._sort_order = order
            QtGui.QStandardItemModel.sort(self, column, order)

class Window(QtGui.QWidget):
    def __init__(self, rows, columns):
        QtGui.QWidget.__init__(self)
        self.table = QtGui.QTableView(self)
        model = TableModel(rows, columns, self.table)
        for row in range(rows):
            for column in range(columns):
                item = QtGui.QStandardItem('(%d, %d)' % (row, column))
                item.setTextAlignment(QtCore.Qt.AlignCenter)
                model.setItem(row, column, item)
        self.table.setModel(model)
        self.table.setSortingEnabled(True)
        self.table.horizontalHeader().sortIndicatorChanged.connect(
            self.handleSortIndicatorChanged)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.table)

    def handleSortIndicatorChanged(self, index, order):
        if index != 0:
            self.table.horizontalHeader().setSortIndicator(
                0, self.table.model().sortOrder())

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window(5, 5)
    window.show()
    window.setGeometry(600, 300, 600, 250)
    sys.exit(app.exec_())
+5

All Articles