所以我有一个QTableView,我只想让第一列可以排序,而第二列不行。
自然地,我尝试在QHeaderView或QTableView上安装EventFilter,但MouseButtonPress事件除非你在QApplication上安装EventFilter,否则不会被传递。
现在,当eventFilter被调用时,目标对象始终是顶层小部件,尽管event.pos()实际上是相对于头部或单元格的,具体取决于您单击的位置。
因此,我们无法使用QHeaderView.rect().contains(event.pos())来找出用户是否单击了标题,因为当您单击第一个表格单元格的顶部边缘时,您会得到错误的结果。
但是,仍然可以使用globalPos进行计算,但是当您更改布局或在tableview上方添加更多小部件时,您的eventFilter逻辑必须更改。
我认为event.pos()返回相对pos即使object参数总是引用相同的顶级小部件是一个bug。
更合理的API应该是有一个event.target()方法来返回计算相对pos的目标。
但是我没有看到target()方法或者在这个event filter中找到目标的方法。
也许我漏掉了什么?
自然地,我尝试在QHeaderView或QTableView上安装EventFilter,但MouseButtonPress事件除非你在QApplication上安装EventFilter,否则不会被传递。
现在,当eventFilter被调用时,目标对象始终是顶层小部件,尽管event.pos()实际上是相对于头部或单元格的,具体取决于您单击的位置。
因此,我们无法使用QHeaderView.rect().contains(event.pos())来找出用户是否单击了标题,因为当您单击第一个表格单元格的顶部边缘时,您会得到错误的结果。
但是,仍然可以使用globalPos进行计算,但是当您更改布局或在tableview上方添加更多小部件时,您的eventFilter逻辑必须更改。
我认为event.pos()返回相对pos即使object参数总是引用相同的顶级小部件是一个bug。
更合理的API应该是有一个event.target()方法来返回计算相对pos的目标。
但是我没有看到target()方法或者在这个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_())