Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Is there a simple way to use pinch to zoom an image at the center of the pinch gesture?
QtWS25 Last Chance

Is there a simple way to use pinch to zoom an image at the center of the pinch gesture?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
qmlimagezoompinchpincharea
5 Posts 3 Posters 4.1k 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.
  • L Offline
    L Offline
    larkei15
    wrote on last edited by
    #1

    Hello,

    I want to use a pinch control to zoom and image and also be able to drag the zoomed image with one finger or while zooming. I can easily do this by attaching an image as the pinch target of a PinchArea and also setting it as the drag target of a MouseArea. However, this only zooms this image at the Image's transformOrigin, which is the center by default. This is not ideal, as it makes zooming the image on a touchscreen difficult if you want to zoom to a point on the edge, as oyu zoom onto the center and then have to pan. I know I can set a Scale item to the transform property of the Image, but then I lose the simplicity of attaching it to the pinch target. Is there any way to do this without having to reinvent the wheel?

    Thanks,
    Keith

    1 Reply Last reply
    1
    • S Offline
      S Offline
      stcorp
      wrote on last edited by
      #2

      I have some code of how I did it. I haven't made any efforts to make it nice, but it does work. It also allows zooming in using a mouse wheel or by double clicking, so it is cross platform. I hope this helps you. If you have any questions just ask. You will need to set a source for the image for this to work, and possibly change some things. Mostly this was just to show you how I did it using a Flickable and a PinchArea

      Flickable {
                  id: flick
                  Layout.fillWidth: true
                  Layout.fillHeight: true
                  contentHeight: height
                  contentWidth: width
      
                  clip: true
                  ScrollBar.vertical: ScrollBar{active: flick.contentHeight/flick.height > 1 ? true : false}
                  ScrollBar.horizontal: ScrollBar{active: flick.contentWidth/flick.width > 1 ? true : false}
                  boundsBehavior: Flickable.StopAtBounds
      
                  PinchArea {
                      id: pinch
                      width: Math.max(flick.contentWidth, flick.width)
                      height: Math.max(flick.contentHeight, flick.height)
      
                      property real initialWidth
                      property real initialHeight
      
                      onPinchStarted: {
                          initialWidth = flick.contentWidth
                          initialHeight = flick.contentHeight
                      }
      
                      onPinchUpdated: {
                          var newWidth = initialWidth * pinch.scale
                          var newHeight = initialHeight * pinch.scale
      
                          if (newWidth < flick.width || newHeight < flick.height) {
                              flick.resizeContent(flick.width, flick.height, Qt.point(flick.width/2, flick.height/2))
                          }
                          else {
                              flick.contentX += pinch.previousCenter.x - pinch.center.x
                              flick.contentY += pinch.previousCenter.y - pinch.center.y
                              flick.resizeContent(initialWidth * pinch.scale, initialHeight * pinch.scale, pinch.center)
                          }
                      }
      
                      onPinchFinished: {
                          // Move its content within bounds.
      
                          flick.returnToBounds()
                      }
      
                      Image {
                          id: image
                          width: flick.contentWidth
                          height: flick.contentHeight
                          fillMode: Image.PreserveAspectFit
                          MouseArea {
                              anchors.fill: parent
                              onDoubleClicked: {
                                  flick.resizeContent(flick.contentWidth*1.5, flick.contentHeight*1.5, Qt.point(mouseX, mouseY))
                              }
                              onWheel: {
                                  if (wheel.angleDelta.y/120*flick.contentWidth*0.1+flick.contentWidth > flick.width && wheel.angleDelta.y/120*flick.contentHeight*0.1+flick.contentHeight > flick.height)
                                  {
                                      flick.resizeContent(wheel.angleDelta.y/120*flick.contentWidth*0.1+flick.contentWidth, wheel.angleDelta.y/120*flick.contentHeight*0.1+flick.contentHeight, Qt.point(flick.contentX + mouse.mouseX, flick.contentY + mouse.mouseY))
                                      flick.returnToBounds()
                                  }
                                  else {
                                      flick.resizeContent(flick.width, flick.height, Qt.point(flick.width/2, flick.height/2))
                                      flick.returnToBounds()
                                  }
                              }
                          }
                      }
                  }
              }
      
      L 1 Reply Last reply
      1
      • S stcorp

        I have some code of how I did it. I haven't made any efforts to make it nice, but it does work. It also allows zooming in using a mouse wheel or by double clicking, so it is cross platform. I hope this helps you. If you have any questions just ask. You will need to set a source for the image for this to work, and possibly change some things. Mostly this was just to show you how I did it using a Flickable and a PinchArea

        Flickable {
                    id: flick
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    contentHeight: height
                    contentWidth: width
        
                    clip: true
                    ScrollBar.vertical: ScrollBar{active: flick.contentHeight/flick.height > 1 ? true : false}
                    ScrollBar.horizontal: ScrollBar{active: flick.contentWidth/flick.width > 1 ? true : false}
                    boundsBehavior: Flickable.StopAtBounds
        
                    PinchArea {
                        id: pinch
                        width: Math.max(flick.contentWidth, flick.width)
                        height: Math.max(flick.contentHeight, flick.height)
        
                        property real initialWidth
                        property real initialHeight
        
                        onPinchStarted: {
                            initialWidth = flick.contentWidth
                            initialHeight = flick.contentHeight
                        }
        
                        onPinchUpdated: {
                            var newWidth = initialWidth * pinch.scale
                            var newHeight = initialHeight * pinch.scale
        
                            if (newWidth < flick.width || newHeight < flick.height) {
                                flick.resizeContent(flick.width, flick.height, Qt.point(flick.width/2, flick.height/2))
                            }
                            else {
                                flick.contentX += pinch.previousCenter.x - pinch.center.x
                                flick.contentY += pinch.previousCenter.y - pinch.center.y
                                flick.resizeContent(initialWidth * pinch.scale, initialHeight * pinch.scale, pinch.center)
                            }
                        }
        
                        onPinchFinished: {
                            // Move its content within bounds.
        
                            flick.returnToBounds()
                        }
        
                        Image {
                            id: image
                            width: flick.contentWidth
                            height: flick.contentHeight
                            fillMode: Image.PreserveAspectFit
                            MouseArea {
                                anchors.fill: parent
                                onDoubleClicked: {
                                    flick.resizeContent(flick.contentWidth*1.5, flick.contentHeight*1.5, Qt.point(mouseX, mouseY))
                                }
                                onWheel: {
                                    if (wheel.angleDelta.y/120*flick.contentWidth*0.1+flick.contentWidth > flick.width && wheel.angleDelta.y/120*flick.contentHeight*0.1+flick.contentHeight > flick.height)
                                    {
                                        flick.resizeContent(wheel.angleDelta.y/120*flick.contentWidth*0.1+flick.contentWidth, wheel.angleDelta.y/120*flick.contentHeight*0.1+flick.contentHeight, Qt.point(flick.contentX + mouse.mouseX, flick.contentY + mouse.mouseY))
                                        flick.returnToBounds()
                                    }
                                    else {
                                        flick.resizeContent(flick.width, flick.height, Qt.point(flick.width/2, flick.height/2))
                                        flick.returnToBounds()
                                    }
                                }
                            }
                        }
                    }
                }
        
        L Offline
        L Offline
        larkei15
        wrote on last edited by
        #3

        @stcorp I'll have to look at that later, but I didn't know about the resizeContent method from Flickable. From waht I'm seeing in your code and in the documentation, this looks like a good solution. Thanks!

        1 Reply Last reply
        0
        • C Offline
          C Offline
          Choudhary Ramesh
          wrote on last edited by Choudhary Ramesh
          #4
          This post is deleted!
          1 Reply Last reply
          0
          • C Offline
            C Offline
            Choudhary Ramesh
            wrote on last edited by
            #5

            QZoomableImage

            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