Qt cross platform UI scaling ( Android / Windows / Linux )

Sé que Qt tiene otros métodos para disfrutar de una escala apropiada en cualquier plataforma, pero es bastante común el trabajar sobre un proyecto en el cual no puedes hacer uso de esos métodos y necesitas al final usar un factor común de escala para todos los elementos.

Tras mucho investigar y hacer pruebas empíricas he conseguido tener un factor de escala que realmente funcione en todas las plataformas ( he probado en Android, Windows y linux ) resultando en un mismo aspecto en cualquier dispositivo sin importar de su resolución o densidad. 

 Aquí os cuento como hacerlo.

  1.- El primer paso es obtener los dpi en los que el dispositivo está funcionando realmente 
- Android -
// Android tiene density baseline de 160dpi ( mdpi ) 

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;"); 
qreal realDpi = displayMetrics.getField("densityDpi"); 

- Windows -
// Windows tiene density baseline de 96dpi y sobre el aplica el zoom; ( ¿Por qué 96dpi?

QScreen *screen = app.screens().at(0); 
qreal realDpi = screen->logicalDotsPerInch() * app.devicePixelRatio(); 

- Linux -
// En las versiones actuales de linux sobre Xorg, el density baseline es también 96dpi como Windows; por lo que no podemos hacer uso de logicalDotsPerInch ( es siempre 96 ), asi que debemos sacar los dpi reales aplicando el ratio sobre la diferencia de la realidad usando como base los 96dpi 

QScreen *screen = app.screens().at(0); 
qreal ratio = 96/screen->physicalDotsPerInch(); 
qreal realDpi = 96*ratio; 

2.- Una vez tenemos los DPI reales del dispositivo, calculamos el factor de escala.
// Yo lo estoy haciendo en Qml, pero podría calcularse en C++ sin problema y pasar directamente el factor de escala; lo tengo hecho así por particularidades de implementación 

if (Qt.platform.os === 'android') 

    scaleFactor = realDpi / 160; 
}else{ 
    scaleFactor = realDpi / 96; 


3.- Usar el factor de escala con todas las dimensiones de nuestros componentes Qml.
Item { 
    id: sampleitem width: 300 * app.scaleFactor; height: 300 * app.scaleFactor 
        ... 
}

Happy coding.

Comentarios

Entradas populares de este blog

El juego del impávido.

HowTo Cambiar campo "Archivar como" para que se asemejer a "Nombre completo"

VS2008 C# Centrar un formulario en pantalla.