栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

QGraphicsItemGroup event处理

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

QGraphicsItemGroup event处理

# 参考网上的一篇文章, 自已写的例子.
# 解决 QGraphicsItemGroup 不能向他的子 item 传递事件的问题,
# 要改的,并不是 group层的代码,而是他子类的函数:sceneEvent
# setfilterschildevents 并不是这个问题的关键,sethandleschildevents 已经 obsolete , 所以都没用.
# 本例中 有一个 proxy widget的按钮, 在此模式下,可以正常工作.

# 有三种方式可以重载 sceneEvent,
# 1. 派生一个子类, 这里就不做测试了.
# 2. 把原类的函数更改掉. 因为 pyqt 是 qt的python 包装, 并不是 built-in , 所以这种方法,可以实行.
# 3. 更改子类的方法.

# 要注意的是, 方法 2 和方法 3 在实行时, 函数的写法不同. 方法3, 实际上,就是 一个装饰器.
# 方法2 在更改时, 对原代码的影响最小, 但可能是给自己挖坑..
# 方法3 要对每一个实例进行更改, 实际上, 操作可能有些困难, 别的一些写好的函数内部调用时,可能无法实行.
# 具体 选哪种方式, 见仁见智吧.


# python 3.8 , pyqt 5.15

from typing import Callable
from PyQt5 import QtWidgets as qw, QtCore as qc, QtGui as qg
import sys
import numpy as np


# 通过改变类的函数,来重载 event
def change_type_event():
    def mouseReleaseEvent(
        self: qw.QGraphicsItem, event: "qw.QGraphicsSceneMouseEvent"
    ) -> None:
        print("mouseReleaseEvent", type(self))
        if not isinstance(self, qw.QGraphicsProxyWidget):
            self.setPen(self._base_pen)
        return self._mouseReleaseEvent(self, event)

    def mousePressEvent(
        self: qw.QGraphicsItem, event: "qw.QGraphicsSceneMouseEvent"
    ) -> None:
        event.accept()
        print("mousePressEvent", type(self))
        if not isinstance(self, qw.QGraphicsProxyWidget):
            self._base_pen = self.pen()
            p = qg.QPen()
            p.setColor(qg.QColor(255, 0, 0))
            p.setWidth(self.pen().width())
            self.setPen(p)
        return self._mousePressEvent(self, event)

    def sceneEvent(self: qw.QGraphicsItem, event: qc.QEvent):
        event.accept()
        # 有可能会漏了一部分事件的触发
        if isinstance(event, qw.QGraphicsSceneMouseEvent):
            if event.type() == 155:
                self.mouseMoveEvent(event)
            elif event.type() == 156:
                self.mousePressEvent(event)
            elif event.type() == 157:
                self.mouseReleaseEvent(event)
            elif event.type() == 158:
                self.mouseDoubleClickEvent(event)
            else:
                print("other ", event.type())
        elif isinstance(event, qw.QGraphicsSceneContextMenuEvent):
            print(type(self), type(event), event.type())
            self.contextMenuEvent(event)
        else:
            self._sceneEvent(self, event)
        return True

    types = [
        qw.QGraphicsLineItem,
        qw.QGraphicsPathItem,
        qw.QGraphicsPolygonItem,
        qw.QGraphicsRectItem,
        qw.QGraphicsProxyWidget,
        qw.QGraphicsEllipseItem,
    ]

    for tp in types:
        assert not hasattr(tp, "_mousePressEvent")
        tp._mousePressEvent = tp.mousePressEvent
        tp.mousePressEvent = mousePressEvent

        assert not hasattr(tp, "_mouseReleaseEvent")
        tp._mouseReleaseEvent = tp.mouseReleaseEvent
        tp.mouseReleaseEvent = mouseReleaseEvent

        assert not hasattr(tp, "_sceneEvent")
        tp._sceneEvent = tp.sceneEvent
        tp.sceneEvent = sceneEvent


def change_event_item(obj: qw.QGraphicsItem):
    def mouseReleaseEvent(event: "qw.QGraphicsSceneMouseEvent") -> None:
        print("mouseReleaseEvent", type(obj))
        if not isinstance(obj, qw.QGraphicsProxyWidget):
            obj.setPen(obj._base_pen)
        return obj._mouseReleaseEvent(event)

    def mousePressEvent(event: "qw.QGraphicsSceneMouseEvent") -> None:
        event.accept()
        print("mousePressEvent", type(obj))
        if not isinstance(obj, qw.QGraphicsProxyWidget):
            obj._base_pen = obj.pen()
            p = qg.QPen()
            p.setColor(qg.QColor(255, 0, 0))
            p.setWidth(obj.pen().width())
            obj.setPen(p)
        return obj._mousePressEvent(event)

    def sceneEvent(event: qc.QEvent):
        event.accept()
        # 有可能会漏了一部分事件的触发
        if isinstance(event, qw.QGraphicsSceneMouseEvent):
            if event.type() == 155:
                obj.mouseMoveEvent(event)
            elif event.type() == 156:
                obj.mousePressEvent(event)
            elif event.type() == 157:
                obj.mouseReleaseEvent(event)
            elif event.type() == 158:
                obj.mouseDoubleClickEvent(event)
            else:
                print("other ", event.type())
        elif isinstance(event, qw.QGraphicsSceneContextMenuEvent):
            print(type(obj), type(event), event.type())
            obj.contextMenuEvent(event)
        else:
            obj._sceneEvent(event)
        return True

    assert not hasattr(obj, "_mousePressEvent")
    obj._mousePressEvent = obj.mousePressEvent
    obj.mousePressEvent = mousePressEvent

    assert not hasattr(obj, "_mouseReleaseEvent")
    obj._mouseReleaseEvent = obj.mouseReleaseEvent
    obj.mouseReleaseEvent = mouseReleaseEvent

    assert not hasattr(obj, "_sceneEvent")
    obj._sceneEvent = obj.sceneEvent
    obj.sceneEvent = sceneEvent

    return obj


if __name__ == "__main__":

    def make_items(obj_wraper: Callable = None):

        flag1 = qw.QGraphicsItem.GraphicsItemFlag.ItemIsMovable
        flag2 = qw.QGraphicsItem.GraphicsItemFlag.ItemIsSelectable

        scene = qw.QGraphicsScene()
        scene.setBackgroundBrush(qg.QColor(qg.QColor().red()))

        pen = qg.QPen()
        pen.setColor(qg.QColor(0, 160, 230))
        pen.setWidth(10)

        m_rectItem = qw.QGraphicsRectItem()
        m_rectItem.setRect(0, 0, 80, 80)
        m_rectItem.setPen(pen)
        m_rectItem.setBrush(qg.QBrush(qg.QColor(255, 0, 255)))
        m_rectItem.setFlag(flag1)
        m_rectItem.setFlag(flag2)

        bt = qw.QPushButton()
        bt_p = qw.QGraphicsProxyWidget()
        bt_p.setWidget(bt)

        def on_bt_click(event):
            print("clicked")

        bt.clicked.connect(on_bt_click)
        m_lineItem = qw.QGraphicsLineItem()
        m_lineItem.setLine(qc.QLineF(0, 0, 100, 100))
        m_lineItem.setPen(pen)
        m_lineItem.setFlag(flag1)
        m_lineItem.setFlag(flag2)

        m_pathItem = qw.QGraphicsPathItem()

        path = qg.QPainterPath()
        path.moveTo(90, 50)
        for i in range(1, 5):
            path.lineTo(
                50 + 40 * np.cos(0.8 * i * np.pi), 50 + 40 * np.sin(0.8 * i * np.pi)
            )

        path.closeSubpath()
        m_pathItem.setPath(path)
        m_pathItem.setPen(pen)
        m_pathItem.setFlag(flag1)
        m_pathItem.setFlag(flag2)

        m_polygonItem = qw.QGraphicsPolygonItem()
        polygon = qg.QPolygonF()
        polygon.append(qc.QPointF(-100.0, -150.0))
        polygon.append(qc.QPointF(-120.0, 150.0))
        polygon.append(qc.QPointF(320.0, 160.0))
        polygon.append(qc.QPointF(220.0, -140.0))

        m_polygonItem.setPolygon(polygon)
        m_polygonItem.setPen(pen)
        m_polygonItem.setFlag(flag1)
        m_polygonItem.setFlag(flag2)

        gp = qw.QGraphicsItemGroup()
        gp.setFlag(flag1)
        gp.setFlag(flag2)

        if obj_wraper:
            m_rectItem = obj_wraper(m_rectItem)
            bt_p = obj_wraper(bt_p)
            m_polygonItem = obj_wraper(m_polygonItem)
            m_lineItem = obj_wraper(m_lineItem)
            m_pathItem = obj_wraper(m_pathItem)

        gp.addToGroup(m_rectItem)
        gp.addToGroup(bt_p)
        scene.addItem(m_polygonItem)
        scene.addItem(m_lineItem)
        scene.addItem(m_pathItem)
        scene.addItem(gp)

        v = qw.QGraphicsView()
        v.setBackgroundBrush(qg.QBrush(qg.QColor(75, 225, 200)))
        v.setScene(scene)
        v.resize(1027, 768)
        return v

    def test1():
        # 直接更改类的函数来重载 event
        app = qw.QApplication(sys.argv)
        change_type_event()  # 重载
        v = make_items()
        v.show()

        r = app.exec_()
        sys.exit(r)

    def test2():
        # 更改实例的函数来重载 event
        app = qw.QApplication(sys.argv)

        v = make_items(change_event_item)
        v.show()

        r = app.exec_()
        sys.exit(r)

    # 两个 test 是两种方式, 只能按一种方式重载
    # test1()
    test2()

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/280498.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号