Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Zooming in/out QGraphicsView

Zooming in/out QGraphicsView

Scheduled Pinned Locked Moved Solved Qt for Python
pythonqt for python
4 Posts 2 Posters 3.2k 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.
  • P Offline
    P Offline
    Pythonic person
    wrote on last edited by Pythonic person
    #1

    Hello, i have an application for drawing shapes, I used QGraphicsView with QGraphicsScene, And then I added two different QPixmap QGraphicsItem to the scene.

    1. the first one is a canvas for drawing and printing the shapes.
    2. the second one is only for displaying a "ruler" to show you that 'x' of canvas boxes represents a number of pixels or whatever unit (this one should stay on the left bottom corner).

    And I implemented the zooming feature successfully, BUT my problem is that whenever I zoom in both items get zoomed so I can not see the "ruler" anymore because it is out of the scope after zooming (it only appears after zooming if you used pam and go to the bottom left corner), And that's right because I applied that feature to the whole view.

    I want to keep the second pixmap out of zooming functionality. Only apply that feature on the first item the "canvas"

    Here is a snippet of my code:

    class Canvas(QGraphicsView):
        def __init__(self, scene: QGraphicsScene):
            super().__init__(scene)
            self.scene = scene
            self.setFrameShape(QFrame.NoFrame)
            self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
    
            background_color = QColor("#333")
            self.pixmap_item: QGraphicsItem = self.scene.addPixmap(QPixmap(780, 580))
            self.pixmap_item.setTransformationMode(Qt.FastTransformation)
            self.pixmap_item.pixmap().fill(background_color)
            # legend mean the ruler
            self.legend = QPixmap(780, 580)
            self.legend.fill(QColor("#00ffffff"))
    
            p = QtGui.QPainter(self.legend)
            p.setPen(QPen(QColor("#0000FF"), 4))
            p.drawLine(35 * 5.1, self.legend.height() - 60, 35 * 8.9, self.legend.height() - 60)
            p.setPen(QColor("#c9c9c9"))
            p.setFont(QFont('Century Gothic', 14))
            p.drawText(35 * 5.5, self.legend.height() - 35, f'this text is from the other pixmap (legend)')
            p.end()
            self.scene.addPixmap(self.legend)
    
            self.zoom_times = 0
    
      def wheelEvent(self, event):
            # this function is working fine, but what I want is to only apply zooming on the self.pixmapitem, and keep the self.legend visable.
            zoom_in_factor = 1.25
            zoom_out_factor = 1 / zoom_in_factor
    
            # Save the scene pos
            old_pos = self.mapToScene(event.pos())
    
            # Zoom
            if event.angleDelta().y() > 0:
                if self.zoom_times == 6:
                    return
                zoom_factor = zoom_in_factor
                self.zoom_times += 1
            else:
                if self.zoom_times == 0:
                    return
                zoom_factor = zoom_out_factor
                self.zoom_times -= 1
            self.scale(zoom_factor, zoom_factor)
    
            # Get the new position
            new_pos = self.mapToScene(event.pos())
            # Move scene to old position
            delta = new_pos - old_pos
            self.translate(delta.x(), delta.y())
    

    Here are some images that explain what I am saying:

    Screenshot (258)_LI.jpg
    Screenshot (259)_LI.jpg

    JonBJ 1 Reply Last reply
    0
    • P Pythonic person

      Hello, i have an application for drawing shapes, I used QGraphicsView with QGraphicsScene, And then I added two different QPixmap QGraphicsItem to the scene.

      1. the first one is a canvas for drawing and printing the shapes.
      2. the second one is only for displaying a "ruler" to show you that 'x' of canvas boxes represents a number of pixels or whatever unit (this one should stay on the left bottom corner).

      And I implemented the zooming feature successfully, BUT my problem is that whenever I zoom in both items get zoomed so I can not see the "ruler" anymore because it is out of the scope after zooming (it only appears after zooming if you used pam and go to the bottom left corner), And that's right because I applied that feature to the whole view.

      I want to keep the second pixmap out of zooming functionality. Only apply that feature on the first item the "canvas"

      Here is a snippet of my code:

      class Canvas(QGraphicsView):
          def __init__(self, scene: QGraphicsScene):
              super().__init__(scene)
              self.scene = scene
              self.setFrameShape(QFrame.NoFrame)
              self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
              self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
      
              background_color = QColor("#333")
              self.pixmap_item: QGraphicsItem = self.scene.addPixmap(QPixmap(780, 580))
              self.pixmap_item.setTransformationMode(Qt.FastTransformation)
              self.pixmap_item.pixmap().fill(background_color)
              # legend mean the ruler
              self.legend = QPixmap(780, 580)
              self.legend.fill(QColor("#00ffffff"))
      
              p = QtGui.QPainter(self.legend)
              p.setPen(QPen(QColor("#0000FF"), 4))
              p.drawLine(35 * 5.1, self.legend.height() - 60, 35 * 8.9, self.legend.height() - 60)
              p.setPen(QColor("#c9c9c9"))
              p.setFont(QFont('Century Gothic', 14))
              p.drawText(35 * 5.5, self.legend.height() - 35, f'this text is from the other pixmap (legend)')
              p.end()
              self.scene.addPixmap(self.legend)
      
              self.zoom_times = 0
      
        def wheelEvent(self, event):
              # this function is working fine, but what I want is to only apply zooming on the self.pixmapitem, and keep the self.legend visable.
              zoom_in_factor = 1.25
              zoom_out_factor = 1 / zoom_in_factor
      
              # Save the scene pos
              old_pos = self.mapToScene(event.pos())
      
              # Zoom
              if event.angleDelta().y() > 0:
                  if self.zoom_times == 6:
                      return
                  zoom_factor = zoom_in_factor
                  self.zoom_times += 1
              else:
                  if self.zoom_times == 0:
                      return
                  zoom_factor = zoom_out_factor
                  self.zoom_times -= 1
              self.scale(zoom_factor, zoom_factor)
      
              # Get the new position
              new_pos = self.mapToScene(event.pos())
              # Move scene to old position
              delta = new_pos - old_pos
              self.translate(delta.x(), delta.y())
      

      Here are some images that explain what I am saying:

      Screenshot (258)_LI.jpg
      Screenshot (259)_LI.jpg

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @Pythonic-person said in Zooming in/out QGraphicsView:

      the second one is only for displaying a "ruler" to show you that 'x' of canvas boxes represents a number of pixels or whatever unit (this one should stay on the left bottom corner).

      Anything like this would be best implemented by overriding your QGraphicsView.drawForeground(), rather than via adding a QGraphicsItem. That should have two advantages:

      • No scaling from zoom.
      • Can be placed always in same place, e.g. bottom-left of a view, regardless of where the view is positioned.

      Having said that, if your "legend" is actually a "ruler" what is it measuring? If it is the "scale" for the map/scene, you usually would want that to change with the zoom factor!

      Also unless you want really want your pixmap for the background you might draw the black background + grid lines in an override of QGraphicsScene.drawBackground().

      P 1 Reply Last reply
      1
      • JonBJ JonB

        @Pythonic-person said in Zooming in/out QGraphicsView:

        the second one is only for displaying a "ruler" to show you that 'x' of canvas boxes represents a number of pixels or whatever unit (this one should stay on the left bottom corner).

        Anything like this would be best implemented by overriding your QGraphicsView.drawForeground(), rather than via adding a QGraphicsItem. That should have two advantages:

        • No scaling from zoom.
        • Can be placed always in same place, e.g. bottom-left of a view, regardless of where the view is positioned.

        Having said that, if your "legend" is actually a "ruler" what is it measuring? If it is the "scale" for the map/scene, you usually would want that to change with the zoom factor!

        Also unless you want really want your pixmap for the background you might draw the black background + grid lines in an override of QGraphicsScene.drawBackground().

        P Offline
        P Offline
        Pythonic person
        wrote on last edited by
        #3

        @JonB said in Zooming in/out QGraphicsView:

        Anything like this would be best implemented by overriding your QGraphicsView.drawForeground(), rather than via adding a QGraphicsItem. That should have two advantages:

        No scaling from zoom.
        Can be placed always in same place, e.g. bottom-left of a view, regardless of where the view is positioned.

        It was really really helpful I was searching for this for a long time, Thanks.
        And that won't affect the performance of the app or any other effect?

        here is my implementation (it worked well just needs some calculation and taking care of the zooming factor):

        Old code PLUS this function:

        def drawForeground(self, painter, rectF):
                super(Canvas, self).drawForeground(painter, rectF)
                painter.setPen(QPen(QColor("#0000FF"), 4))
                painter.setFont(QFont('Century Gothic', 14))
                painter.drawLine(rectF.bottomLeft().x(), rectF.bottomLeft().y(),rectF.bottomLeft().x(), rectF.bottomLeft().y())
                painter.setPen(QColor("#c9c9c9"))
                painter.drawText(rectF.bottomLeft().x(),rectF.bottomLeft().y(), f'this text is from the other pixmap (legend)')
        
        JonBJ 1 Reply Last reply
        1
        • P Pythonic person

          @JonB said in Zooming in/out QGraphicsView:

          Anything like this would be best implemented by overriding your QGraphicsView.drawForeground(), rather than via adding a QGraphicsItem. That should have two advantages:

          No scaling from zoom.
          Can be placed always in same place, e.g. bottom-left of a view, regardless of where the view is positioned.

          It was really really helpful I was searching for this for a long time, Thanks.
          And that won't affect the performance of the app or any other effect?

          here is my implementation (it worked well just needs some calculation and taking care of the zooming factor):

          Old code PLUS this function:

          def drawForeground(self, painter, rectF):
                  super(Canvas, self).drawForeground(painter, rectF)
                  painter.setPen(QPen(QColor("#0000FF"), 4))
                  painter.setFont(QFont('Century Gothic', 14))
                  painter.drawLine(rectF.bottomLeft().x(), rectF.bottomLeft().y(),rectF.bottomLeft().x(), rectF.bottomLeft().y())
                  painter.setPen(QColor("#c9c9c9"))
                  painter.drawText(rectF.bottomLeft().x(),rectF.bottomLeft().y(), f'this text is from the other pixmap (legend)')
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @Pythonic-person said in Zooming in/out QGraphicsView:

          And that won't affect the performance of the app or any other effect?

          LOL no. If anything I think it might be a microsecond faster. For all the QGraphicsItems on your scene it has to see where they are, who's on top of whom, whether the item is hidden, how to draw it etc. The foreground is just a simple layer it puts on top of any items (just as the background is below any items). There are probably lots of calculations it can skip, at a guess. If you want you can optimize the foreground/background redrawing with clip areas.

          Using the background/foreground of the scene or view for things which are static and not the actual objects you are playing with on the scene seems to me to keep things cleaner. E.g. if you go looking for one of your items on the scene, why do you want to have to encounter and skip a ruler or the background grid pattern or whatever?

          1 Reply Last reply
          0

          • Login

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