Swapping Between multiple QGraphicsViews / QGraphicsScenes
-
Hello -
In my application, I have a class which contains both a QGraphicsView and an associated QGraphics scene (I would like to have one view per graphics scene in order to retain things like pan/zoom per scene).
I would like to swap between multiple instances of this class in my application's main viewport, but I'm unsure what to actually set as the Main window's central widget here... if I set the first instance of my custom class as the central widget, and then try to to re-set the central widget with another instance of that class, I produce this error:
wrapped C/C++ object of type SceneAndView has been deleted
Obviously this is not the right approach and the error is expected, since Qt will apparently delete the original central widget as it is replaced by another widget, as written about here:
https://stackoverflow.com/questions/5339062/python-pyside-internal-c-object-already-deleted
In the above link, there is a reference to QStackedWidget. I played around with it but was unable to get a workable result. So, I was wondering if anyone could help out with the code below? The result I'm looking for is to be able to toggle between 'self.graphics_scene_1' and 'self.graphics_scene_2' in the main viewport.
Any advice or help would be greatly appreciated, thankyou,
Ekarimport sys from PyQt5.QtCore import Qt from PyQt5.QtGui import QBrush, QPen from PyQt5.QtWidgets import * class SceneAndView(QWidget): """ Class containing both a QGraphicsView and an associated QGraphicsScene """ def __init__(self, parent=None): super().__init__(parent) # setup layout self.layout = QVBoxLayout() self.setLayout(self.layout) # create graphics scene self.gfx_scene = QGraphicsScene(self) self.gfx_scene.setSceneRect(0, 0, 200, 200) # create graphics view self.view = QGraphicsView(self.gfx_scene) self.layout.addWidget(self.view) # define and add some graphics items rect = QGraphicsRectItem(0, 0, 200, 50) rect.setPos(50, 20) brush = QBrush(Qt.red) rect.setBrush(brush) pen = QPen(Qt.cyan) pen.setWidth(10) rect.setPen(pen) ellipse = QGraphicsEllipseItem(0, 0, 100, 100) ellipse.setPos(75, 30) brush = QBrush(Qt.blue) ellipse.setBrush(brush) pen = QPen(Qt.green) pen.setWidth(5) ellipse.setPen(pen) self.gfx_scene.addItem(ellipse) self.gfx_scene.addItem(rect) # Set all items as moveable and selectable for item in self.gfx_scene.items(): item.setFlag(QGraphicsItem.ItemIsMovable) item.setFlag(QGraphicsItem.ItemIsSelectable) class Window(QMainWindow): def __init__(self): super().__init__() self.toggle = 1 # var to toggle between scenes 1 and 2 self.graphics_scene_1 = SceneAndView() self.graphics_scene_2 = SceneAndView() # add a button to enable toggling between scenes self.test_toolbar = QToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.test_toolbar) self.toggle_view_and_scene = QAction('Toggle View and GFX Scene', self) self.toggle_view_and_scene.triggered.connect(self.toggle_scene) self.test_toolbar.addAction(self.toggle_view_and_scene) """ # what should I be setting as the central widget here? Getting error when toggling back and forth between gfx scene 1 and 2: # 'wrapped C/C++ object of type SceneAndView has been deleted' """ self.setCentralWidget(self.graphics_scene_1) def toggle_scene(self): print('toggling scene') # I want to be able to swap between gfx scene and view, 1 and 2 if self.toggle == 1: self.setCentralWidget(self.graphics_scene_2) self.toggle = 0 else: self.setCentralWidget(self.graphics_scene_1) self.toggle = 1 app = QApplication(sys.argv) w = Window() w.show() app.exec()
-
Hello -
In my application, I have a class which contains both a QGraphicsView and an associated QGraphics scene (I would like to have one view per graphics scene in order to retain things like pan/zoom per scene).
I would like to swap between multiple instances of this class in my application's main viewport, but I'm unsure what to actually set as the Main window's central widget here... if I set the first instance of my custom class as the central widget, and then try to to re-set the central widget with another instance of that class, I produce this error:
wrapped C/C++ object of type SceneAndView has been deleted
Obviously this is not the right approach and the error is expected, since Qt will apparently delete the original central widget as it is replaced by another widget, as written about here:
https://stackoverflow.com/questions/5339062/python-pyside-internal-c-object-already-deleted
In the above link, there is a reference to QStackedWidget. I played around with it but was unable to get a workable result. So, I was wondering if anyone could help out with the code below? The result I'm looking for is to be able to toggle between 'self.graphics_scene_1' and 'self.graphics_scene_2' in the main viewport.
Any advice or help would be greatly appreciated, thankyou,
Ekarimport sys from PyQt5.QtCore import Qt from PyQt5.QtGui import QBrush, QPen from PyQt5.QtWidgets import * class SceneAndView(QWidget): """ Class containing both a QGraphicsView and an associated QGraphicsScene """ def __init__(self, parent=None): super().__init__(parent) # setup layout self.layout = QVBoxLayout() self.setLayout(self.layout) # create graphics scene self.gfx_scene = QGraphicsScene(self) self.gfx_scene.setSceneRect(0, 0, 200, 200) # create graphics view self.view = QGraphicsView(self.gfx_scene) self.layout.addWidget(self.view) # define and add some graphics items rect = QGraphicsRectItem(0, 0, 200, 50) rect.setPos(50, 20) brush = QBrush(Qt.red) rect.setBrush(brush) pen = QPen(Qt.cyan) pen.setWidth(10) rect.setPen(pen) ellipse = QGraphicsEllipseItem(0, 0, 100, 100) ellipse.setPos(75, 30) brush = QBrush(Qt.blue) ellipse.setBrush(brush) pen = QPen(Qt.green) pen.setWidth(5) ellipse.setPen(pen) self.gfx_scene.addItem(ellipse) self.gfx_scene.addItem(rect) # Set all items as moveable and selectable for item in self.gfx_scene.items(): item.setFlag(QGraphicsItem.ItemIsMovable) item.setFlag(QGraphicsItem.ItemIsSelectable) class Window(QMainWindow): def __init__(self): super().__init__() self.toggle = 1 # var to toggle between scenes 1 and 2 self.graphics_scene_1 = SceneAndView() self.graphics_scene_2 = SceneAndView() # add a button to enable toggling between scenes self.test_toolbar = QToolBar(self) self.addToolBar(Qt.TopToolBarArea, self.test_toolbar) self.toggle_view_and_scene = QAction('Toggle View and GFX Scene', self) self.toggle_view_and_scene.triggered.connect(self.toggle_scene) self.test_toolbar.addAction(self.toggle_view_and_scene) """ # what should I be setting as the central widget here? Getting error when toggling back and forth between gfx scene 1 and 2: # 'wrapped C/C++ object of type SceneAndView has been deleted' """ self.setCentralWidget(self.graphics_scene_1) def toggle_scene(self): print('toggling scene') # I want to be able to swap between gfx scene and view, 1 and 2 if self.toggle == 1: self.setCentralWidget(self.graphics_scene_2) self.toggle = 0 else: self.setCentralWidget(self.graphics_scene_1) self.toggle = 1 app = QApplication(sys.argv) w = Window() w.show() app.exec()
-
@S-Tozer
AQGraphicsView
is justQWidget
, so useQStackedWidget
. You add your two views onto the QSW and usesetCurrentIndex
/Widget()
to swap which one it currently shows. Make your central widget be that QSW.Thankyou JonB- this is working fine now. Terrific!
Here's how it looks now in the example code:
self.stacked_widget = QStackedWidget() self.setCentralWidget(self.stacked_widget) self.stacked_widget.addWidget(self.graphics_scene_1) self.stacked_widget.addWidget(self.graphics_scene_2)
Now I can swap between scenes without issues with:
self.stacked_widget.setCurrentIndex(1) self.stacked_widget.setCurrentIndex(0)
etc...
Cheers!