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. switching from QGraphicsView to QML
QtWS25 Last Chance

switching from QGraphicsView to QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
11 Posts 2 Posters 4.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.
  • M Offline
    M Offline
    Marek
    wrote on last edited by
    #1

    Hi,

    I need some guideline, how to achieve in QML what I have done in QGraphicsView.
    I have a QGraphicsView in which I have one big custom QGraphicsPixmapItem with around 100 smaller custom QGraphicsPixmapItem at specific x,y positions. At application start mainItem is scaled to fit the view, then user can stretch this item with pinch gesture (child items are stretched too), then user can move mainItem in view but with restrictions - top left corner of mainItem must not cross top left corner of the view, and bottom right corner must not cross bottom left corner of the view - classic case, picture in view is twice the size of the view itself.
    So I need QML equivalent for QGrapvicsView signal that view is ready and has width and height

    void showEvent(QShowEvent * event);
    void resizeEvent(QResizeEvent *event);
    

    setting scale for mainView item (and its children), something like:

    floorData->transform.setMatrix(floorData->scale/(double)100,0,0,0,floorData->scale/(double)100,0,0,0,1);
    floorData->mainviewItem->setTransform(floorData->transform);
    

    and some way to control mainItem movement, which is done in subclassed item:

    QVariant MainItem::itemChange(GraphicsItemChange change, const QVariant &value)
    

    Is this doable in QML, well I'm sure it is, but what is the concept for that?

    Best Regards
    Marek

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      Some basic way to achieve this:

      Item { // Assuming this is your floor item
        onXChanged: if (x < 0) x = 0
        onYChanged: if (y < 0) y = 0
      }
      

      Or if you use anchors/ layouts to position items, you kind of get this for free. Modifying position can then be achieved by specifying anchor margins.

      (Z(:^

      M 1 Reply Last reply
      0
      • sierdzioS sierdzio

        Some basic way to achieve this:

        Item { // Assuming this is your floor item
          onXChanged: if (x < 0) x = 0
          onYChanged: if (y < 0) y = 0
        }
        

        Or if you use anchors/ layouts to position items, you kind of get this for free. Modifying position can then be achieved by specifying anchor margins.

        M Offline
        M Offline
        Marek
        wrote on last edited by
        #3

        @sierdzio thanks for hint. I'm quite new to QML although I'm writing widget apps for some years.
        So now I have main.qml and SwipeView with two pages, second one is for QGraphicsView equivalent
        Is there any equivalent in QML ?

        With anchor approach it would be something like ?:

        MainItem {
            anchor.left: parent.left - (calculated size diff between MainItem width and screen width)
        |
        

        this size should be calculated whenever user stretches MainItem, right?

        1 Reply Last reply
        0
        • sierdzioS Offline
          sierdzioS Offline
          sierdzio
          Moderators
          wrote on last edited by
          #4

          There is no equivalent ot QGraphicsView in QML. They work on different principles. I strongly recommend doing some simple apps first, just to get the hang of it. QML is easy to learn, but you will need some time to get adjusted to different way of thinking than in imperative code.

          Regarding anchors. You can't add or substract anything from an anchor. You can modify the margin, however.

          MainItem {
              anchors.left: parent.left
              anchors.leftMargin: 20
          }
          

          Another possibility: consider using Flickable element. I think it might work out very well in your use case. It already supports zooming and flicking, just like you need. And you can get the exact behaviour you need using boundsBehaviour property. Exact position of content item (your floor) can be accessed with contentY and contentX properties, etc.

          (Z(:^

          M 1 Reply Last reply
          1
          • sierdzioS sierdzio

            There is no equivalent ot QGraphicsView in QML. They work on different principles. I strongly recommend doing some simple apps first, just to get the hang of it. QML is easy to learn, but you will need some time to get adjusted to different way of thinking than in imperative code.

            Regarding anchors. You can't add or substract anything from an anchor. You can modify the margin, however.

            MainItem {
                anchors.left: parent.left
                anchors.leftMargin: 20
            }
            

            Another possibility: consider using Flickable element. I think it might work out very well in your use case. It already supports zooming and flicking, just like you need. And you can get the exact behaviour you need using boundsBehaviour property. Exact position of content item (your floor) can be accessed with contentY and contentX properties, etc.

            M Offline
            M Offline
            Marek
            wrote on last edited by
            #5

            @sierdzio Thanks for flickable example, there is also one in QtCreator which I will try to implement.
            I have an impression that I have seen somewhere in examples that right part of the binding was an expression calculated from some function in javascript or from C++ bindings.

            Best Regards
            Marek

            1 Reply Last reply
            0
            • sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by
              #6

              @Marek said in switching from QGraphicsView to QML:

              I have an impression that I have seen somewhere in examples that right part of the binding was an expression calculated from some function in javascript or from C++ bindings.

              Yes, that is correct. You can easily write stuff like:

              x: 15 * someProperty
              y: 80 + SomeQObject.someFunction()
              

              etc. However, in case of anchors property, it expects not a numerical value, but an actual anchor from another object. Hence in that case, margins are needed.

              (Z(:^

              M 1 Reply Last reply
              0
              • sierdzioS sierdzio

                @Marek said in switching from QGraphicsView to QML:

                I have an impression that I have seen somewhere in examples that right part of the binding was an expression calculated from some function in javascript or from C++ bindings.

                Yes, that is correct. You can easily write stuff like:

                x: 15 * someProperty
                y: 80 + SomeQObject.someFunction()
                

                etc. However, in case of anchors property, it expects not a numerical value, but an actual anchor from another object. Hence in that case, margins are needed.

                M Offline
                M Offline
                Marek
                wrote on last edited by
                #7

                @sierdzio I have copied flick-resize into my app and played for a while, seems to be what I need.
                Howver, I cant work out how to have two images parent and a children, where children is also affected by pinch gesture
                For instance, child image is positioned in (100,100)px of the main mapImage, then pinch gesture resizes the mapImage but child image remains in the same scale and in fixed position over the scaled image.

                Flickable {
                        id: flick
                        anchors.fill: parent
                        contentWidth: 4109
                        contentHeight: 824
                
                        PinchArea {
                            id:pinch
                            width: Math.max(flick.contentWidth, flick.width)
                            height: Math.max(flick.contentHeight, flick.height)
                
                            property real initialWidth
                            property real initialHeight
                            //![0]
                            onPinchStarted: {
                                initialWidth = flick.contentWidth
                                initialHeight = flick.contentHeight
                            }
                
                            onPinchUpdated: {
                                // adjust content pos due to drag
                                flick.contentX += pinch.previousCenter.x - pinch.center.x
                                flick.contentY += pinch.previousCenter.y - pinch.center.y
                
                                // resize content
                                if(initialWidth * pinch.scale>500 && initialHeight * pinch.scale>200)
                                    flick.resizeContent(initialWidth * pinch.scale, initialHeight * pinch.scale, pinch.center)
                            }
                
                            onPinchFinished: {
                                // Move its content within bounds.
                                flick.returnToBounds()
                                console.log("pinch updated width:"+flick.contentWidth+" height:"+flick.contentHeight+" scale:"+pinch.scale)
                            }
                            //![0]
                
                            Rectangle {
                                width: flick.contentWidth
                                height: flick.contentHeight
                                color: "white"
                                Image {
                                    id: mapImage
                                    anchors.fill: parent
                                    source: "images/mapa.jpg"
                                    MouseArea {
                                        anchors.fill: parent
                                        onDoubleClicked: {
                                            flick.contentWidth = 4109
                                            flick.contentHeight = 824
                                        }
                                    }
                                    onScaleChanged: {
                                        console.log("scale changed:"+scale)
                                    }
                                    Image {
                                        id: childImage
                                        x: 100
                                        y: 100
                                        source: "images/seat_icon.jpg"
                                    }
                                }
                            }
                        }
                    }
                

                Is this a parent-child relation problem ? Scale of the mapImage does not change.
                I'm looking for a similar behavior as with QGraphicsPixmapItem. When I have parent and child and I apply setScale to parent child is also scaled and his position is in parent coordinates so it seems it moves with parent image when it is resized.

                Best Regards
                Marek

                M 1 Reply Last reply
                0
                • M Marek

                  @sierdzio I have copied flick-resize into my app and played for a while, seems to be what I need.
                  Howver, I cant work out how to have two images parent and a children, where children is also affected by pinch gesture
                  For instance, child image is positioned in (100,100)px of the main mapImage, then pinch gesture resizes the mapImage but child image remains in the same scale and in fixed position over the scaled image.

                  Flickable {
                          id: flick
                          anchors.fill: parent
                          contentWidth: 4109
                          contentHeight: 824
                  
                          PinchArea {
                              id:pinch
                              width: Math.max(flick.contentWidth, flick.width)
                              height: Math.max(flick.contentHeight, flick.height)
                  
                              property real initialWidth
                              property real initialHeight
                              //![0]
                              onPinchStarted: {
                                  initialWidth = flick.contentWidth
                                  initialHeight = flick.contentHeight
                              }
                  
                              onPinchUpdated: {
                                  // adjust content pos due to drag
                                  flick.contentX += pinch.previousCenter.x - pinch.center.x
                                  flick.contentY += pinch.previousCenter.y - pinch.center.y
                  
                                  // resize content
                                  if(initialWidth * pinch.scale>500 && initialHeight * pinch.scale>200)
                                      flick.resizeContent(initialWidth * pinch.scale, initialHeight * pinch.scale, pinch.center)
                              }
                  
                              onPinchFinished: {
                                  // Move its content within bounds.
                                  flick.returnToBounds()
                                  console.log("pinch updated width:"+flick.contentWidth+" height:"+flick.contentHeight+" scale:"+pinch.scale)
                              }
                              //![0]
                  
                              Rectangle {
                                  width: flick.contentWidth
                                  height: flick.contentHeight
                                  color: "white"
                                  Image {
                                      id: mapImage
                                      anchors.fill: parent
                                      source: "images/mapa.jpg"
                                      MouseArea {
                                          anchors.fill: parent
                                          onDoubleClicked: {
                                              flick.contentWidth = 4109
                                              flick.contentHeight = 824
                                          }
                                      }
                                      onScaleChanged: {
                                          console.log("scale changed:"+scale)
                                      }
                                      Image {
                                          id: childImage
                                          x: 100
                                          y: 100
                                          source: "images/seat_icon.jpg"
                                      }
                                  }
                              }
                          }
                      }
                  

                  Is this a parent-child relation problem ? Scale of the mapImage does not change.
                  I'm looking for a similar behavior as with QGraphicsPixmapItem. When I have parent and child and I apply setScale to parent child is also scaled and his position is in parent coordinates so it seems it moves with parent image when it is resized.

                  Best Regards
                  Marek

                  M Offline
                  M Offline
                  Marek
                  wrote on last edited by
                  #8

                  I have modified example to work with onWheel signal, easier to work with on desktop.
                  Child image item is repositioned, but there is slight error with position, due to setting "scale" for child item.
                  Child Image moves towards bottom right corner when I scale down main image.
                  Can someone advice me on how to keep this child image in fixed position when flickable element is resized ?

                  Flickable {
                          id: flick
                          anchors.fill: parent
                          contentWidth: 4109
                          contentHeight: 824
                  
                          Image {
                              id: mapImage
                              anchors.fill: parent
                              source: "images/mapa.jpg"
                              property real itemScale: 1
                              MouseArea {
                                  anchors.fill: parent
                  
                                  onWheel: {
                                      if(wheel.angleDelta.y>0)
                                          parent.itemScale+=0.1
                                      else
                                          parent.itemScale+=-0.1 
                                       flick.resizeContent(mapImage.sourceSize.width*parent.itemScale,mapImage.sourceSize.height*parent.itemScale,Qt.point(mouseX,mouseY))
                  
                                      flick.returnToBounds()
                                  }
                              }
                              Image {
                                  id: childImage
                                  x: 100*parent.itemScale
                                  y: 100*parent.itemScale
                                  scale: parent.itemScale
                                  source: "images/seat_icon.jpg"
                  
                              }
                          }
                      }
                  

                  Best Regards
                  Marek

                  1 Reply Last reply
                  0
                  • sierdzioS Offline
                    sierdzioS Offline
                    sierdzio
                    Moderators
                    wrote on last edited by sierdzio
                    #9

                    @Marek said in switching from QGraphicsView to QML:

                    anchors.fill: parent

                    I suspect that might be the issue: you are trying to anchor to an object that is designed for scrolling (that is: it is designed to handle components larger than itself).

                    So, my recommendations:

                    • remove anchors from mapImage
                    • give mapImage a fixed size
                    • when zooming/ pinching, modify scale of mapImage

                    Feel free to take a look at/clone/reuse my code from CCF it's old, very old code, but it used to work and scale contents of a Flickable correctly.

                    (Z(:^

                    M 1 Reply Last reply
                    1
                    • sierdzioS sierdzio

                      @Marek said in switching from QGraphicsView to QML:

                      anchors.fill: parent

                      I suspect that might be the issue: you are trying to anchor to an object that is designed for scrolling (that is: it is designed to handle components larger than itself).

                      So, my recommendations:

                      • remove anchors from mapImage
                      • give mapImage a fixed size
                      • when zooming/ pinching, modify scale of mapImage

                      Feel free to take a look at/clone/reuse my code from CCF it's old, very old code, but it used to work and scale contents of a Flickable correctly.

                      M Offline
                      M Offline
                      Marek
                      wrote on last edited by
                      #10

                      @sierdzio Thanks for hint and for Your help, I will look into your code.
                      I have just returned from the gym and during workout I have figured out the problem ;) Probably more oxygen for the brain.
                      Instead of child Image which need to be scaled (and then the problem appears) I have Rectangle which is scaled, and inside rectangle there is an image. Works very well.

                      Rectangle {
                          width:sourceImageWidth*parent.itemScale
                          height:sourceImageHeight*parent.itemScale
                          x: 100*parent.itemScale
                          y: 100*parent.itemScale
                          Image {
                              id: childImage
                              anchors.fill: parent
                              source: "images/seat_icon.jpg"
                      
                          }
                      }
                      

                      Just need to check whether this will work well with 100 child Images on top the mapImage.
                      So partly solved ;) Now I need to load them dynamically so next questions will follow ;)

                      Best Regards
                      Marek

                      1 Reply Last reply
                      1
                      • sierdzioS Offline
                        sierdzioS Offline
                        sierdzio
                        Moderators
                        wrote on last edited by
                        #11

                        OK, good news. Happy coding :-)

                        (Z(:^

                        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