How to stop window size jumping around when forcing fixed aspect ratio?

随声附和 提交于 2019-12-07 15:59:34

I've had a problem like that once, I ended up a "chicken or egg" paradox, so I disabled the window decorations altogether and made custom resizing bars. This established a proper value flow from handles to dimensions, without it the flow was dimensions to dimensions, if that makes any sense...

If removing the window frame is not a problem for you, you could go that way, for me it wasn't since I was looking for a custom and platform independent look, so the window frame was actually part of the application:

Window {
    id: main
    visible: true
    width: 500
    height: 250
    flags: Qt.FramelessWindowHint | Qt.Window

    MouseArea {
      width: 20
      height: 20
      anchors.bottom: parent.bottom
      anchors.right: parent.right
      onPositionChanged: {
        var w = mouseX + x, h = mouseY + y
        if (w > (h * 2)) {
          main.width = w
          main.height = w * .5
        } else {
          main.height = h
          main.width = h * 2
        }
      }
      Rectangle {
        anchors.fill: parent
        color: "red"
      }
    }
}

That's just a trivial example, obviously in a complete solution you should do all sides and corners. Aspect ratio is fixed at 2/1.

On my system there is still some flickering for the entire window, but I think that's just the scenegraph, but the "dimensions jumping around" problem is effectively solved.

EDIT:

To clarify, what I mean by the "flow was dimensions to dimensions" is that the handles manipulate the dimensions, and you hook to the changed handlers to... make a change. I suspect that's why it works so flaky. If so, in order to employ the window frame for resizing, the connection between the handles and the window dimensions has to be severed to insert the aspect ratio code between. Unfortunately, filtering out the resize event at QGuiApplication level did not prevent the resizing, but maybe there is another way to do that, for example overriding the class.

Ok, here's one possible workaround. It doesn't try to control the window size, but instead adds extra item inside the window, which then contains the rest of the UI, and keeps the desired aspect ratio: If window aspect ratio is different, then there's empty area either above and below, or left and right, of the content area, drawn with window color ("gray" here). The content area is filled with "yellow" here to show the difference.

import QtQuick 2.4
import QtQuick.Window 2.2

Window {

    readonly property int defaultWidth: 700
    readonly property int defaultHeight: 500
    readonly property real defaultAspectRatio: defaultWidth / defaultHeight

    readonly property real aspectRatio: width / height
    readonly property real scaleFactor: content.width / defaultWidth

    visible: true
    width: defaultWidth
    height: defaultHeight
    color: "gray"

    Item {
        id: content
        anchors.centerIn: parent
        width: (aspectRatio > defaultAspectRatio)
               ? parent.height * defaultAspectRatio
               : parent.width
        height: (aspectRatio < defaultAspectRatio)
                ? parent.width / defaultAspectRatio
                : parent.height

        Rectangle { color: "yellow"; anchors.fill: parent } // just to show the effect

        TextEdit {
            clip: true // text drawing needs to be clipped explicitly
            id: textEdit
            text: "Lorem ipsum"
            font.pixelSize: 40 * scaleFactor
            anchors.fill: parent
        }
    }
}

But this is just a workaround, not a full solution asked for in the question, so the question remains open.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!