Top.Mail.Ru

Qt.FramelessWindowHint. Перемещение и изменение размеров окна.

Тут на форуме давеча возникла тема, которую также можно отнести к топовым, если оценивать по частоте возникновения данного вопроса. Поэтому я решил оформить ответ более развернуто, чем подразумевается в рамках форума. И пресловутый вопрос заключается в том, как на QML осуществить изменение размеров и перемещение окна приложения, которое является frameless. То есть не имеет стандартной внешней рамки и заголовка, за которые можно было бы его растягивать и перемещать.

Я сегодня приведу базовый вариант, как это сделать, так что переходим сразу к практической части. Создаем пустое Qt Quick приложение и запускаем его, ничего не меняя. А хотя нет, поместим элемент Rectangle на все окно и зададим для него какой-нибудь цвет. Базовый main.qml трансформируется в:

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    id: window
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Rectangle {
        anchors.fill: parent
        color: "#035570"
    }
}
Qt Quick project.

Соответственно, в наличии имеются все дефолтные элементы внешнего вида, в частности, панель сверху, заголовок, кнопки и т. д. По разным причинам, рассмотрение которых нас сегодня не интересует, зачастую все это требуется убрать. Для этого меняем свойство flags у Window:

import QtQuick 2.15
import QtQuick.Window 2.15

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

    Rectangle {
        anchors.fill: parent
        color: "#035570"
    }
}

Мы приблизились к сути вопроса - окно не содержит ничего лишнего, но оно стало неподвластно пользовательскому перемещению и изменению размеров.

Да, кстати, немного сопутствующей информации - если требуется сделать так, чтобы приложение не отображало значка на панели задач, вот тут:

Qt.widget.

То это можно осуществить таким образом:

flags: Qt.Widget | Qt.FramelessWindowHint

Возвращаемся к взаимодействию с окном, которое стало невозможным. Итак, базовый, наиболее наглядный и предельно надежный вариант заключается в следующем:

  • добавляем дополнительные элементы по краю окна, пусть будут обычные Rectangle
  • каждый из них при помощи MouseArea захватывает события мыши в своих пределах
  • дальше - дело техники - непосредственно перемещение, либо изменение размеров окна.

Начнем с изменения размеров, добавляем максимально топорно четыре Rectangle по границам окна (ставлю разные цвета для наглядности, далее, конечно, надо будет изменить на прозрачный):

import QtQuick 2.15
import QtQuick.Window 2.15

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

    Rectangle {
        anchors.fill: parent
        color: "#035570"
    }

    property var resizeRectangleSize: 5

    Rectangle {
        id: resizeRectangleRight
        color: "red"

        anchors.right: parent.right
        anchors.top: parent.top
        anchors.bottom: parent.bottom

        width: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeHorCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.RightEdge);
            }
        }
    }

    Rectangle {
        id: resizeRectangleLeft
        color: "green"

        anchors.left: parent.left
        anchors.top: parent.top
        anchors.bottom: parent.bottom

        width: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeHorCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.LeftEdge);
            }
        }
    }

    Rectangle {
        id: resizeRectangleTop
        color: "blue"

        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top

        height: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeVerCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.TopEdge);
            }
        }
    }

    Rectangle {
        id: resizeRectangleBottom
        color: "yellow"

        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom

        height: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeVerCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.BottomEdge);
            }
        }
    }
}

Полезная деятельность осуществляется при помощи window.startSystemResize(). Кроме того, задаем cursorShape для того, чтобы указатель мыши изменял свой вид при наведении на эти области:

Изменение внешнего вида курсора в QML.

Размер областей задаем при помощи:

property var resizeRectangleSize: 5

Отрабатывает четко, поэтому переходим ко второй подчасти - перемещению окна. Делаем абсолютно аналогично, добавляем еще один Rectangle, пусть будет оранжевый. И при нажатии на него будет происходить перемещение окна:

property var moveRectangleSize: 5

Rectangle {
	color: "orange"
	
	anchors.left: parent.left        
	anchors.right: parent.right
	anchors.top: resizeRectangleTop.bottom        
	
	height: moveRectangleSize

	MouseArea {
		anchors.fill: parent

		onPressed: {
			window.startSystemMove();
		}
	}
}

Собираем, запускаем, тестируем:

Остается только изменить везде цвет: color: "transparent". Такая вот базовая идея и механизм, далее уже зависит от конкретного приложения и целей )

На всякий случай main.qml полностью, цвета на прозрачные не менял:

import QtQuick 2.15
import QtQuick.Window 2.15

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

    Rectangle {
        anchors.fill: parent
        color: "#035570"
    }

    property var resizeRectangleSize: 5
    property var moveRectangleSize: 5

    Rectangle {
        id: resizeRectangleRight
        color: "red"

        anchors.right: parent.right
        anchors.top: parent.top
        anchors.bottom: parent.bottom

        width: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeHorCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.RightEdge);
            }
        }
    }

    Rectangle {
        id: resizeRectangleLeft
        color: "green"

        anchors.left: parent.left
        anchors.top: parent.top
        anchors.bottom: parent.bottom

        width: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeHorCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.LeftEdge);
            }
        }
    }

    Rectangle {
        id: resizeRectangleTop
        color: "blue"

        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top

        height: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeVerCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.TopEdge);
            }
        }
    }

    Rectangle {
        id: resizeRectangleBottom
        color: "yellow"

        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom

        height: resizeRectangleSize

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            cursorShape: containsMouse ? Qt.SizeVerCursor : Qt.ArrowCursor

            onPressed: {
                window.startSystemResize(Qt.BottomEdge);
            }
        }
    }

    Rectangle {
        color: "orange"

        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: resizeRectangleTop.bottom

        height: moveRectangleSize

        MouseArea {
            anchors.fill: parent

            onPressed: {
                window.startSystemMove();
            }
        }
    }
}

P. S. И, конечно, благодарю за поднятую на форуме тему 🤝

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x