Search code examples
qttextlabelqml

Qml Text Size based on Container


I am using Qt Quick to develop an app (Qt 5.8). I have text that appears in multiple places so I created a component to use to display the text. The areas the text can vary in placement and size. How can I adjust my text so that the data displays in 1 line horizontally and all text is the same size if I simply want to display the following?

FLAPS 1
GEAR DOWN
TRIM -1.0

I used Text and was able to get close, however since GEAR DOWN has more characters the text was smaller, than flaps and trim. So I moved on to using Label. Can someone provide better insight on how to have text size based on its container's width or height?

main.qml

import QtQuick 2.6
import QtQuick.Window 2.2

Window {
    id: windowRoot
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle{
        height: windowRoot.height * .80
        width: windowRoot.width * .80
        color: "green"
        anchors.centerIn: parent
        Rectangle {
            id: rect1
            opacity: .5
            anchors.top: parent.top
            anchors.left: parent.left
            color: "lime"
            border.color: "orange"
            height: parent.height * 1/2
            width: parent.width * 1/2
            TextHolder {
                anchors.top: parent.top
                anchors.left: parent.left
                width: parent.width * 1/4
                height: parent.height
            }
        }
        Rectangle {
            id: rect2
            anchors.top: parent.top
            anchors.left: rect1.right
            color: "yellow"
            border.color: "blue"
            height: parent.height * 1/2
            width: parent.width * 1/2
        }
        Rectangle {
            id: rect3
            anchors.top: rect1.bottom
            anchors.left: parent.left
            color: "pink"
            border.color: "red"
            height: parent.height * 1/2
            width: parent.width * 1/2
            TextHolder {
                anchors.top: parent.top
                anchors.left: parent.left
                width: parent.width * 1/4
                height: parent.height * 1/2
            }
        }
        Rectangle {
            id: rect4
            anchors.top: rect2.bottom
            anchors.left: rect3.right
            color: "orange"
            border.color: "lime"
            height: parent.height * 1/2
            width: parent.width * 1/2
            TextHolder {
                anchors.bottom: parent.bottom
                height: parent.height * 1/4
                width: parent.width * 1/4
                anchors.horizontalCenter: parent.horizontalCenter
            }
        }
    }
}

TextHolder.qml

import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.1

Rectangle {
    color: "purple"
    border.color: "steelblue"
    border.width: 3
    property color colorOfText: "white"
    property real textSize: 48
    Item {
        id: inputs
        property int flapHndl: 1
        property int gearHndl: 1
        property real trim: -1.0
    }

    clip: true

    ColumnLayout {
        anchors.top: parent.top
        width: parent.width
        height: parent.height
        spacing: 5

        Label {
            id: flapLabel
            text: "FLAPS " + inputs.flapHndl
            color: colorOfText
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            font.pixelSize: textSize
            fontSizeMode: Text.HorizontalFit
            Layout.fillWidth: true
        }

        Label {
            id: gearLabel
            text: {
                if (inputs.gearHndl === 1)
                    return "GEAR DOWN"
                else
                    return "GEAR UP"
            }
            color: colorOfText
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            font.pixelSize: textSize
            fontSizeMode: Text.HorizontalFit
            Layout.fillWidth: true
        }

        Label {
            id: trimLabel
            text: "TRIM " + inputs.trim.toFixed(1)
            color: colorOfText
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            font.pixelSize: textSize
            fontSizeMode: Text.HorizontalFit
            Layout.fillWidth: true
        }
    }
}

Solution

  • Can someone provide better insight on how to have text size based on its container's width or height?

    For evaluating the text width and height we can definitely use QML type TextMetrics and having the metrics we can then attempt to fit the text in. If the text still won't fit we can then try to adjust the font size. For that, some logic might need to be implemented with JavaScript. So, the below code is an example of the "feedback" type of solution.

    Rectangle {
       property string textToShow
       property int widthLimit: 400
    
       onTextToShowChanged: {
          while (txtMeter.width > widthLimit) {
             txtMeter.font.pixelSize --;
          }
       }
    
       TextMetrics {
          id: txtMeter
          font.family: "Courier"
          font.pixelSize: 25
          text: textToShow
       }
    
       Text {
          font: txtMeter.font
          text: textToShow
       }
    }
    

    P.S. This is just a sketchy idea and your actual implementation may differ