pyqt qt4 QTableView 如何禁用某些列的排序?
Posted
技术标签:
【中文标题】pyqt qt4 QTableView 如何禁用某些列的排序?【英文标题】:pyqt qt4 QTableView how to disable sorting for certain columns? 【发布时间】:2014-02-23 20:14:10 【问题描述】:所以我有一个 QTableView,我只想让列排序在第 1 列而不是第 2 列。
当然,我尝试在QHeaderView
或QTableView
上installEventFilter
,但除非您在QApplication
上installEventFilter
,否则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_())
【问题讨论】:
【参考方案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 很奇怪,它们给出了相对位置,但是没有简单的方法来找出对象是什么以上是关于pyqt qt4 QTableView 如何禁用某些列的排序?的主要内容,如果未能解决你的问题,请参考以下文章
PyQt5 QTableView:如何在保持默认样式/颜色的同时禁用用户交互/选择?
如何在 Qt4 及更高版本中对 QTableView 进行排序
PyQt4 - QTableView - 如何循环 QTableView