如何在 QML 中调整无框窗口的大小?

问题描述 投票:0回答:4

如何返回无框窗口中边框的调整大小逻辑?

框架窗口有这样的逻辑: enter image description here

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
}

我在左侧尝试了此代码:

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

我将此代码放在 (1) 位置,但它不起作用 - 单击(不移动)窗口会调整到右侧大小,并且应用程序崩溃并出现错误:

QQuickPaintedItem::textureProvider:只能在 暴露窗口的渲染线程

这看起来像图片上的那样: enter image description here

你能帮我吗?

谢谢!

c++ qt qml c++17 qt6
4个回答
5
投票

Qt5.15
开始,我们有了startSystemResize,它执行本机调整大小,建议不要使用将单击位置与当前位置进行比较之类的方法。

功能非常简单;一旦经过边缘,窗口就会开始调整大小。

无框窗户的示例如下所示:

自定义窗口.QML

使用此属性更改可按下鼠标的窗口边缘的偏移量。

property
int
edgeOffest
5

也可用于移动窗口,您可以使用

DragHandler
,它在激活时会调用 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);
            }
        }
    }
}

预览

Window resize preview

最后的笔记

不过,我不建议开发具有自定义功能的自定义窗口,这会迫使您处理大量功能,同时仍然感觉不像原生功能。

但是,有一些 github 项目为此提供了一些辅助库,所以请看一下这些项目。


0
投票

我想不出更好的方法来做到这一点

这是一个工作示例:

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    id: window
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    flags: Qt.Window | Qt.FramelessWindowHint

    Rectangle
    {
        id: dragItemRight
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        width: 5
        color: "red"
        x: window.width - width

        onXChanged:
        {
            if (dragItemRightMouse.drag.active)
            {
                window.width = dragItemRight.x + width
            }
        }

        MouseArea
        {
            id: dragItemRightMouse
            anchors.fill: parent
            drag.target: parent
            drag.axis: Drag.XAxis
            cursorShape: Qt.SizeHorCursor
            drag.minimumX: 300

            drag.onActiveChanged:
            {
                if (!drag.active)
                {
                    dragItemRight.x = Qt.binding(function() { return window.width - width })
                }
            }
        }
    }

    Rectangle
    {
        id: dragItemBottom
        anchors.left: parent.left
        anchors.right: parent.right
        height: 5
        color: "red"
        y: window.height - height

        onYChanged:
        {
            if (dragItemBottomMouse.drag.active)
            {
                window.height = dragItemBottom.y + height
            }
        }

        MouseArea
        {
            id: dragItemBottomMouse
            anchors.fill: parent
            drag.target: parent
            drag.axis: Drag.YAxis
            cursorShape: Qt.SizeVerCursor
            drag.minimumY: 300

            drag.onActiveChanged:
            {
                if (!drag.active)
                {
                    dragItemBottom.y = Qt.binding(function() { return window.height - height })
                }
            }
        }
    }

    Rectangle
    {
        id: dragItemBottomRight
        width: 5
        height: 5
        color: "green"
        x: window.width - width
        y: window.height - height

        onYChanged:
        {
            if (dragItemBottomRightMouse.drag.active)
            {
                window.height = dragItemBottomRight.y + height
            }
        }
        onXChanged:
        {
            if (dragItemBottomRightMouse.drag.active)
            {
                window.width = dragItemBottomRight.x + width
            }
        }

        MouseArea
        {
            id: dragItemBottomRightMouse
            anchors.fill: parent
            drag.target: parent
            drag.axis: Drag.XAndYAxis
            drag.minimumX: 300
            drag.minimumY: 300
            cursorShape: Qt.SizeFDiagCursor

            drag.onActiveChanged:
            {
                if (!drag.active)
                {
                    dragItemBottomRight.x = Qt.binding(function() { return window.width - width })
                    dragItemBottomRight.y = Qt.binding(function() { return window.height - height })
                }
            }
        }
    }
}

0
投票

我找到了解决方案:

import QtQuick
import QtQuick.Controls 2.15
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"

    property point startMousePos
    property point startWindowPos
    property size startWindowSize

    function absoluteMousePos(mouseArea) {
        var windowAbs = mouseArea.mapToItem(null, mouseArea.mouseX, mouseArea.mouseY)
        return Qt.point(windowAbs.x + mainWindow.x,
                        windowAbs.y + mainWindow.y)
    }

    

    MouseArea {
        id: moveArea
        anchors.fill: title
        property point mPos;
        onPressed: {
            mPos = Qt.point(mouseX, mouseY)
        }
        onPositionChanged: {
            mainWindow.setX(mainWindow.x + mouseX - mPos.x)
            mainWindow.setY(mainWindow.y + mouseY - mPos.y)
        }
    }

    MouseArea {
        id: leftArea
        anchors.top: parent.top
        anchors.topMargin: 48
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 5
        cursorShape: Qt.SizeHorCursor
        width: 5
        onPressed: {
            startMousePos = absoluteMousePos(leftArea)
            startWindowPos = Qt.point(mainWindow.x, mainWindow.y)
            startWindowSize = Qt.size(mainWindow.width, mainWindow.height)
        }
        onMouseXChanged: {
            var abs = absoluteMousePos(leftArea)
            var newWidth = Math.max(mainWindow.minimumWidth, startWindowSize.width - (abs.x - startMousePos.x))
            var newX = startWindowPos.x - (newWidth - startWindowSize.width)
            mainWindow.x = newX
            mainWindow.width = newWidth
        }

        Rectangle {
            anchors.fill: parent
            color: "red"
        }
    }

    MouseArea {
        id: rightArea
        width: 5
        x: parent.width - rightArea.width
        anchors.right: parent.rigth
        anchors.top: parent.top
        anchors.rightMargin: 5
        anchors.topMargin: 48
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 5
        cursorShape: Qt.SizeHorCursor

        onPressed: {
            startMousePos = absoluteMousePos(rightArea)
            startWindowPos = Qt.point(mainWindow.x, mainWindow.y)
            startWindowSize = Qt.size(mainWindow.width, mainWindow.height)
        }
        onMouseXChanged: {
            var abs = absoluteMousePos(rightArea)
            var newWidth = Math.max(mainWindow.minimumWidth, startWindowSize.width + (abs.x - startMousePos.x))
            mainWindow.width = newWidth
        }

        Rectangle {
            anchors.fill: parent
            color: "red"
        }
    }

    MouseArea {
        id: buttonArea
        y: parent.height - buttonArea.height
        height: 5
        anchors.leftMargin: 5
        anchors.left: parent.left
        anchors.rightMargin: 5
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        cursorShape: Qt.SizeVerCursor

        onPressed: {
            startMousePos = absoluteMousePos(buttonArea)
            startWindowPos = Qt.point(mainWindow.x, mainWindow.y)
            startWindowSize = Qt.size(mainWindow.width, mainWindow.height)
        }
        onMouseYChanged: {
            var abs = absoluteMousePos(buttonArea)
            var newHeight = Math.max(mainWindow.minimumHeight, startWindowSize.height + (abs.y - startMousePos.y))
            mainWindow.height = newHeight
        }

        Rectangle {
            anchors.fill: parent
            color: "red"
        }
    }

}

0
投票

我有这个问题的解决方案。
https://github.com/tongmon/qt-frameless-windows

如果你分析我的模板项目,你可以知道在无框Qt窗口上启用调整大小功能的关键点是WM_NCHITTEST消息。

像下面的代码一样。

case WM_NCHITTEST: {
    RECT winrect;
    GetWindowRect(msg->hwnd, &winrect);
    long x = GET_X_LPARAM(msg->lParam);
    long y = GET_Y_LPARAM(msg->lParam);

    if (x >= winrect.left && x < winrect.left + m_resize_border_width &&
        y < winrect.bottom && y >= winrect.bottom - m_resize_border_width)
    {
        *result = HTBOTTOMLEFT;
        return true;
    }

    if (x < winrect.right && x >= winrect.right - m_resize_border_width &&
        y < winrect.bottom && y >= winrect.bottom - m_resize_border_width)
    {
        *result = HTBOTTOMRIGHT;
        return true;
    }

    if (x >= winrect.left && x < winrect.left + m_resize_border_width &&
        y >= winrect.top && y < winrect.top + m_resize_border_width)
    {
        *result = HTTOPLEFT;
        return true;
    }

    if (x < winrect.right && x >= winrect.right - m_resize_border_width &&
        y >= winrect.top && y < winrect.top + m_resize_border_width)
    {
        *result = HTTOPRIGHT;
        return true;
    }

    if (x >= winrect.left && x < winrect.left + m_resize_border_width)
    {
        *result = HTLEFT;
        return true;
    }

    if (x < winrect.right && x >= winrect.right - m_resize_border_width)
    {
        *result = HTRIGHT;
        return true;
    }

    if (y < winrect.bottom && y >= winrect.bottom - m_resize_border_width)
    {
        *result = HTBOTTOM;
        return true;
    }

    if (y >= winrect.top && y < winrect.top + m_resize_border_width)
    {
        *result = HTTOP;
        return true;
    }

    *result = HTTRANSPARENT;
    break;
}
© www.soinside.com 2019 - 2024. All rights reserved.