You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在QGraphicsItem元类中正确调用基类mouseMoveEvent方法?

问题描述

我想给多个继承自QGraphicsItem的类添加相同的自定义函数,目前的重复实现方式如下:

class QGraphicsRectItem(QGraphicsRectItem):
   def mouseMoveEvent(self, event):
       print( "mouseMoveEvent :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() )   )
       super().mouseMoveEvent( event )
class QGraphicsEllipseItem(QGraphicsEllipseItem):
   def mouseMoveEvent(self, event):
       print( "mouseMoveEvent :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() )   )
       super().mouseMoveEvent( event )
class QGraphicsPixmapItem(QGraphicsPixmapItem):
   def mouseMoveEvent(self, event):
       print( "mouseMoveEvent :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() )   )
       super().mouseMoveEvent( event )
class QGraphicsSimpleTextItem(QGraphicsSimpleTextItem):
   def mouseMoveEvent(self, event):
       print( "mouseMoveEvent :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() )   )
       super().mouseMoveEvent( event )

为简化代码,我尝试用继承自type(QGraphicsItem)的元类批量注入该自定义方法,但在元类中编写super().mouseMoveEvent( event )时遇到问题,当前元类实现无法正常工作:

from types import FunctionType

class QGraphicsItemMeta(type(QGraphicsItem)):
    def __new__(cls, name, bases, dct):
        print("name= %s" %(name))
        print("bases= %s" %(bases))
        print("dct=", dct)

        newDct = {}
        for name, method in dct.items():
            if type(method) is FunctionType:
                print("method name= %s" % (name))
                newDct[name] = method
            else:
                print("attribut name= %s" % (name))
                newDct[name] = method

        def mouseMoveEventMyCustomize(self, event):
            print( "mouseMoveEventNew :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() )   )
            super().mouseMoveEvent( event )

        newDct['mouseMoveEvent'] = mouseMoveEventMyCustomize

        return super().__new__(cls, name, bases, newDct)

class QGraphicsRectItem(QGraphicsRectItem, metaclass = QGraphicsItemMeta):
    pass
class QGraphicsEllipseItem(QGraphicsEllipseItem, metaclass = QGraphicsItemMeta):
    pass
class QGraphicsPixmapItem(QGraphicsPixmapItem, metaclass = QGraphicsItemMeta):
    pass
class QGraphicsSimpleTextItem(QGraphicsSimpleTextItem, metaclass = QGraphicsItemMeta):
    pass

我曾尝试将该行代码替换为bases().mouseMoveEvent( event ),但依然无法解决问题,请问该如何修正?


解决方案

问题核心在于元类中定义的mouseMoveEventMyCustomize方法里的super()调用没有绑定当前实例的类上下文,无法正确定位父类方法;而bases()会创建新的基类实例,并非调用当前实例的父类方法,因此无效。以下是两种可靠的修正方案:

方法一:使用装饰器(推荐,更简洁)

无需元类,通过装饰器批量为类注入自定义逻辑:

def add_custom_mouse_move(cls):
    # 保存原有方法,避免覆盖类自身定义的逻辑
    original_mouse_move = cls.mouseMoveEvent
    def new_mouse_move(self, event):
        print("mouseMoveEventNew :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() ))
        # 调用原方法
        original_mouse_move(self, event)
    cls.mouseMoveEvent = new_mouse_move
    return cls

# 用装饰器批量处理目标类
@add_custom_mouse_move
class QGraphicsRectItem(QGraphicsRectItem):
    pass

@add_custom_mouse_move
class QGraphicsEllipseItem(QGraphicsEllipseItem):
    pass

@add_custom_mouse_move
class QGraphicsPixmapItem(QGraphicsPixmapItem):
    pass

@add_custom_mouse_move
class QGraphicsSimpleTextItem(QGraphicsSimpleTextItem):
    pass

方法二:修正元类实现

如果坚持使用元类,需通过实例的__class__绑定正确的上下文来调用父类方法:

from types import FunctionType

class QGraphicsItemMeta(type(QGraphicsItem)):
    def __new__(cls, name, bases, dct):
        def mouseMoveEventMyCustomize(self, event):
            print("mouseMoveEventNew :: event pos  =(%.1f, %.1f) " %( event.pos().x(), event.pos().y() ))
            # 通过实例的实际类构建super对象,确保找到正确的父类方法
            super(self.__class__, self).mouseMoveEvent(event)
        
        # 仅当类自身未定义mouseMoveEvent时才注入,保留灵活性
        if 'mouseMoveEvent' not in dct:
            dct['mouseMoveEvent'] = mouseMoveEventMyCustomize
        
        # 移除不必要的newDct复制逻辑,直接修改传入的dct
        return super().__new__(cls, name, bases, dct)

# 使用元类创建目标类
class QGraphicsRectItem(QGraphicsRectItem, metaclass=QGraphicsItemMeta):
    pass

class QGraphicsEllipseItem(QGraphicsEllipseItem, metaclass=QGraphicsItemMeta):
    pass

class QGraphicsPixmapItem(QGraphicsPixmapItem, metaclass=QGraphicsItemMeta):
    pass

class QGraphicsSimpleTextItem(QGraphicsSimpleTextItem, metaclass=QGraphicsItemMeta):
    pass

内容的提问来源于stack exchange,提问作者jljPatch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:55:10