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. Speedometer
Forum Updated to NodeBB v4.3 + New Features

Speedometer

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
22 Posts 4 Posters 3.1k Views 1 Watching
  • 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.
  • MarkkyboyM Markkyboy

    @Darq I think you should take a look at this GitHub, it offers all kinds of gauges, including one with needle movement. I have personally taken many cues from this code and have developed dozens of speedometer types. https://github.com/arunpkqt/CircularSlider
    I think you can learn a lot from this code and build what you like.

    D Offline
    D Offline
    Darq
    wrote on last edited by
    #11

    @Markkyboy How to limit the movement of the hand? What I want is for it not to show values ​​below 50. To sum up, the movement of the pointer would only start after reaching 50.

    MarkkyboyM 1 Reply Last reply
    0
    • D Darq

      @Markkyboy How to limit the movement of the hand? What I want is for it not to show values ​​below 50. To sum up, the movement of the pointer would only start after reaching 50.

      MarkkyboyM Offline
      MarkkyboyM Offline
      Markkyboy
      wrote on last edited by Markkyboy
      #12

      @Darq - without seeing what code you have so far, I don't know how to answer your question. Please post some working code, or what you have so far. It is much easier to see and have ideas when one can see some code.

      EDIT: As I am already using CircularSlider from arunpkqt in several projects, I can easily adapt my code with your code and possibly work out a way to get what you want.

      Don't just sit there standing around, pick up a shovel and sweep up!

      I live by the sea, not in it.

      D 1 Reply Last reply
      0
      • MarkkyboyM Markkyboy

        @Darq - without seeing what code you have so far, I don't know how to answer your question. Please post some working code, or what you have so far. It is much easier to see and have ideas when one can see some code.

        EDIT: As I am already using CircularSlider from arunpkqt in several projects, I can easily adapt my code with your code and possibly work out a way to get what you want.

        D Offline
        D Offline
        Darq
        wrote on last edited by Darq
        #13

        @Markkyboy
        HmiImage {
        id: pointer1
        anchors.centerIn: parent
        source: "icons/abc.png"
        rotation: 2.25*XXX+225
        }

        XXX is my measured value
        225 is an angle where the value is 0
        2.25 is a degrees conversion, so for example, my value indicates 1, which corresponds to 2.25 degrees

        MarkkyboyM 1 Reply Last reply
        0
        • D Darq

          @Markkyboy
          HmiImage {
          id: pointer1
          anchors.centerIn: parent
          source: "icons/abc.png"
          rotation: 2.25*XXX+225
          }

          XXX is my measured value
          225 is an angle where the value is 0
          2.25 is a degrees conversion, so for example, my value indicates 1, which corresponds to 2.25 degrees

          MarkkyboyM Offline
          MarkkyboyM Offline
          Markkyboy
          wrote on last edited by
          #14

          @Darq - this small bit of code is not enough for me to work with.

          Don't just sit there standing around, pick up a shovel and sweep up!

          I live by the sea, not in it.

          D 1 Reply Last reply
          0
          • MarkkyboyM Markkyboy

            @Darq - this small bit of code is not enough for me to work with.

            D Offline
            D Offline
            Darq
            wrote on last edited by
            #15

            @Markkyboy There is almost no more code there. There is only one more HmiImage defining the appearance of the shield (it loads the shields, i.e. a png file). In this code snippet there is only the "source" command which specifies the location of the png file. The png file has a scale drawn on it. The hint is called by the code above, which specifies its position (e.g. point 0 is at 225 degrees, so in the png file 0 is drawn at 225 degrees).

            MarkkyboyM 1 Reply Last reply
            0
            • D Darq

              @Markkyboy There is almost no more code there. There is only one more HmiImage defining the appearance of the shield (it loads the shields, i.e. a png file). In this code snippet there is only the "source" command which specifies the location of the png file. The png file has a scale drawn on it. The hint is called by the code above, which specifies its position (e.g. point 0 is at 225 degrees, so in the png file 0 is drawn at 225 degrees).

              MarkkyboyM Offline
              MarkkyboyM Offline
              Markkyboy
              wrote on last edited by
              #16

              @Darq - sorry, I just don't understand what you're trying to do. I can take plenty of wild guesses but I don't have the time to do so.

              Making a functional speedometer requires a lot more code in my opinion. You could at the very least show an image/screenshot of what you have, otherwise I'm in the dark. At the very least, a mock up image of what you're wanting might be helpful.

              What kind of speedo only functions when hitting 50?, what is the idea of this?, 50 what?, kmh?, mph?, kts?.....?

              What is "icons/abc.png"?, what does it look like?

              What is "hmiImage", where is that code?

              Are you taking ANY cues from arunpkqt's application?

              Seriously now, what you write here gives me very little to go on. I'm not sure I can help you.

              Don't just sit there standing around, pick up a shovel and sweep up!

              I live by the sea, not in it.

              1 Reply Last reply
              0
              • MarkkyboyM Offline
                MarkkyboyM Offline
                Markkyboy
                wrote on last edited by Markkyboy
                #17

                Rather than leave you completely in the dark, Darq, here's some full code to make a working speedometer. Perhaps from this you can make it do what you want/require.

                import QtQuick
                import QtQuick.Controls
                
                Item {
                    id: control
                
                    property int trackWidth: 20
                    property int progressWidth: 20
                    property color trackColor: "#505050"
                    property color progressColor: "#3a4ec4"
                    property bool hideTrack: false
                    property bool hideProgress: false
                
                    property color handleColor: "#fefefe"
                    property int handleWidth: 80
                    property int handleHeight: 80
                    property int handleRadius: 40
                    property int handleVerticalOffset: 0
                
                    property real startAngle: 0
                    property real endAngle: 360
                    property real minValue: 0.0
                    property real maxValue: 1.0
                
                    property real value: 0.0
                    readonly property alias angle: internal.angle
                
                
                    property real stepSize: 0
                    property bool snap: false
                    property Component handle: null
                    readonly property alias pressed: trackMouse.pressed
                
                    property bool interactive: true
                    property alias cursorShape: trackMouse.cursorShape
                
                    implicitWidth: 250
                    implicitHeight: 250
                
                    Binding {
                        target: control
                        property: "value"
                        value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                        when: internal.setUpdatedValue
                    }
                
                    QtObject {
                        id: internal
                
                        property point centerPt: Qt.point(control.width / 2, control.height / 2)
                        property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
                        property real actualSpanAngle: control.endAngle - control.startAngle
                        property color transparentColor: "transparent"
                        property color trackColor: control.trackColor
                        property bool setUpdatedValue: false
                        property real angleProxy: control.startAngle
                        property real snappedValue: 0.0
                        readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
                
                        function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
                            return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
                        }
                
                        function updateAngle(angleVal) {
                            if (angleVal < 0)
                                angleVal += 360;
                
                            if ((angleVal >= control.startAngle) && (angleVal <= control.endAngle)) {
                                internal.setUpdatedValue = true;
                                internal.angleProxy = Qt.binding(function() { return angleVal; });
                                if(control.snap) {
                                    var mappedValue = internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                    var range = control.maxValue - control.minValue
                                    var effectiveStep = 2
                                    var actualVal = control.stepSize * Math.round(mappedValue / control.stepSize)
                                    internal.snappedValue = actualVal
                                }
                                internal.setUpdatedValue = false;
                            }
                        }
                    }
                
                    MouseArea {
                        anchors.fill: parent
                        enabled: control.interactive
                        onClicked: {
                            var outerRadius = Math.min(control.width, control.height)/ 2
                            var innerRadius = outerRadius - Math.max(control.trackWidth, 20);
                            var clickedDistance = (mouseX - internal.centerPt.x) * (mouseX - internal.centerPt.x) + (mouseY - internal.centerPt.y) * (mouseY - internal.centerPt.y);
                            var innerRadius2 = (innerRadius * innerRadius);
                            var outerRadius2 = (outerRadius * outerRadius);
                            var isOutOfInnerRadius = clickedDistance > innerRadius2;
                            var inInSideOuterRadius = clickedDistance <= outerRadius2;
                            if (inInSideOuterRadius && isOutOfInnerRadius) {
                                var angleDeg = Math.atan2(mouseY - internal.centerPt.y, mouseX - internal.centerPt.x) * 180 / Math.PI + 90;
                                internal.updateAngle(angleDeg);
                            }
                        }
                    }
                
                    // Handle Item
                    Item {
                        id: handleItem
                        visible: control.interactive
                
                        x: control.width / 2 - width / 2
                        y: control.height / 2 - height / 2
                        // make sure that the slider handle is always on top as we can set custom track or progress items
                        z: 2
                        width: control.handleWidth
                        height: control.handleHeight
                        antialiasing: true
                        transform: [
                            Translate {
                                y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.handleVerticalOffset
                            },
                            Rotation {
                                angle: control.angle
                                origin.x: handleItem.width / 2
                                origin.y: handleItem.height / 2
                            }
                        ]
                
                        MouseArea {
                            id: trackMouse
                            enabled: control.interactive
                
                            function getVal() {
                                var handlePoint = mapToItem(control, trackMouse.mouseX, trackMouse.mouseY);
                                // angle in degrees
                                var angleDeg = Math.atan2(handlePoint.y - internal.centerPt.y, handlePoint.x - internal.centerPt.x) * 180 / Math.PI + 90;
                                internal.updateAngle(angleDeg);
                            }
                
                            anchors.fill: parent
                            onPositionChanged: getVal()
                            onClicked: getVal()
                            cursorShape: Qt.ArrowCursor
                        }
                
                        Loader {
                            id: handleLoader
                
                            sourceComponent: control.handle ? handle : handleComponent
                        }
                    }
                
                    /// Default handle component
                    Component {
                        id: handleComponent
                
                        Rectangle {
                            width: control.handleWidth
                            height: control.handleHeight
                            color: control.handleColor
                            radius: control.handleRadius
                            antialiasing: true
                        }
                    }
                }
                
                
                import QtQuick
                import QtQuick.Controls
                import "../components"
                
                Page {
                    id: darqSpeedo
                
                    allowedOrientations: Orientation.All // this is specific to SailfishOS and can likely be omitted.
                
                    // imported from "../components"
                    CircularSlider {
                        id: speedometer
                        interactive: false
                        anchors.centerIn: parent
                        width: 1000
                        height: width
                        value: 0
                        startAngle: -108
                        endAngle: 108
                        minValue: 0
                        maxValue: 180
                        anchors {
                            verticalCenterOffset: 200
                            verticalCenter: parent.verticalCenter
                            horizontalCenter: parent.horizontalCenter
                        }
                        // Tickmarks around gauge
                        Repeater {
                            model: 37
                            Rectangle {
                                id: ones
                                width: 6
                                height: index % 4 === 0 ? 50 : 25
                                color: index % 4 === 0 ? "white" : "silver"
                                property real angle: index * 6
                                transform: [ Translate { x: parent.width / 2 - width / 2; y: -155 },
                                    Rotation {
                                        origin.x: parent.width / 2
                                        origin.y: parent.height / 2
                                        angle: ones.angle + parent.startAngle
                                    }
                                ]
                            }
                        }
                        // Numbers around gauge
                        Repeater {
                            model: 10
                            Label {
                                id: digits
                                text: index * 20
                                color: "white"
                                font { bold: true; pixelSize: 48 }
                                property real angle: index * 24
                                transform: [
                                    Translate {
                                        x: parent.width / 2 - width / 2
                                        y: -75 // distance from tickmarks
                                    },
                                    Rotation {
                                        origin.x: parent.width / 2
                                        origin.y: parent.height / 2
                                        angle: digits.angle + parent.startAngle
                                    }
                                ]
                                // keeps numbers horizontal
                                rotation: -digits.angle - parent.startAngle
                            }
                        }
                        // Needle hub
                        Rectangle {
                            anchors.centerIn: speedometer
                            width: 100
                            height: width
                            radius: width/2
                            color: "#a0545454"
                        }
                        // Needle/pointer
                        Repeater {
                            model: 1
                            Rectangle {
                                id: needle
                                width: 20
                                height: 450
                                color: "orange"
                                radius: 20
                                transform: [
                                    Translate {
                                        x: speedometer.width / 2 - width / 2
                                        y: 50 // needle distance from centre
                                    },
                                    Rotation {
                                        origin.x: speedometer.width / 2
                                        origin.y: speedometer.height / 2
                                        angle: speedometer.angle
                                    }
                                ]
                            }
                        }
                        // Animation for demo purposes
                        SequentialAnimation on value {
                            id: animation
                            loops: Animation.Infinite
                            running: true
                            NumberAnimation { from: 0; to: 180; duration: 2000 }
                            NumberAnimation { from: 180; to: 0; duration: 2000 }
                        }
                    }
                }
                
                

                NOTE: I use Page, as my apps are built for my mobile phone using SailfishOS. You don't have to use Page, you can likely swap it for Item instead.

                Screenshot_20231114_001.png

                Don't just sit there standing around, pick up a shovel and sweep up!

                I live by the sea, not in it.

                D S 2 Replies Last reply
                0
                • MarkkyboyM Markkyboy

                  Rather than leave you completely in the dark, Darq, here's some full code to make a working speedometer. Perhaps from this you can make it do what you want/require.

                  import QtQuick
                  import QtQuick.Controls
                  
                  Item {
                      id: control
                  
                      property int trackWidth: 20
                      property int progressWidth: 20
                      property color trackColor: "#505050"
                      property color progressColor: "#3a4ec4"
                      property bool hideTrack: false
                      property bool hideProgress: false
                  
                      property color handleColor: "#fefefe"
                      property int handleWidth: 80
                      property int handleHeight: 80
                      property int handleRadius: 40
                      property int handleVerticalOffset: 0
                  
                      property real startAngle: 0
                      property real endAngle: 360
                      property real minValue: 0.0
                      property real maxValue: 1.0
                  
                      property real value: 0.0
                      readonly property alias angle: internal.angle
                  
                  
                      property real stepSize: 0
                      property bool snap: false
                      property Component handle: null
                      readonly property alias pressed: trackMouse.pressed
                  
                      property bool interactive: true
                      property alias cursorShape: trackMouse.cursorShape
                  
                      implicitWidth: 250
                      implicitHeight: 250
                  
                      Binding {
                          target: control
                          property: "value"
                          value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                          when: internal.setUpdatedValue
                      }
                  
                      QtObject {
                          id: internal
                  
                          property point centerPt: Qt.point(control.width / 2, control.height / 2)
                          property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
                          property real actualSpanAngle: control.endAngle - control.startAngle
                          property color transparentColor: "transparent"
                          property color trackColor: control.trackColor
                          property bool setUpdatedValue: false
                          property real angleProxy: control.startAngle
                          property real snappedValue: 0.0
                          readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
                  
                          function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
                              return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
                          }
                  
                          function updateAngle(angleVal) {
                              if (angleVal < 0)
                                  angleVal += 360;
                  
                              if ((angleVal >= control.startAngle) && (angleVal <= control.endAngle)) {
                                  internal.setUpdatedValue = true;
                                  internal.angleProxy = Qt.binding(function() { return angleVal; });
                                  if(control.snap) {
                                      var mappedValue = internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                      var range = control.maxValue - control.minValue
                                      var effectiveStep = 2
                                      var actualVal = control.stepSize * Math.round(mappedValue / control.stepSize)
                                      internal.snappedValue = actualVal
                                  }
                                  internal.setUpdatedValue = false;
                              }
                          }
                      }
                  
                      MouseArea {
                          anchors.fill: parent
                          enabled: control.interactive
                          onClicked: {
                              var outerRadius = Math.min(control.width, control.height)/ 2
                              var innerRadius = outerRadius - Math.max(control.trackWidth, 20);
                              var clickedDistance = (mouseX - internal.centerPt.x) * (mouseX - internal.centerPt.x) + (mouseY - internal.centerPt.y) * (mouseY - internal.centerPt.y);
                              var innerRadius2 = (innerRadius * innerRadius);
                              var outerRadius2 = (outerRadius * outerRadius);
                              var isOutOfInnerRadius = clickedDistance > innerRadius2;
                              var inInSideOuterRadius = clickedDistance <= outerRadius2;
                              if (inInSideOuterRadius && isOutOfInnerRadius) {
                                  var angleDeg = Math.atan2(mouseY - internal.centerPt.y, mouseX - internal.centerPt.x) * 180 / Math.PI + 90;
                                  internal.updateAngle(angleDeg);
                              }
                          }
                      }
                  
                      // Handle Item
                      Item {
                          id: handleItem
                          visible: control.interactive
                  
                          x: control.width / 2 - width / 2
                          y: control.height / 2 - height / 2
                          // make sure that the slider handle is always on top as we can set custom track or progress items
                          z: 2
                          width: control.handleWidth
                          height: control.handleHeight
                          antialiasing: true
                          transform: [
                              Translate {
                                  y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.handleVerticalOffset
                              },
                              Rotation {
                                  angle: control.angle
                                  origin.x: handleItem.width / 2
                                  origin.y: handleItem.height / 2
                              }
                          ]
                  
                          MouseArea {
                              id: trackMouse
                              enabled: control.interactive
                  
                              function getVal() {
                                  var handlePoint = mapToItem(control, trackMouse.mouseX, trackMouse.mouseY);
                                  // angle in degrees
                                  var angleDeg = Math.atan2(handlePoint.y - internal.centerPt.y, handlePoint.x - internal.centerPt.x) * 180 / Math.PI + 90;
                                  internal.updateAngle(angleDeg);
                              }
                  
                              anchors.fill: parent
                              onPositionChanged: getVal()
                              onClicked: getVal()
                              cursorShape: Qt.ArrowCursor
                          }
                  
                          Loader {
                              id: handleLoader
                  
                              sourceComponent: control.handle ? handle : handleComponent
                          }
                      }
                  
                      /// Default handle component
                      Component {
                          id: handleComponent
                  
                          Rectangle {
                              width: control.handleWidth
                              height: control.handleHeight
                              color: control.handleColor
                              radius: control.handleRadius
                              antialiasing: true
                          }
                      }
                  }
                  
                  
                  import QtQuick
                  import QtQuick.Controls
                  import "../components"
                  
                  Page {
                      id: darqSpeedo
                  
                      allowedOrientations: Orientation.All // this is specific to SailfishOS and can likely be omitted.
                  
                      // imported from "../components"
                      CircularSlider {
                          id: speedometer
                          interactive: false
                          anchors.centerIn: parent
                          width: 1000
                          height: width
                          value: 0
                          startAngle: -108
                          endAngle: 108
                          minValue: 0
                          maxValue: 180
                          anchors {
                              verticalCenterOffset: 200
                              verticalCenter: parent.verticalCenter
                              horizontalCenter: parent.horizontalCenter
                          }
                          // Tickmarks around gauge
                          Repeater {
                              model: 37
                              Rectangle {
                                  id: ones
                                  width: 6
                                  height: index % 4 === 0 ? 50 : 25
                                  color: index % 4 === 0 ? "white" : "silver"
                                  property real angle: index * 6
                                  transform: [ Translate { x: parent.width / 2 - width / 2; y: -155 },
                                      Rotation {
                                          origin.x: parent.width / 2
                                          origin.y: parent.height / 2
                                          angle: ones.angle + parent.startAngle
                                      }
                                  ]
                              }
                          }
                          // Numbers around gauge
                          Repeater {
                              model: 10
                              Label {
                                  id: digits
                                  text: index * 20
                                  color: "white"
                                  font { bold: true; pixelSize: 48 }
                                  property real angle: index * 24
                                  transform: [
                                      Translate {
                                          x: parent.width / 2 - width / 2
                                          y: -75 // distance from tickmarks
                                      },
                                      Rotation {
                                          origin.x: parent.width / 2
                                          origin.y: parent.height / 2
                                          angle: digits.angle + parent.startAngle
                                      }
                                  ]
                                  // keeps numbers horizontal
                                  rotation: -digits.angle - parent.startAngle
                              }
                          }
                          // Needle hub
                          Rectangle {
                              anchors.centerIn: speedometer
                              width: 100
                              height: width
                              radius: width/2
                              color: "#a0545454"
                          }
                          // Needle/pointer
                          Repeater {
                              model: 1
                              Rectangle {
                                  id: needle
                                  width: 20
                                  height: 450
                                  color: "orange"
                                  radius: 20
                                  transform: [
                                      Translate {
                                          x: speedometer.width / 2 - width / 2
                                          y: 50 // needle distance from centre
                                      },
                                      Rotation {
                                          origin.x: speedometer.width / 2
                                          origin.y: speedometer.height / 2
                                          angle: speedometer.angle
                                      }
                                  ]
                              }
                          }
                          // Animation for demo purposes
                          SequentialAnimation on value {
                              id: animation
                              loops: Animation.Infinite
                              running: true
                              NumberAnimation { from: 0; to: 180; duration: 2000 }
                              NumberAnimation { from: 180; to: 0; duration: 2000 }
                          }
                      }
                  }
                  
                  

                  NOTE: I use Page, as my apps are built for my mobile phone using SailfishOS. You don't have to use Page, you can likely swap it for Item instead.

                  Screenshot_20231114_001.png

                  D Offline
                  D Offline
                  Darq
                  wrote on last edited by
                  #18

                  @Markkyboy I don't mean the code for the entire speedometer. I want to restrict only this part of the code " rotation: 2.25*XXX+225 " to move in the angle range, e.g. from 225 to 135. I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                  MarkkyboyM 1 Reply Last reply
                  0
                  • D Darq

                    @Markkyboy I don't mean the code for the entire speedometer. I want to restrict only this part of the code " rotation: 2.25*XXX+225 " to move in the angle range, e.g. from 225 to 135. I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                    MarkkyboyM Offline
                    MarkkyboyM Offline
                    Markkyboy
                    wrote on last edited by
                    #19

                    @Darq said in Speedometer:

                    ...... I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                    Sorry, right now I have no idea how to get what you want. I guess, like me, you will have to keep trying and playing until you succeed. I found little to no help with my own endeavours but fumbled my way through the code you see above. If I have an epiphany, I'll post it here but I make no promise.

                    Could you explain why you want such a feature?

                    Don't just sit there standing around, pick up a shovel and sweep up!

                    I live by the sea, not in it.

                    D 1 Reply Last reply
                    0
                    • MarkkyboyM Markkyboy

                      @Darq said in Speedometer:

                      ...... I want there to be no movement in the range from 136 to 224 degrees. I don't know how to specify this in the code.

                      Sorry, right now I have no idea how to get what you want. I guess, like me, you will have to keep trying and playing until you succeed. I found little to no help with my own endeavours but fumbled my way through the code you see above. If I have an epiphany, I'll post it here but I make no promise.

                      Could you explain why you want such a feature?

                      D Offline
                      D Offline
                      Darq
                      wrote on last edited by
                      #20

                      @Markkyboy Commands like "CircularSlider" don't work for me. This shield is called as png. The only problem is with the limitation of the "Rotation" command, so that the rotation is only within a specific range.

                      1 Reply Last reply
                      0
                      • JonBJ JonB referenced this topic on
                      • MarkkyboyM Markkyboy

                        Rather than leave you completely in the dark, Darq, here's some full code to make a working speedometer. Perhaps from this you can make it do what you want/require.

                        import QtQuick
                        import QtQuick.Controls
                        
                        Item {
                            id: control
                        
                            property int trackWidth: 20
                            property int progressWidth: 20
                            property color trackColor: "#505050"
                            property color progressColor: "#3a4ec4"
                            property bool hideTrack: false
                            property bool hideProgress: false
                        
                            property color handleColor: "#fefefe"
                            property int handleWidth: 80
                            property int handleHeight: 80
                            property int handleRadius: 40
                            property int handleVerticalOffset: 0
                        
                            property real startAngle: 0
                            property real endAngle: 360
                            property real minValue: 0.0
                            property real maxValue: 1.0
                        
                            property real value: 0.0
                            readonly property alias angle: internal.angle
                        
                        
                            property real stepSize: 0
                            property bool snap: false
                            property Component handle: null
                            readonly property alias pressed: trackMouse.pressed
                        
                            property bool interactive: true
                            property alias cursorShape: trackMouse.cursorShape
                        
                            implicitWidth: 250
                            implicitHeight: 250
                        
                            Binding {
                                target: control
                                property: "value"
                                value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                when: internal.setUpdatedValue
                            }
                        
                            QtObject {
                                id: internal
                        
                                property point centerPt: Qt.point(control.width / 2, control.height / 2)
                                property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
                                property real actualSpanAngle: control.endAngle - control.startAngle
                                property color transparentColor: "transparent"
                                property color trackColor: control.trackColor
                                property bool setUpdatedValue: false
                                property real angleProxy: control.startAngle
                                property real snappedValue: 0.0
                                readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
                        
                                function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
                                    return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
                                }
                        
                                function updateAngle(angleVal) {
                                    if (angleVal < 0)
                                        angleVal += 360;
                        
                                    if ((angleVal >= control.startAngle) && (angleVal <= control.endAngle)) {
                                        internal.setUpdatedValue = true;
                                        internal.angleProxy = Qt.binding(function() { return angleVal; });
                                        if(control.snap) {
                                            var mappedValue = internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
                                            var range = control.maxValue - control.minValue
                                            var effectiveStep = 2
                                            var actualVal = control.stepSize * Math.round(mappedValue / control.stepSize)
                                            internal.snappedValue = actualVal
                                        }
                                        internal.setUpdatedValue = false;
                                    }
                                }
                            }
                        
                            MouseArea {
                                anchors.fill: parent
                                enabled: control.interactive
                                onClicked: {
                                    var outerRadius = Math.min(control.width, control.height)/ 2
                                    var innerRadius = outerRadius - Math.max(control.trackWidth, 20);
                                    var clickedDistance = (mouseX - internal.centerPt.x) * (mouseX - internal.centerPt.x) + (mouseY - internal.centerPt.y) * (mouseY - internal.centerPt.y);
                                    var innerRadius2 = (innerRadius * innerRadius);
                                    var outerRadius2 = (outerRadius * outerRadius);
                                    var isOutOfInnerRadius = clickedDistance > innerRadius2;
                                    var inInSideOuterRadius = clickedDistance <= outerRadius2;
                                    if (inInSideOuterRadius && isOutOfInnerRadius) {
                                        var angleDeg = Math.atan2(mouseY - internal.centerPt.y, mouseX - internal.centerPt.x) * 180 / Math.PI + 90;
                                        internal.updateAngle(angleDeg);
                                    }
                                }
                            }
                        
                            // Handle Item
                            Item {
                                id: handleItem
                                visible: control.interactive
                        
                                x: control.width / 2 - width / 2
                                y: control.height / 2 - height / 2
                                // make sure that the slider handle is always on top as we can set custom track or progress items
                                z: 2
                                width: control.handleWidth
                                height: control.handleHeight
                                antialiasing: true
                                transform: [
                                    Translate {
                                        y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.handleVerticalOffset
                                    },
                                    Rotation {
                                        angle: control.angle
                                        origin.x: handleItem.width / 2
                                        origin.y: handleItem.height / 2
                                    }
                                ]
                        
                                MouseArea {
                                    id: trackMouse
                                    enabled: control.interactive
                        
                                    function getVal() {
                                        var handlePoint = mapToItem(control, trackMouse.mouseX, trackMouse.mouseY);
                                        // angle in degrees
                                        var angleDeg = Math.atan2(handlePoint.y - internal.centerPt.y, handlePoint.x - internal.centerPt.x) * 180 / Math.PI + 90;
                                        internal.updateAngle(angleDeg);
                                    }
                        
                                    anchors.fill: parent
                                    onPositionChanged: getVal()
                                    onClicked: getVal()
                                    cursorShape: Qt.ArrowCursor
                                }
                        
                                Loader {
                                    id: handleLoader
                        
                                    sourceComponent: control.handle ? handle : handleComponent
                                }
                            }
                        
                            /// Default handle component
                            Component {
                                id: handleComponent
                        
                                Rectangle {
                                    width: control.handleWidth
                                    height: control.handleHeight
                                    color: control.handleColor
                                    radius: control.handleRadius
                                    antialiasing: true
                                }
                            }
                        }
                        
                        
                        import QtQuick
                        import QtQuick.Controls
                        import "../components"
                        
                        Page {
                            id: darqSpeedo
                        
                            allowedOrientations: Orientation.All // this is specific to SailfishOS and can likely be omitted.
                        
                            // imported from "../components"
                            CircularSlider {
                                id: speedometer
                                interactive: false
                                anchors.centerIn: parent
                                width: 1000
                                height: width
                                value: 0
                                startAngle: -108
                                endAngle: 108
                                minValue: 0
                                maxValue: 180
                                anchors {
                                    verticalCenterOffset: 200
                                    verticalCenter: parent.verticalCenter
                                    horizontalCenter: parent.horizontalCenter
                                }
                                // Tickmarks around gauge
                                Repeater {
                                    model: 37
                                    Rectangle {
                                        id: ones
                                        width: 6
                                        height: index % 4 === 0 ? 50 : 25
                                        color: index % 4 === 0 ? "white" : "silver"
                                        property real angle: index * 6
                                        transform: [ Translate { x: parent.width / 2 - width / 2; y: -155 },
                                            Rotation {
                                                origin.x: parent.width / 2
                                                origin.y: parent.height / 2
                                                angle: ones.angle + parent.startAngle
                                            }
                                        ]
                                    }
                                }
                                // Numbers around gauge
                                Repeater {
                                    model: 10
                                    Label {
                                        id: digits
                                        text: index * 20
                                        color: "white"
                                        font { bold: true; pixelSize: 48 }
                                        property real angle: index * 24
                                        transform: [
                                            Translate {
                                                x: parent.width / 2 - width / 2
                                                y: -75 // distance from tickmarks
                                            },
                                            Rotation {
                                                origin.x: parent.width / 2
                                                origin.y: parent.height / 2
                                                angle: digits.angle + parent.startAngle
                                            }
                                        ]
                                        // keeps numbers horizontal
                                        rotation: -digits.angle - parent.startAngle
                                    }
                                }
                                // Needle hub
                                Rectangle {
                                    anchors.centerIn: speedometer
                                    width: 100
                                    height: width
                                    radius: width/2
                                    color: "#a0545454"
                                }
                                // Needle/pointer
                                Repeater {
                                    model: 1
                                    Rectangle {
                                        id: needle
                                        width: 20
                                        height: 450
                                        color: "orange"
                                        radius: 20
                                        transform: [
                                            Translate {
                                                x: speedometer.width / 2 - width / 2
                                                y: 50 // needle distance from centre
                                            },
                                            Rotation {
                                                origin.x: speedometer.width / 2
                                                origin.y: speedometer.height / 2
                                                angle: speedometer.angle
                                            }
                                        ]
                                    }
                                }
                                // Animation for demo purposes
                                SequentialAnimation on value {
                                    id: animation
                                    loops: Animation.Infinite
                                    running: true
                                    NumberAnimation { from: 0; to: 180; duration: 2000 }
                                    NumberAnimation { from: 180; to: 0; duration: 2000 }
                                }
                            }
                        }
                        
                        

                        NOTE: I use Page, as my apps are built for my mobile phone using SailfishOS. You don't have to use Page, you can likely swap it for Item instead.

                        Screenshot_20231114_001.png

                        S Offline
                        S Offline
                        Sattiy
                        wrote on last edited by
                        #21

                        @Markkyboy Can You Please specify which file is which file so i can integrate it accordingly like which is main.qml file here

                        MarkkyboyM 1 Reply Last reply
                        0
                        • S Sattiy

                          @Markkyboy Can You Please specify which file is which file so i can integrate it accordingly like which is main.qml file here

                          MarkkyboyM Offline
                          MarkkyboyM Offline
                          Markkyboy
                          wrote on last edited by
                          #22

                          The first file is CircularSlider.qml, this forms the basis for the speedometer gauge in a circular fashion.

                          The second file is basically the 'Main.qml', in my case, it is called FirstPage.qml.

                          Don't just sit there standing around, pick up a shovel and sweep up!

                          I live by the sea, not in it.

                          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