为什么 QGraphicsBlurEffect 使我的 QGraphicsView 无法工作?

问题描述 投票:0回答:1

我在 PyQt5 上使用

QGraphicsView
小部件,并创建了一些自定义
QGraphicsItems

当我实例化我的项目而没有任何效果时,我得到: Without any blur

当我添加这三行时:

        blur = _QtWidgets.QGraphicsBlurEffect()
        blur.setBlurRadius(1.1)
        self.setGraphicsEffect(blur)

在我的自定义项目的“祖父母”中,我得到了这个:

With blur

此外,似乎没有任何东西在移动,我的鼠标没有移动,甲板没有做任何事情......

我找到了这篇文章,但它对我没有帮助,我作为参数传递的每个提示都产生了相同的结果。

我还尝试直接在 QGraphicsView 上传递模糊效果,但它仅在 QGraphicsView 更改(调整大小,...)时起作用,并且不适用于任何项目更新。

我该怎么办?

感谢您的帮助!

编辑:

正确设置每个元素的边界矩形后,我得到了这个:

With blur and good rects

但我仍然遇到动画不起作用、鼠标不动等问题......

重现

这里有一个重现它的小方法,仅包含背景和鼠标:

from PyQt5 import QtWidgets as _QtWidgets, uic as _uic
from PyQt5 import QtCore as _QtCore
from PyQt5 import QtGui as _QtGui

class GameWidget(_QtWidgets.QGraphicsView):
    def __init__(self):
        super().__init__()
        
        self._scene: _QtWidgets.QGraphicsScene = _QtWidgets.QGraphicsScene()
        
        self.setScene(self._scene)
        
        self._main_graphic = MainDisplayedElement()
        self._main_graphic.setZValue(-10)
        self._scene.addItem(self._main_graphic)
        
        self._mouse = MouseDisplayedElement()
        self._mouse.set_size(40)
        
        self._mouse.setZValue(1000)
        
        self._scene.addItem(self._mouse)
        
        self.setMouseTracking(True)
        self.setInteractive(True)
        
        self.setVerticalScrollBarPolicy(_QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(_QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        
    def onShow(self):
        self.resizeEvent()
    
    def resizeEvent(self, event = None) -> None:
        w, h = self.width() - 2, self.height() - 2
        
        self.setSceneRect(-w / 2, -h / 2, w, h)
        self._main_graphic.set_rect(-w / 2, -h / 2, w, h)
    
    def mouseMoveEvent(self, event: _QtGui.QMouseEvent) -> None:
        super().mouseMoveEvent(event)
        
        position: _QtCore.QPointF = event.pos()
        
        position.setX(int(position.x() - self.width() / 2))
        position.setY(int(position.y() - self.height() / 2))
        
        event.ignore()
        
        x, y = position.x(), position.y()
        self._mouse.set_position(x, y)
        
        self._scene.update()

class GameDisplayedElement(_QtWidgets.QGraphicsObject):
    def __init__(self, x: int, y: int, width: int, height: int, parent = None):
        super().__init__(parent)
        
        self._width: int = width
        self._height: int = height
        self._x: int = x
        self._y: int = y
        
        self.setAcceptHoverEvents(True)
        self.setAcceptedMouseButtons(_QtCore.Qt.MouseButton.AllButtons)
        
        # Here are the three lines...
        blur = _QtWidgets.QGraphicsBlurEffect()
        blur.setBlurRadius(1.1)
        blur.setBlurHints(_QtWidgets.QGraphicsBlurEffect.BlurHint.QualityHint)
        self.setGraphicsEffect(blur)
        
    def paint(self, painter: _QtGui.QPainter, options: _QtWidgets.QStyleOptionGraphicsItem, widget: _QtWidgets.QWidget) -> None:
        pass
    
    def boundingRect(self) -> _QtCore.QRectF:
        x = self._x - self._width / 2
        y = self._y - self._height / 2
        
        return _QtCore.QRectF(int(x), int(y), int(self._width), int(self._height))

class MainDisplayedElement(GameDisplayedElement):
    def __init__(self, parent=None):
        super().__init__(0, 0, 0, 0)
        
        self._size = 150
        
        self.setAcceptHoverEvents(False)
        self.setAcceptedMouseButtons(_QtCore.Qt.MouseButton.NoButton)
    
    def paint(self, painter: _QtGui.QPainter, options: _QtWidgets.QStyleOptionGraphicsItem, widget: _QtWidgets.QWidget) -> None:
        a = open("./any_image.png", "rb")
        data = a.read()
        a.close()
        
        image = _QtGui.QImage.fromData(data) # use any QImage you want
    
        x = 0
        while x - self._size <= self._width / 2:
            y = 0
            while y - self._size <= self._height / 2:
                painter.drawImage(_QtCore.QRectF(x, y, self._size, self._size), image)
                painter.drawImage(_QtCore.QRectF(-x-self._size, y, self._size, self._size), image)
                painter.drawImage(_QtCore.QRectF(x, -y-self._size, self._size, self._size), image)
                painter.drawImage(_QtCore.QRectF(-x-self._size, -y-self._size, self._size, self._size), image)
                y += self._size
            x += self._size
    
    def set_rect(self, x: float, y: float, w: float, h: float) -> None:
        self._x = 0
        self._y = 0
        self._width = w
        self._height = h
    
class MouseDisplayedElement(GameDisplayedElement):
    def __init__(self, parent = None):
        super().__init__(0, 0, 50, 50, parent)
        
        self.setAcceptHoverEvents(False)
        self.setAcceptedMouseButtons(_QtCore.Qt.MouseButton.NoButton)
    
    def paint(self, painter: _QtGui.QPainter, options: _QtWidgets.QStyleOptionGraphicsItem, widget: _QtWidgets.QWidget) -> None:
        a = open("./any_image.png", "rb")
        data = a.read()
        a.close()
        
        image = _QtGui.QImage.fromData(data) # use any QImage you want
    
        painter.drawImage(_QtCore.QRectF(self._x, self._y, self._width, self._height), image)
    
    def set_size(self, size: int) -> None:
        self._width, self._height = size, size
    
    def hoverMoveEvent(self, event: _QtGui.QHoverEvent) -> None:
        event.ignore()
    
    def mousePressEvent(self, event):
        event.ignore()
        
    def set_position(self, x: int, y: int) -> None:
        self._x = x
        self._y = y
    
app = _QtWidgets.QApplication([''])

widg = GameWidget()
widg.show()

app.exec()
    

在两个项目的

paint
方法中更改该项目的路径进行测试。您会看到鼠标不随着这三条线移动,并且在没有它们的情况下移动,因为背景不会随着树线调整大小,并且在没有它们的情况下成功调整大小。

背景

关于我的环境,我使用的是Python3.10.12,带有PyQt5和qt5.15.3(通过qtdiag命令给出);我使用的是带有 Ubuntu22.04 LTS 的 x86-64 计算机。

pyqt5 blur qgraphicsview qgraphicsitem
1个回答
0
投票

根据@musicamante(谢谢你),我唯一缺少的是在调整大小和替换函数中调用

prepareGeometryChange
方法:

    def set_size(self, size: int) -> None:
        self._width, self._height = size, size
        self.prepareGeometryChange() # this will make the graphics item update again

但是也有一种可能是在我绘制图像时仅将模糊效果应用于图像(在我的情况下效果更好),可以在这个答案中找到:

    def applyEffectToImage(self, src: _QtGui.QImage, effect: _QtWidgets.QGraphicsEffect, extent: int = 0) -> _QtGui.QImage:
        scene = _QtWidgets.QGraphicsScene()
        item = _QtWidgets.QGraphicsPixmapItem()
        item.setPixmap(_QtGui.QPixmap.fromImage(src))
        item.setGraphicsEffect(effect)
        scene.addItem(item)
        res = _QtGui.QImage(src.size() + _QtCore.QSize(extent*2, extent*2), _QtGui.QImage.Format.Format_ARGB32)
        res.fill(_QtCore.Qt.GlobalColor.transparent)
        ptr = _QtGui.QPainter(res)
        scene.render(ptr, _QtCore.QRectF(), _QtCore.QRectF( -extent, -extent, src.width()+extent*2, src.height()+extent*2 ) )
        ptr.end()
        return res

    

这样,我可以绘制所有图形,并且仅将模糊应用于需要它的图像。

© www.soinside.com 2019 - 2024. All rights reserved.