Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Swapping Between multiple QGraphicsViews / QGraphicsScenes
Forum Updated to NodeBB v4.3 + New Features

Swapping Between multiple QGraphicsViews / QGraphicsScenes

Scheduled Pinned Locked Moved Solved General and Desktop
3 Posts 2 Posters 888 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    S Tozer
    wrote on last edited by S Tozer
    #1

    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,
    Ekar

    import 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()
    
    JonBJ 1 Reply Last reply
    0
    • S S Tozer

      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,
      Ekar

      import 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()
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @S-Tozer
      A QGraphicsView is just QWidget, so use QStackedWidget. You add your two views onto the QSW and use setCurrentIndex/Widget() to swap which one it currently shows. Make your central widget be that QSW.

      S 1 Reply Last reply
      2
      • JonBJ JonB

        @S-Tozer
        A QGraphicsView is just QWidget, so use QStackedWidget. You add your two views onto the QSW and use setCurrentIndex/Widget() to swap which one it currently shows. Make your central widget be that QSW.

        S Offline
        S Offline
        S Tozer
        wrote on last edited by S Tozer
        #3

        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!

        1 Reply Last reply
        1

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved