首页 > 解决方案 > 检测 QTreeView 图标上的点击

问题描述

我有一个QTreeView,其中一些项目用图标装饰。这些项目可以在 TreeView 的任何列中。

我想知道如何检测鼠标点击图标。我可以使用视图的mousePressEvent()来检测鼠标按下,我可以通过使用Qt.DecorationRole调用模型的data()方法来检查单击的项目中是否存在图标,以查看是否返回一个空的QVariant,并且我可以使用视图的iconSize()方法查询图标的大小。但我无法知道项目的视觉矩形内图标的坐标。

PS。其他与 QTreeView 装饰有关的 SO 问题通常是指树折叠展开图标,与此问题无关。

标签: pythonqtpyqtqtreeview

解决方案


逻辑是有2个数据:

  • 鼠标点击的位置,可以在delegate的editorEvent方法中获取。
  • 使用 StyleOptionViewItem 和用于绘画的 QStyle 获得的图标的位置。
from PyQt5 import QtCore, QtGui, QtWidgets


class Delegate(QtWidgets.QStyledItemDelegate):
    def editorEvent(self, event, model, option, index):
        ret = super().editorEvent(event, model, option, index)
        if event.type() == QtCore.QEvent.MouseButtonPress:
            self.initStyleOption(option, index)
            widget = option.widget
            style = (
                widget.style() if widget is not None else QtWidgets.QApplication.style()
            )
            icon_rect = style.subElementRect(
                QtWidgets.QStyle.SE_ItemViewItemDecoration, option, widget
            )
            if icon_rect.contains(event.pos()):
                print("icon clicked")
        return ret


def main():
    app = QtWidgets.QApplication([])
    pixmap = QtGui.QPixmap(128, 128)
    pixmap.fill(QtCore.Qt.green)
    icon = QtGui.QIcon(pixmap)
    model = QtGui.QStandardItemModel()
    for i in range(5):
        item = QtGui.QStandardItem(f"item-{i}")
        item.setIcon(icon)
        item.setEditable(False)
        model.appendRow(item)
        for j in range(6):
            child_item = QtGui.QStandardItem(f"item {i}{j}")
            child_item.setIcon(icon)
            child_item.setEditable(False)
            item.appendRow(child_item)
    w = QtWidgets.QTreeView()
    w.setModel(model)
    w.expandAll()
    delegate = Delegate(w)
    w.setItemDelegate(delegate)
    w.resize(640, 480)
    w.show()
    app.exec_()


if __name__ == "__main__":
    main()

推荐阅读