【问题标题】:pyqt qt4 QTableView how to disable sorting for certain columns?pyqt qt4 QTableView 如何禁用某些列的排序?
【发布时间】:2014-02-23 20:14:10
【问题描述】:

所以我有一个 QTableView,我只想让列排序在第 1 列而不是第 2 列。

当然,我尝试在QHeaderViewQTableViewinstallEventFilter,但除非您在QApplicationinstallEventFilter,否则MouseButtonPress 事件不会被传递

现在,如果在调用 eventFilter 时,目标 object 始终是顶级小部件,尽管 event.pos() 实际上与标题或表格单元格相关,具体取决于您单击的位置。

所以我们不能使用QHeaderView.rect().contains(event.pos()) 来判断用户是否点击了标题,因为当您点击第一个表格单元格的顶部边缘时会出现误报。

但是,您仍然可以使用 globalPos 进行计算,但是当您更改布局或在 tableview 上方添加更多小部件时,您的 eventFilter 的逻辑必须更改。

我认为 event.pos() 返回相对位置是一个错误,即使 object 参数总是引用同一个顶级小部件。

更合乎逻辑的 API 是有一个 event.target() 方法来返回它计算相对位置的目标。

但我没有看到 target() 方法或在此事件过滤器中找到目标的方法。

也许我错过了什么?

# -*- 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's global position
            print repr(event.globalPos())
            # given the top level widget's geometry
            print repr(app.activeWindow().geometry())
            # and the table header's 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_())

【问题讨论】:

    标签: qt pyqt pyqt4 qtableview qt4.8


    【解决方案1】:

    有一个更简单的解决方案:重新实现模型的sort 方法,并且只允许对适当的列进行排序。

    另外,作为一个额外的改进,在适当的时候使用标题的sortIndicatorChanged 信号来恢复当前的排序指示符。

    这是一个演示脚本:

    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_())
    

    【讨论】:

    • 这适用于我的目的。 thx 我仍然觉得 Qt API 很奇怪,它们给出了相对位置,但是没有简单的方法来找出对象是什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2019-03-11
    • 2019-01-24
    相关资源
    最近更新 更多