Search code examples
androidqmlqt5qtquickcontrols

Change font size of a Button in Android while remaining native


I'd like to change the font size of a Button. I used the solution from here

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2

Rectangle {
  id: container
  width: 800
  height: 800

  Button {
    id: cmdQuit
    text: qsTr("Quit")
    width: 100
    height: 100
    style: ButtonStyle {
      label: Text {
        renderType: Text.NativeRendering
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
        font.pointSize: 20
        text: cmdQuit.text
      }
    }
  }
}

Unfortunately, when I do this, I lose the Android native look and get a fallback base look. Is there any way to change the font size without losing the native style on Android?

I want to change the look of a single button and want the other buttons to remain the same. I'm using Qt5 (C++) with QML. I don't want a solution which involves copying the whole QtQuick/Controls/Styles/Android folder - I can do it on my own but it's awful


Solution

  • WARNING : this solution relies on modifying an internal object and is not guaranteed to work across different Qt versions or platforms

    If you absolutely want to modify only a property of an object that is not exposed, you can still access it with the children property of an Item (or resources/data).

    One handy function to call on Component.omCompleted is one that dumps the hierarchy of an Item, here is an example implementation :

    function dumpHierarchy(item, level) {
        level = level | 0;
        for (var index = 0; index < item.children.length; ++index) {
            var child = item.children[index];
            print(Array(level*2 + 1).join(" ")+ index +": "+child);
            dumpHierarchy(child, level+1);
        }
    }
    

    and what it outputs on Android and Qt 5.5 for a Button:

    0: QQuickLoader(0xab87c768)
      0: QQuickLoader_QML_44(0xab7a84f0)
      1: QQuickItem_QML_53(0xab8c8d60)
        0: DrawableLoader_QMLTYPE_51(0xab8bb088)
          0: StateDrawable_QMLTYPE_65(0xab949420)
            0: DrawableLoader_QMLTYPE_51(0xab936ea0)
              0: NinePatchDrawable_QMLTYPE_67(0xab955c90)
                0: QQuickAndroid9Patch_QML_68(0xab913608)
            1: QQuickLoader_QML_66(0xab924838)
        1: QQuickRowLayout(0xab8b03a0)
          0: QQuickImage(0xab8b0960)
          1: LabelStyle_QMLTYPE_50(0xab8c1758)
    1: QQuickMouseArea_QML_46(0xab887028)
    

    Here we can see the hierarchy position of the LabelStyle which is of interest to us. If you want to do it quick and dirty you could just add this in your Button element :

    Component.onCompleted: children[0].children[1].children[1].children[1].font.pixelSize = 50
    

    but this isn't really maintainable, a more acceptable solution is to traverse the children hierarchy of our Button and find the font to modify.

    I've put a function findFont in a working example Application :

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
        id: app
        visible: true
        width: 640
        height: 480
    
        function findFont(object) {
            if (object.font)
                return object.font;
            var font = null;
            for (var index = 0; index < object.children.length && !font; ++index)
                font = findFont(object.children[index]);
            return font;
        }
    
        Column {
            anchors.centerIn: parent
    
            Button {
                anchors.horizontalCenter: parent.horizontalCenter
                text: "Button 1"
                width: 300
                height: 100
            }
            Button {
                anchors.horizontalCenter: parent.horizontalCenter
                text: "Button 2"
                width: 300
                height: 100
    
                Component.onCompleted: {
                    findFont(this).pixelSize = 50;
                    // On Android and Qt 5.5, this is equivalent :
                    //children[0].children[1].children[1].children[1].font.pixelSize = 50;
                }
            }
        }
    }