pyqt qt4 QTableView如何禁用某些列的排序? [英] pyqt qt4 QTableView how to disable sorting for certain columns?
问题描述
所以我有一个QTableView,我只想让列在第1列而不是在column2上进行排序.
So I have a QTableView and I only want to let column sorting on column 1 but not column2.
自然,我尝试在QHeaderView
或QTableView
上使用installEventFilter
,但是除非您在QApplication
上使用installEventFilter
Naturally I tried to installEventFilter
on QHeaderView
or QTableView
, but MouseButtonPress
event is not being passed unless you installEventFilter
on QApplication
现在,如果调用eventFilter
时,则目标object
始终是顶级窗口小部件,尽管event.pos()
实际上是相对于标题或表单元格的,具体取决于您单击的位置.
Now if when eventFilter
is called, the target object
is always the top level widget although event.pos()
is actually relative to the header or tablecell depending on where you click.
因此,我们无法使用QHeaderView.rect().contains(event.pos())
来确定用户是否单击标题,因为单击第一个表格单元格的顶部边缘时您会得到误报.
So we cannot use QHeaderView.rect().contains(event.pos())
to find out if the user clicks on the header because you get false positive when you click on the top edge of the very first table cell.
不过,您仍然可以使用globalPos进行计算,但是当您更改布局或在表格视图上方添加更多小部件时,eventFilter的逻辑必须更改.
You can still however calculate this using globalPos but then your eventFilter's logic has to change when you change layout or add more widgets above the tableview.
我相信event.pos()返回相对pos是一个错误,即使object
参数始终引用相同的顶级小部件.
I believe it is a bug that event.pos() returns the relative pos even the object
argument always refer to the same top level widget.
更合乎逻辑的API是,有一个event.target()方法可返回目标,以在此目标中计算相对位置.
A more logical API would be that there is a event.target() method to return the target where it calculates the relative pos.
但是我没有看到target()方法或在此事件过滤器中找到目标的方法.
But I don't see a target() method or a way to find the target in this event filter.
也许我想念什么?
# -*- 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_())
推荐答案
There's a much easier solution: reimplement the sort method of the model, and only permit sorting for the appropriate column.
此外,作为一种改进,请使用 sortIndicatorChanged 标头的信号,以在适当时恢复当前的排序指示器.
Also, as an added refinement, use the sortIndicatorChanged signal of the header to restore the current sort indicator when appropriate.
这是一个演示脚本:
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_())
这篇关于pyqt qt4 QTableView如何禁用某些列的排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!