Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Solved QML SplitView - handleDelegate

    QML and Qt Quick
    2
    14
    5902
    Loading More Posts
    • 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
      peteritv last edited by

      Hi all!

      I use a horizontal SplitView in QML with 2 children (let's say: Rectangles).
      When the SplitView handle is dragged, I want to calculate the left/right ratio and save the value for further processing (store it in settings or so).

      The documentation (http://doc.qt.io/qt-5/qml-qtquick-controls-splitview.html#details) mentions something like "handleDelegate Component" which seems to be of some use, but it only mentions readonly properties. Is it so that the delegate will be activated on any SplitView event, and I use the properties to find out what exactly happened?

      The editor also suggests the existance of an event called "on__HandlesChanged: ". Maybe that is the way to go?

      Does anyone know how to implement such a thing?
      Maybe some example?

      T.I.A!

      1 Reply Last reply Reply Quote 0
      • p3c0
        p3c0 Moderators last edited by

        @peteritv

        Is it so that the delegate will be activated on any SplitView event, and I use the properties to find out what exactly happened?

        There is already a default one activated i.e the thin vertical 1 width line which you click and drag.
        You can override it and create new one as:

        handleDelegate: Rectangle {
            width: 20
            color: "red"
        }
        

        The editor also suggests the existance of an event called "on__HandlesChanged: ". Maybe that is the way to go?

        Not sure. This is a private property and may change in future and so cant be relied on.

        Does anyone know how to implement such a thing?

        When the handle is moved the items which it holds are resized too. So you can monitor these size change in your Rectangles ?

        157

        1 Reply Last reply Reply Quote 0
        • P
          peteritv last edited by

          @p3c0 : Thanx for your reply!

          Now I know how that delegate works :)

          But now for the resizing stuff, this is my simplified QML so far:

          Item {
              id: mainItem
              anchors.fill: parent
          
              SplitView {
                  id: splitMain
                  orientation: Qt.Horizontal
                  anchors.fill: parent
                  property var ratio: [ 0.6, 0.4 ]
                  Rectangle { width: splitMain.width * splitMain.ratio[0] }
                  Rectangle { width: splitMain.width * splitMain.ratio[1] }
                  handleDelegate: Rectangle { width: 4; color: "red" }
              }
          }
          

          I gave the splitview a dynamic property "ratio" which is used to calculate the width of children. Children will be created dynamiccally later on, so this code just illustrates.

          Point is that the width of a child is calculated from ratio, so using a child event to change the ratio will cause a circular reference, right?

          So I need some kind of event at the splitMain level that signals the user is fiddling with the handles. I tried onChildrenChanged and onChildrenRectChanged, but those do not seem to be fired.

          To indicate what I want, I tried the child.onWidthChanged anyway, and surprisingly it kinda works, besides the fact that the first initialization immediately resets ratio to 0.

          Item {
              id: mainItem
              anchors.fill: parent
          
              SplitView {
                  id: splitMain
                  orientation: Qt.Horizontal
                  anchors.fill: parent
                  property var ratio: [ 0.6, 0.4 ]
          
                  Rectangle {
                      id: r1
                      width: splitMain.width * splitMain.ratio[0];
                      Text { text: splitMain.ratio[0] }
                      onWidthChanged: {
                          if (splitMain.resizing ) splitMain.ratioChanged()
                      }
                  }
                  Rectangle {
                      id: r2
                      width: splitMain.width * splitMain.ratio[1];
                      Text { text: splitMain.ratio[1] }
                  }
                  handleDelegate: Rectangle { width: 4; color: "red" }
          
                  onRatioChanged: {
                      ratio[0] = r1.width / width
                      ratio[1] = (r2.width + 4) / width
                  }
              }
          }
          

          Any ideas on how to fix this?

          1 Reply Last reply Reply Quote 0
          • P
            peteritv last edited by

            A few hours later, and after a lot of trial & error, I came up with this result, that is supposed to work for both horizontal as vertical SplitView, and with just 2 children:

            import QtQuick 2.6
            import QtQuick.Controls 1.5
            import QtQuick.Layouts 1.3
            
            Item {
                id: mainItem
                anchors.fill: parent
            
                SplitView {
                    id: splitMain
                    orientation: Qt.Vertical
                    anchors.fill: parent
                    signal handleChanged()
                    property real ratio: 0.6
            
                    Rectangle {
                        id: r1
                        width: if (splitMain.orientation == Qt.Horizontal) {
                                   splitMain.width * splitMain.ratio
                               }
                        height: if (splitMain.orientation == Qt.Vertical) {
                                    splitMain.height * splitMain.ratio
                                }
                        Text { text: splitMain.ratio.toFixed(2) }
                        onWidthChanged: {
                            if ( (splitMain.orientation == Qt.Horizontal) && splitMain.resizing )
                                splitMain.handleChanged()
                        }
                        onHeightChanged: {
                            if ( (splitMain.orientation == Qt.Vertical) && splitMain.resizing )
                                splitMain.handleChanged()
                        }
                    }
                    Rectangle {
                        id: r2
                        Layout.fillWidth: true
                        Layout.fillHeight: true
                    }
                    handleDelegate: Rectangle {
                        width: (splitMain.orientation == Qt.Horizontal) ? 4 : 0
                        height: (splitMain.orientation == Qt.Vertical) ? 4 : 0
                        color: "red"
                    }
            
                    onHandleChanged: {
                        ratio = (splitMain.orientation == Qt.Horizontal) ? r1.width / width : r1.height / height
                        console.log("handle changed to ratio " + ratio.toFixed(2))
                    }
                }
            }
            

            As you can see, I declared an event "handleChanged" that is triggered when width/height (depending on SplitView orientation) of the children changes.

            Now I am 95% happy!
            In horizontal orientation this works like a charm, but when changed to vertical (splitMain.orientation = Qt.Vertical) somehow the initial ratio get's lost?

            Please???? Any help will be GREATLY appreciated!

            1 Reply Last reply Reply Quote 0
            • P
              peteritv last edited by

              OK, I dug a little deeper into the problem with this code:

              Item {
                  id: mainItem
                  anchors.fill: parent
              
                  SplitView {
                      id: splitMain
                      orientation: Qt.Horizontal
                      anchors.fill: parent
                      signal handleChanged
                      property real ratio: 0.6
              
                      Rectangle {
                          id: r1
                          width: {
                              if (splitMain.orientation == Qt.Horizontal) {
                                  console.log("width: " + splitMain.width)
                                  return splitMain.width * splitMain.ratio
                              }
                          }
                          height: {
                              if (splitMain.orientation == Qt.Vertical) {
                                  console.log("height: " + splitMain.height)
                                  return splitMain.height * splitMain.ratio
                              }
                          }
                          Text {
                              text: splitMain.ratio.toFixed(2)
                          }
                          onWidthChanged: {
                              if ((splitMain.orientation == Qt.Horizontal)
                                      && splitMain.resizing)
                                  splitMain.handleChanged()
                          }
                          onHeightChanged: {
                              if ((splitMain.orientation == Qt.Vertical)
                                      && splitMain.resizing)
                                  splitMain.handleChanged()
                          }
                      }
                      Rectangle {
                          id: r2
                          Layout.fillWidth: if (splitMain.orientation == Qt.Horizontal)
                                                true
                          Layout.fillHeight: if (splitMain.orientation == Qt.Vertical)
                                                 true
                      }
                      handleDelegate: Rectangle {
                          width: (splitMain.orientation == Qt.Horizontal) ? 4 : 0
                          height: (splitMain.orientation == Qt.Vertical) ? 4 : 0
                          color: "red"
                      }
              
                      onHandleChanged: {
                          ratio = (splitMain.orientation == Qt.Horizontal) ? r1.width / width : r1.height / height
                          console.log("handle changed to ratio " + ratio.toFixed(2))
                      }
                  }
              }
              

              Now on horizontal orientation, I get this output after initialization:

              Starting /home/peter/V-PlaySDK/5.7/gcc_64/bin/qmlscene...
              qml: width: 0
              file:///home/peter/Projects/BridgeComponents/MainForm.ui.qml:48:32: Unable to assign [undefined] to bool
              qml: width: 800
              

              On vertical orientation I get this:

              Starting /home/peter/V-PlaySDK/5.7/gcc_64/bin/qmlscene...
              qml: height: 0
              qml: height: -21
              file:///home/peter/Projects/BridgeComponents/MainForm.ui.qml:46:31: Unable to assign [undefined] to bool
              

              and then it stops...

              Now I start to think there is more to this problem than meets the eye, so here is my main QML:

              import QtQuick 2.6
              import QtQuick.Controls 1.5
              
              ApplicationWindow {
                  visible: true
                  width: 800
                  height: 600
                  title: qsTr("Bridge layout")
              
                  menuBar: MenuBar {
                      Menu {
                          title: qsTr("File")
                          MenuItem {
                              text: qsTr("&Open")
                              onTriggered: console.log("Open action triggered");
                          }
                          MenuItem {
                              text: qsTr("Exit")
                              onTriggered: Qt.quit();
                          }
                      }
                  }
              
                  MainForm {
                      anchors.fill: parent
                  }
              }
              

              Now does that not CLEARLY state that the default height is 600?

              So how come the default width is being handled OK, but the height not?

              And both (horizontal and vertical) complain about "Unable to assign [undefined] to bool"? What is that about?

              1 Reply Last reply Reply Quote 0
              • P
                peteritv last edited by

                AAAAAHHHHHHH!!!!!!!!!!

                I removed the menuBar from the main QML, and now IT IS WORKING!!!

                Is this a BUG or am I just newbie enough to not understand?

                1 Reply Last reply Reply Quote 0
                • P
                  peteritv last edited by

                  There is still the matter of the "Unable to assign [undefined] to bool" though...

                  Any suggestions?

                  1 Reply Last reply Reply Quote 0
                  • P
                    peteritv last edited by

                    OK, solved that too!

                    Layout.fillWidth and Layout.fillHeight do not like to be unassigned when you call on them, so this code solves that problem:

                            Rectangle {
                                id: r2
                                Layout.fillWidth: (splitMain.orientation == Qt.Horizontal) ? true : false
                                Layout.fillHeight: (splitMain.orientation == Qt.Vertical) ? true : false
                            }
                    

                    I guess I am happy now!

                    But I am not closing this topic yet, because the main reason why I started this topic was:

                    When you DO NOT touch the SplitView handle, and you resize the Window, then the SplitView resizes with it, keeping initial aspect ratio. However, when u touch the handle, all bets or off and resizing the Window does no longer keep aspect ratio.

                    Now I am sure there are some real QML guru's out there that can explain?

                    Greetz,
                    Peter

                    1 Reply Last reply Reply Quote 0
                    • P
                      peteritv last edited by peteritv

                      Should I make that a new Topic?

                      I already had a topic for that, but deleted it now, due to new knowledge :)

                      So how to resize the SplitView when the handle has been touched, and the container resizes?

                      1 Reply Last reply Reply Quote 0
                      • P
                        peteritv last edited by

                        BTW: I think that Layout.fillWidth and Layout.fillHeight should BOTH accept "undefined", and keep their current value, or is it just me who thinks so?

                        1 Reply Last reply Reply Quote 0
                        • P
                          peteritv last edited by

                          The higher layer programming languages get, the more things are being taken for granted! I still dream of the times that every bit and byte had to be accounted for when programming in direct machine language :)

                          1 Reply Last reply Reply Quote 0
                          • P
                            peteritv last edited by

                            Maybe I can get a vote here?

                            Who thinks Layout.fillWidth and Layout.fillHeight should accept "undefined" and keep there current value?

                            1 Reply Last reply Reply Quote 0
                            • P
                              peteritv last edited by

                              Vote + if you agree, vote - otherwise...

                              1 Reply Last reply Reply Quote 0
                              • P
                                peteritv last edited by

                                I'll continue this on a new Topic...

                                This topic has reached its goal, and so I will will mark it is such.

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post