Qtableview indexAt 不同的行为 with/without header

Qt TableView indexAt different behaviour with/without header

使用 PySide 1.2

QTableView returns 中抓取点击项目的索引,无论是否存在水平 header 都会产生不同的结果。 如果有横的header,好像也算在visualRect里面了。所以第一行第一列索引不再是 0, 0 而是 1, 0.

这是故意的吗?因为它真的很混乱和不方便,因为最后一行索引将无效。

重现:

import re
import operator
import os
import sys 
# from Qt.QtCore import * 
# from Qt.QtGui import * 
# from Qt.QtWidgets import * 
from PySide.QtCore import * 
from PySide.QtGui import * 


def main(): 
    app = QApplication(sys.argv) 
    w = MyWindow() 
    w.show() 
    sys.exit(app.exec_()) 


class CustomTableView(QTableView):
    """
    """

    def __init__(self, parent=None):
        """
        """
        super(CustomTableView, self).__init__(parent=parent)

    def mousePressEvent(self, mouse_event):
        """
        """
        view_pos = self.mapFromGlobal(mouse_event.globalPos())
        index = self.indexAt(view_pos)
        print('mouse press index not  cutting header : ' + str((index.row(), index.column())))
        view_pos.setY(view_pos.y() - self.horizontalHeader().sizeHint().height())
        index = self.indexAt(view_pos)
        print('mouse press index cutting header : ' + str((index.row(), index.column())))
        super(CustomTableView, self).mousePressEvent(mouse_event)


class MyWindow(QWidget): 
    def __init__(self, *args): 
        QWidget.__init__(self, *args) 

        # create table
        self.get_table_data()
        table = self.createTable() 

        # layout
        layout = QVBoxLayout()
        layout.addWidget(table) 
        self.setLayout(layout) 

    def get_table_data(self):
        stdouterr = os.popen4("dir c:\")[1].read()
        lines = stdouterr.splitlines()
        lines = lines[5:]
        lines = lines[:-2]
        self.tabledata = [re.split(r"\s+", line, 4)
                     for line in lines]

    def createTable(self):
        # create the view
        tv = CustomTableView()

        # set the table model
        header = ['date', 'time', '', 'size', 'filename']
        tm = MyTableModel(self.tabledata, header, self) 
        tv.setModel(tm)
        return tv

class MyTableModel(QAbstractTableModel): 
    def __init__(self, datain, headerdata, parent=None, *args): 
        """ datain: a list of lists
            headerdata: a list of strings
        """
        QAbstractTableModel.__init__(self, parent, *args) 
        self.arraydata = datain
        self.headerdata = headerdata

    def rowCount(self, parent): 
        return len(self.arraydata)

    def columnCount(self, parent): 
        return len(self.arraydata[0]) 

    def data(self, index, role): 
        if not index.isValid(): 
            return None 
        elif role != Qt.DisplayRole: 
            return None 
        return self.arraydata[index.row()][index.column()]

    def headerData(self, col, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.headerdata[col]
        return None

if __name__ == "__main__": 
    main()

您不必使用全局位置然后将其传递给本地位置,因为您将获得相对于 QTableView 上角的位置,但 indexAt 需要相对于内容的位置根据docs:

PySide.QtGui.QAbstractItemView.indexAt(point)

Parameters: point – PySide.QtCore.QPoint

Return type: PySide.QtCore.QModelIndex

Returns the model index of the item at the viewport coordinates point.

您必须使用事件的位置:mouse_event.pos()

def mousePressEvent(self, mouse_event):
    index = self.indexAt(mouse_event.pos())
    print('mouse press index: ' + str((index.row(), index.column())))
    super(CustomTableView, self).mousePressEvent(mouse_event)

如果要使用全局位置,则必须将其转换为相对于 viewport():

的本地位置
def mousePressEvent(self, mouse_event):
    view_pos = self.viewport().mapFromGlobal(mouse_event.globalPos())
    index = self.indexAt(view_pos)
    print('mouse press index : ' + str((index.row(), index.column())))
    super(CustomTableView, self).mousePressEvent(mouse_event)