'PySide2 QGraphicsView zoom widget in scene macOS

Apparently, a widget inside a QGraphicsView does not scale correctly on macOS. Does anyone have a workaround?

Problem:

I have a QGraphicsView where I am zooming by calling the scale method.

I also have some QWidgets in my QGraphicScene, but their UI graphics do not scale accordingly when I zoom.

I use a QGraphicsProxyWidget from within a QGraphicsItem to display the widgets, but the scale issue persists even by using the scene.addWidget.

scale zoom issue

I tested the code on macOS 10.15.7 and 10.14.6, both Intel CPUs.

Edit: As pointed out in the comments by musicamante, the QGraphicsItem.ItemIgnoresTransformations does the exact opposite, so I am taking the reference out of the question to avoid confusion since it was only a failed attempt.

Edit2: On Windows 10 seems to work fine.

windows_os

import sys

from PySide2.QtCore import Qt
from PySide2.QtGui import QPainterPath, QColor, QBrush
from PySide2.QtWidgets import (
    QGraphicsItem,
    QPushButton,
    QGraphicsScene,
    QWidget,
    QVBoxLayout,
    QMainWindow,
    QApplication,
    QGraphicsView,
    QGraphicsProxyWidget
)


class NodeGraphicsContent(QGraphicsProxyWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWidget(QPushButton('QGraphicsItem Button'))


class GraphicsItem(QGraphicsItem):
    def __init__(self):
        super().__init__()

        self.item_body = self.draw_item()
        self.draw_content()

    def draw_content(self):
        NodeGraphicsContent(self)

    def draw_item(self):
        path = QPainterPath()
        path.addRect(0, 0, 200, 200)
        return path

    def paint(self, painter, option, widget):
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(QColor("#FF313131")))
        painter.drawPath(self.item_body)

    def boundingRect(self):
        return self.item_body.boundingRect()


class GraphicScene(QGraphicsScene):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.scene_width = 500
        self.scene_height = 500

        self._grid_pattern = QBrush(QColor("#282828"), Qt.Dense7Pattern)

        self.setBackgroundBrush(QColor("#393939"))
        self.setSceneRect(-self.scene_width // 2, -self.scene_height // 2,
                          self.scene_width, self.scene_height)

    def drawBackground(self, painter, rect):
        super().drawBackground(painter, rect)
        painter.fillRect(rect, self._grid_pattern)


class GraphicsView(QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)

    def wheelEvent(self, event):
        """Zoom function."""
        zoom_factor = 1.25
        zoom_out = 1 / zoom_factor
        zoom_factor = zoom_factor if event.delta() > 0 else zoom_out
        self.scale(zoom_factor, zoom_factor)


class MainWidgets(QWidget):
    def __init__(self):
        super().__init__()

        self.scene = GraphicScene()
        self.view = GraphicsView(self.scene)

        _layout = QVBoxLayout()
        _layout.addWidget(self.view)
        self.setLayout(_layout)

        self.add_widgets()

    def add_widgets(self):
        """Add first a normal widget, then a QGraphicsItem, 
        which both dont seem to scale correctly.
        """
        button = self.scene.addWidget(QPushButton('Widget Button'))
        button.setPos(-50, -100)
        self.scene.addItem(GraphicsItem())


class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setCentralWidget(MainWidgets())
        self.statusBar().showMessage('Zoom with mouse wheel')


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source