1

I have a main widget inside a window who contains a lot of widgets. How can I insert a QGraphics view and a QGraphicsScene in that widget? I have not found a direct insertion method, so I am trying using a wrapper, in this case a box layout but it is not a good solution. The QGraphicsScene stands out from the layout limits.

Code:

class UiVentana(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedSize(1500, 1015)

        widget_central = QtWidgets.QWidget(self)

        wrapper = QtWidgets.QHBoxLayout(widget_central)

        scene = QtWidgets.QGraphicsScene(wrapper)
        vista = QtWidgets.QGraphicsView(scene)

        wrapper.addWidget(vista)

        self.diedrico = Diedrico() # This is a class who draw things, not relevant
        self.diedrico.setFixedSize(2000, 2000)
        scene.addWidget(self.diedrico)
        self.setCentralWidget(widget_central)

I would like to get this result:

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QPen, QColor
import sys


class Diedrico(QWidget):
    def __init__(self, parent):
        super().__init__(parent)

    def paintEvent(self, event):
        qp = QPainter(self)
        qp.setPen(QPen(QColor(Qt.black), 5))
        qp.drawRect(500, 500, 1000, 1000)


class UiVentana(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(UiVentana, self).__init__(parent)
        self.resize(520, 520)
        self.widget_central = QtWidgets.QWidget(self)
        scrol = QtWidgets.QScrollArea(self.widget_central)
        scrol.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scrol.setGeometry(QtCore.QRect(30, 30, 500, 500))
        scrol.setWidgetResizable(False)

        contenido = QtWidgets.QWidget()
        contenido.setGeometry(QtCore.QRect(0, 0, 2000, 2000))
        scrol.setWidget(contenido)

        self.Diedrico = Diedrico(contenido)
        self.Diedrico.setGeometry(QtCore.QRect(0, 0, 2000, 2000))
        self.setCentralWidget(self.widget_central)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    ui = UiVentana()
    ui.show()
    sys.exit(app.exec_())

But using QGraphics instead of a scroll area

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Jaime02
  • 299
  • 7
  • 21
  • 1
    add `self.setCentralWidget(widget_central)` – eyllanesc Sep 15 '19 at 17:00
  • @eyllanesc I had done it, I forgot to add that line. This is not a duplicate of that question, I think – Jaime02 Sep 15 '19 at 17:01
  • then provide a [MRE], show an image of what you get and another of what you want to get – eyllanesc Sep 15 '19 at 17:03
  • 1
    On the other hand QGraphicsScene is not a visual element but a kind of administrator of the elements, the visual element is the QGraphicsView. – eyllanesc Sep 15 '19 at 17:04
  • remove `wrapper.setGeometry(QRect(1010, 510, 470, 460))` and `self.resize(1500, 1015)`, are useless – eyllanesc Sep 15 '19 at 17:06
  • @eyllanesc so the QGraphicsScene has to be contained in a layout? Done, that two lines maked sense with the full code. – Jaime02 Sep 15 '19 at 17:09
  • A QGraphicsScene is **not** a widget. A QGraphicsView (which can *show* a scene) is. This means that you can even have multiple graphics views set to a unique scene. Sorry to point this out, but according to your previous questions I think you might need to read more about how the [graphics view framework](https://doc.qt.io/qt-5/graphicsview.html) works, and better understand how the parent/child hierarchy behaves on Qt objects and widgets. – musicamante Sep 16 '19 at 00:42

1 Answers1

1

The QGraphicsProxyWidget that is created using the widget takes into account the minimum size of the widget to set the boundingRect, and the QGraphicsScene uses the boundingRect to set the initial scene rect.

from PyQt5 import QtCore, QtGui, QtWidgets


class Diedrico(QtWidgets.QWidget):
    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.black), 5)
        qp.setPen(pen)
        qp.drawRect(500, 500, 1000, 1000)

    def minimumSizeHint(self):
        return QtCore.QSize(2000, 2000)


class UiVentana(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(UiVentana, self).__init__(parent)
        self.resize(520, 520)

        widget_central = QtWidgets.QWidget()
        self.setCentralWidget(widget_central)

        lay = QtWidgets.QVBoxLayout(widget_central)

        scene = QtWidgets.QGraphicsScene(self)
        view = QtWidgets.QGraphicsView(scene)

        diedrico = Diedrico()
        scene.addWidget(diedrico)

        lay.addWidget(view)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    ui = UiVentana()
    ui.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • How can I move the layout to certain position of the main window? And set its width and height. – Jaime02 Sep 15 '19 at 17:25
  • @PepeElMago33 Do you want me to have margins? – eyllanesc Sep 15 '19 at 17:26
  • @PepeElMago33 add `lay.setContentsMargins(40, 40, 40, 40)` – eyllanesc Sep 15 '19 at 17:29
  • I did not mean the margins of the layout, I need to place the layout at certain position inside the central widget and set a width and heigth for it, the setGeometry method does not work properly, the contents expand outside of the layout. Pic: https://imgur.com/JkmTZj9 – Jaime02 Sep 15 '19 at 18:48
  • @PepeElMago33 The code you have provided does not allow me to test what you point out so it will be impossible for me to help you. – eyllanesc Sep 15 '19 at 18:53
  • I got it, I had to create a widget with the desired geometry and insert the layout in it. Pic: https://imgur.com/XiroSkI – Jaime02 Sep 15 '19 at 19:07