Jiri Zaloudek
Jiri Zaloudek

Reputation: 380

QML font.pointSize varies across platforms

I know there is a huge amount of posts everywhere, however nothing realy works or at least not to me...

basicaly I dont use exact numbers for font.pointSize, i use it like: font.pointSize: Math.min(mainappwindow.width, mainappwindow.height)/10 its to be sure that if resolution changes, the text will always be 10% of all screen (smaller from width or height obviously)...

However, if I compile on windows, the height of the text has 72points (counted, as well as debugged). But when I compile on Android (720x1280 HD), the same code debugs again 72points, but its way bigger! coutned points and its 113... after a week of googling and trying whatever i could try (nothing worked), i just conunted the diference ration of 0.638 what I am multiplying if platform is android.... This works fine... however when I changed resolution on the phone from HD to fullHD(1080x1920) its again bigger by ratio 1.632...

Therefore this ratio recalculation wont work on different devices which has different resolution...

I have read all the google sources, QML scaling etc, but I would realy appriciate any pice of code directed to my example...

Thank you, this makes me desperate

Upvotes: 1

Views: 1856

Answers (2)

BrutalWizard
BrutalWizard

Reputation: 532

How @sk2212, said, you could use Qt::AA_EnableHighDpiScaling

In main.cpp file write this code

QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

I'd recomended to check Text propertys: renderType, minimumPixelSize, minimumPointSize and fontSizeMode. Check renderType and fontSizeMode. Maybe it's your sollution

In Text item try this code. And try it without your custom code

renderType: Text.QtRendering
fontSizeMode: Text.FixedSize

Also, it would be great, if you provide some code.
P.S: I'd recommended to create two versions, one for desktop, and one for phone, there will be less code and easier to maintain your app.

Upvotes: 2

sk2212
sk2212

Reputation: 1722

You can use Qt::AA_EnableHighDpiScaling see High DPI Documentation

However sometimes there are some issues with this option so you can implement your own pixel size wrapper:

import QtQuick 2.0

pragma Singleton

Object {
    id: units

    /*!
       \internal
       This holds the pixel density used for converting millimeters into pixels. This is the exact
       value from \l Screen:pixelDensity, but that property only works from within a \l Window type,
       so this is hardcoded here and we update it from within \l ApplicationWindow
     */
    property real pixelDensity: 4.46
    property real multiplier: 1.4 //default multiplier, but can be changed by user

    /*!
       This is the standard function to use for accessing device-independent pixels. You should use
       this anywhere you need to refer to distances on the screen.
     */
    function dp(number) {
        return Math.round(number*((pixelDensity*25.4)/160)*multiplier);
    }

    function gu(number) {
        return number * gridUnit
    }

    property int gridUnit: dp(64)
}

In your main.cpp use native Android code for density calculation:

int density = 0;
float logicalDensity = 0;
float yDpi = 0; float xDpi = 0;

#if defined(ANDROID)
   QAndroidJniObject qtActivity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
   QAndroidJniObject resources = qtActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
   QAndroidJniObject displayMetrics = resources.callObjectMethod("getDisplayMetrics", "()Landroid/util/DisplayMetrics;");
   density = displayMetrics.getField<int>("densityDpi");
   logicalDensity = displayMetrics.getField<float>("density");
   yDpi = displayMetrics.getField<float>("ydpi");
   xDpi = displayMetrics.getField<float>("xdpi");
   QAndroidJniEnvironment env;
   if (env->ExceptionCheck()) {
       // Handle exception here.
       env->ExceptionClear();
   }
#endif

// Add it as a context property (see main.qml)
engine.rootContext()->setContextProperty("densityData", density);

In your main.qml add in Component.onCompleted something like this:

    Units.pixelDensity = Qt.binding(function() {
        if (Qt.platform.os === "android") {
            return densityData / 25.4; // densityData is per inch but we need per mm
        }
        return Screen.pixelDensity
    });

    function calculateDiagonal() {
        if (Qt.platform.os === "android") {
            return Math.sqrt(Math.pow(Screen.width, 2) +
                             Math.pow(Screen.height, 2)) / densityData;
        }
        return Math.sqrt(Math.pow(Screen.width, 2) +
                         Math.pow(Screen.height, 2)) / (Screen.pixelDensity * 25.4);
    }

    Units.multiplier = Qt.binding(function() {
        var diagonal = calculateDiagonal();
        Device.diagonal = diagonal;
        var baseMultiplier = 1;
        if (diagonal >= 3.5 && diagonal < 5.1) { //iPhone 1st generation to phablet
            return 0.8;
        } else if (diagonal >= 5.1 && diagonal < 6.5) {
            return 1;
        } else if (diagonal >= 6.5 && diagonal < 15.1) {
            return baseMultiplier;
        } else if (diagonal >= 15.1 && diagonal < 29) {
            return 1.4 * baseMultiplier;
        } else if (diagonal >= 29 && diagonal < 92) {
            return 1.4 * baseMultiplier;
        } else {
            return 1.4 * baseMultiplier;
        }
    });

Use for every pixel value:

Rectangle {
 height: Units.dp(50)
 width: Units.dp(30)
}

Upvotes: 1

Related Questions