0

A picture speaks better than words (black rectangle in red ApplicationWindow):

enter image description here

Notice the red unfilled areas on top and right side. The right side red color may be hard to notice but it is there! I want the rectangle which I have colored in black to fill the entire Application Window. See the code:

main.qml

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3

ApplicationWindow {    
    id: window
    visible: true

    /* Developing mobile apps you don’t need to set width
       and height, because the ApplicationWindow always grabs
       the total available space.
    */
    //width: 640
    //height: 480

    color: "#ff0000" // Red color

    /* For some reasons i want this Rectangle here
     * and it MUST fill the entire window but I notice
     * a pixel or two line on top and right of the
     * screen.
     */
    Rectangle {
        id: page
        width: window.width; height: window.height
        //anchors.fill: parent // same output
        color: "#000000" // Black color
    }
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

I don't know what I'm missing here :(

Please share a solution/workaround to this problem.

I also tried this but still the same output:

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2

Window {  
    id: window
    visible: true

    height: Screen.height
    width: Screen.width

    /* Developing mobile apps you don’t need to set width
       and height, because the ApplicationWindow always grabs
       the total available space.
    */
    //width: 640
    //height: 480

    color: "#ff0000" // Red color

    /* For some reasons i want this Rectangle here
     * and it MUST fill the entire window but I notice
     * a pixel or two line on top and right of the
     * screen.
     */
    Rectangle {
        id: page
        width: window.width; height: window.height
        //anchors.fill: parent // same output
        color: "#000000" // Black color
    }
}

I noticed that commenting following line in main.cpp resolves the issue BUT now all the widgets which I want to show in the UI look really small..! They look fine in the small-screen devices while small in large-screen devices. :(

QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

Any solution for this?

EDIT: This is a confirmed bug which has been reported HERE since almost an year! . If you are facing the same issue then please login to https://bugreports.qt.io/ and Vote THIS bug.

Community
  • 1
  • 1
Shuji
  • 624
  • 1
  • 8
  • 24
  • Maybe because ApplicationWindow does not grab all content? Can you try to set width and height explicitly with `height: Screen.height` and `width: Screen.width` with `import QtQuick.Window 2.2`. – sk2212 Oct 16 '17 at 15:35
  • @sk2212 I tried that but it did not work. I have edited my question to include your recommendation. – Shuji Oct 16 '17 at 16:19
  • @sk2212 Here we go! I noticed that if I comment QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); Then the rectangle fills the entire window as expected but now the UI widgets look small. – Shuji Oct 16 '17 at 16:40

1 Answers1

3

Well, you could use your "own" dp calculation.

main.cpp

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");
   qDebug() << "Native Android Call =>>> | Logical Density: " << logicalDensity << " | DensityDPI: " << density << " | " << "++++++++++++++++++++++++";
#endif
[...]
// Set Android pixel data for QML context
engine.rootContext()->setContextProperty("densityData", density);
engine.rootContext()->setContextProperty("logicalDensityData",logicalDensity);
engine.rootContext()->setContextProperty("xDpiData",xDpi);
engine.rootContext()->setContextProperty("yDpiData",yDpi);

For your ApplicationWindow component add this:

main.qml

Component.onCompleted: {
        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;
            }
        });

        Device.type = Qt.binding(function () {
            var diagonal = calculateDiagonal();
            Device.diagonal = diagonal;
            if (diagonal >= 3.5 && diagonal < 5) { //iPhone 1st generation to phablet
                return Device.phone;
            } else if (diagonal >= 5 && diagonal < 7.2) {
                return Device.phone;
            } else if (diagonal >= 7.2 && diagonal < 15.1) {
                return Device.tablet;
            } else if (diagonal >= 15.1 && diagonal < 29) {
                return Device.desktop;
            } else if (diagonal >= 29 && diagonal < 92) {
                return Device.tv;
            } else {
                return Device.unknown;
            }
        });

        // Nasty hack because singletons cannot import the module they were declared in, so
        // the grid unit cannot be defined in either Device or Units, because it requires both.
        // See https://bugreports.qt.io/browse/QTBUG-39703
        Units.gridUnit = Qt.binding(function() {
            return Device.type === Device.phone || Device.type === Device.phablet
                    ? Units.dp(48) : Device.type == Device.tablet ? Units.dp(56) : Units.dp(64)
        });
}

Units.qml

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)
}

Device.qml

import QtQuick 2.0

pragma Singleton

/*!
   \qmltype Device
   \inqmlmodule Material 0.1

   \brief A singleton that provides information about the current device.
 */
Object {
    id: device

    //some kind of enum, by screen size
    property int type: desktop
    property int diagonal: -1

    readonly property int phone: 0
    readonly property int phablet: 1
    readonly property int tablet: 2
    readonly property int desktop: 3
    readonly property int tv: 4
    readonly property int unknown: 5 //it's either bigger than tv or smaller than phone

    readonly property string name: {
        switch (type) {
            case 0:
                return "phone";
            case 1:
                return "phablet";
            case 2:
                return "tablet";
            case 3:
                return "computer";
            case 4:
                return "TV";
            case 5:
                return "device";
        }
    }

    readonly property string iconName: {
        switch (type) {
            case 0:
                return "hardware/smartphone";
            case 1:
                return "hardware/tablet";
            case 2:
                return "hardware/tablet";
            case 3:
                return "hardware/desktop_windows";
            case 4:
                return "hardware/tv";
            case 5:
                return "hardware/computer";
        }
    }

    readonly property bool isMobile: type == phone || type == phablet || type == tablet
}

Units and Device components are taken from here qml-material project "https://github.com/papyros/qml-material"

After adding this you should be able to wrap every pixel statement into width: Units.dp(30)

sk2212
  • 1,688
  • 4
  • 23
  • 43
  • This is a serious bug! It is affecting all platforms with specific screen resolutions. You never know what the end user will be using the screen resolution so it may be affecting your QtQuick applications too! This bug has been reported [HERE](https://bugreports.qt.io/browse/QTBUG-53247) since almost an year! . If you are facing the same issue then please login to https://bugreports.qt.io/ and vote [THIS](https://bugreports.qt.io/browse/QTBUG-53247) bug. Note: It is not just Rectangle that's drawn incorrectly, in fact, all UI elements are affected due to this bug! – Shuji Oct 17 '17 at 14:47
  • @ShujaatAliKhan please do not "flame" this way. Just try provided workaround. – sk2212 Oct 17 '17 at 15:08