QListView.indexAt 在 PyQt5 中返回错误的索引?

QListView.indexAt in PyQt5 returning wrong index?

我试图在用户右键单击 QListView 中的项目时弹出上下文菜单,如果用户在任何项目之外(任何空白处)右键单击则弹出不同的上下文菜单.我发现我在执行 indexAt 命令时收到的索引不准确,我不知道为什么。

我将 QListView 初始化为它自己的 class:

class RBKDataTypesTab(QWidget):
    def __init__(self):
        super().__init__()
        self.models = []
        grid = QGridLayout()
        self.list = QListView()
        self.list.clicked.connect(self.list_item_selected)
        grid.addWidget(self.list, 0, 0, -1, 8)
        self.table = QTableView()
        self.indexMenu = QMenu()
        self.indexMenu.addAction('Add DataType', self.addDataType)
        self.indexMenu.addAction('Remove DataType', self.removeDataType)
        self.nonIndexMenu = QMenu()
        self.nonIndexMenu.addAction('Add DataType', self.addDataType)
        grid.addWidget(self.table, 0, 2, -1, -1)
        self.setLayout(grid)

此时,列表为空。当打开文件以设置模型时,我还有其他功能,它将数据加载到屏幕上。

这是我的上下文菜单事件:

def contextMenuEvent(self, event):
    index = self.list.indexAt(event.pos())
    print(index.data())
    if(index.isValid()):
        event.accept()
        self.indexMenu.exec_(event.globalPos())
    else:
        event.accept()
        self.nonIndexMenu.exec_(event.globalPos())

假设我有三个通用项目:

感谢 print 语句,我可以知道当我单击 QListView 中 item1 的顶部 1/4 时,它正在返回 item1。但是,如果我单击 item1 的底部 3/4,它将返回 item2。 item2 和 item3 的逻辑相同,只有 item3 的底部 3/4 returns None,因此返回错误的上下文菜单。

谁能帮我理解为什么会这样?我认为它与 event.pos() 有关,但我不知道是什么。

谢谢!!

event.pos() 的坐标是相对于拥有 contextMenuEvent() 方法的小部件而言的,在您的情况下它是相对于 window 但 indexAt() 方法需要相对于视图 (QListView) 的 viewport() 的坐标,因此您必须使用 mapFromGlobal() 方法进行转换:

def contextMenuEvent(self, event):
    gp = event.globalPos()
    lp = self.list.viewport().mapFromGlobal(gp)
    index = self.list.indexAt(lp)
    if index.isValid():
        self.indexMenu.exec_(gp)
    else:
        self.nonIndexMenu.exec_(gp)