c++qtqmlc++17qt6

How can I resize frameless window in QML?


How can I return resize logic of borders in Frameless Window?

The frame windows has this logic: enter image description here

Code in QML:

import QtQuick
import QtQuick.Controls 2.5
import Qt5Compat.GraphicalEffects
import NR 1.0

Window {
    id: mainWindow
    width: 640
    height: 720
    visible: true
    title: qsTr("Hello World")
    flags: Qt.Window | Qt.FramelessWindowHint
    color: "transparent"

    // (1)

    MouseArea {
        id: bottomArea
        height: 5
        anchors {
            bottom: parent.bottom
            left: parent.left
            right: parent.right
        }
        cursorShape: Qt.SizeVerCursor

        onPressed: {
            previousY = mouseY
        }

        onMouseYChanged: {
            var dy = mouseY - previousY
            mainWindow.setHeight(mainWindow.height + dy)
        }
    }
    // Some code of another Items here
}

I tried this code for left side:

 MouseArea {
        id: leftSideMouseArea
        anchors.fill: parent
        property point lastMousePos: Qt.point(0, 0)
        onPressed: { lastMousePos = Qt.point(mouseX, mouseY); }
        onMouseXChanged: mainWindow.width += (mouseX + lastMousePos.x)
    }

I put this code in (1) place, but it doesn't work - on click (without move) windows resize to the rigth and app crashes with error:

QQuickPaintedItem::textureProvider: can only be queried on the rendering thread of an exposed window

This looks like on picture: enter image description here

Can you help me?

Thanks!


Solution

  • Since Qt5.15, we have startSystemResize, which performs a native resizing and is recommended against using methods like comparing the click position to the current position.

    The function is very simple; once you pass an edge, the window begins to resize.

    An example of a frameless window is shown below:

    CustomWindow.QML

    Change the offset from the window's edges where the mouse can be pressed by using this property.
    property int edgeOffest: 5

    Also for moving the window as well You can use a DragHandler, which, when activated, calls startSystemMove.

    Window {
        width: 200; height: 100
        color: '#fab'
        flags: Qt.Window | Qt.FramelessWindowHint
    
        DragHandler {
            onActiveChanged: if(active) startSystemMove();
        }
    
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            hoverEnabled: true
            acceptedButtons: Qt.LeftButton
    
            property int edges: 0;
            property int edgeOffest: 5;
    
            function setEdges(x, y) {
                edges = 0;
                if(x < edgeOffest) edges |= Qt.LeftEdge;
                if(x > (width - edgeOffest))  edges |= Qt.RightEdge;
                if(y < edgeOffest) edges |= Qt.TopEdge;
                if(y > (height - edgeOffest)) edges |= Qt.BottomEdge;
            }
    
            cursorShape: {
                return !containsMouse ? Qt.ArrowCursor:
                       edges == 3 || edges == 12 ? Qt.SizeFDiagCursor :
                       edges == 5 || edges == 10 ? Qt.SizeBDiagCursor :
                       edges & 9 ? Qt.SizeVerCursor :
                       edges & 6 ? Qt.SizeHorCursor : Qt.ArrowCursor;
            }
    
            onPositionChanged: setEdges(mouseX, mouseY);
            onPressed: {
                setEdges(mouseX, mouseY);
                if(edges && containsMouse) {
                    startSystemResize(edges);
                }
            }
        }
    }
    

    Preview

    Window resize preview

    Final Notes

    Still, I do not recommend developing a custom window with custom functionality, which forces you to handle a lot of functions while still not feeling like a native one.

    However, there are a few github projects that offered some helper libraries for this, so take a look at those.