- 1. main.qml
Если по какой-то причине, вы решили отказаться от стандартного системного обрамления окна и реализовать все Title Bar`ы окна самостоятельно в QML, то вы вполне можете реализовать это средствами QML, что будет даже проще чем в C++, на мой взгляд. Для ознакомления можете посмотреть статью по кастомизации окна приложения в стиле AIMP . Там имеется значительная доля кода по реализации механики перемещания окна, а также его ресайза. Преимущество QML в данном случае состоит в том, что QML сразу обеспечивает верстку приложения, а значит можно с помощью MouseArea и якорей сразу определить нужную обработку при клике и перемещении мыши без каких-либо специальных расчётов положения курсора в области окна.
А механика расчёта изменения размеров и положения будет сходна с той, которая была применена в статье по кастомизации приложения в C++. То есть необходимо будет запомнить положение, где была нажата кнопка мыши, а потом уже относительно этого положения делать ресайз и перемещение окна приложения, пока кнопка не будет отпущена.
Как видно на рисунке выше, потребуется создать 5 областей MouseArea, четыре из которых будут отвечать за ресайз приложения, а пятая центральная за перемещение приложения. То есть можно будет передвигать приложение зажав кнопку мыши в любом месте пятой центральной области.
Если Вам понадобится специальный Title Bar, то он также может отвечать за перемещение окна приложения. То есть необязательно делать всю центральную область чувствительной к перемещению.
main.qml
Приложение создаётся по умолчанию и изменять будет только файл main.qml, который я и приведу в качестве примера.
- import QtQuick 2.7
- import QtQuick.Controls 2.0
- import QtQuick.Layouts 1.3
- ApplicationWindow {
- id: mainWindow
- visible: true
- width: 640
- height: 480
- flags: Qt.FramelessWindowHint // Отключаем обрамление окна
- // Объявляем свойства, которые будут хранить позицию зажатия курсора мыши
- property int previousX
- property int previousY
- MouseArea {
- id: topArea
- height: 5
- anchors {
- top: parent.top
- left: parent.left
- right: parent.right
- }
- // Устанавливаем форму курсора, чтобы было понятно, что это изменение размера
- cursorShape: Qt.SizeVerCursor
- onPressed: {
- // Запоминаем позицию по оси Y
- previousY = mouseY
- }
- // При изменении позиции делаем пересчёт позиции окна, и его высоты
- onMouseYChanged: {
- var dy = mouseY - previousY
- mainWindow.setY(mainWindow.y + dy)
- mainWindow.setHeight(mainWindow.height - dy)
- }
- }
- // Аналогичные расчёты для остальных трёх областей ресайза
- 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)
- }
- }
- MouseArea {
- id: leftArea
- width: 5
- anchors {
- top: topArea.bottom
- bottom: bottomArea.top
- left: parent.left
- }
- cursorShape: Qt.SizeHorCursor
- onPressed: {
- previousX = mouseX
- }
- onMouseXChanged: {
- var dx = mouseX - previousX
- mainWindow.setX(mainWindow.x + dx)
- mainWindow.setWidth(mainWindow.width - dx)
- }
- }
- MouseArea {
- id: rightArea
- width: 5
- anchors {
- top: topArea.bottom
- bottom: bottomArea.top
- right: parent.right
- }
- cursorShape: Qt.SizeHorCursor
- onPressed: {
- previousX = mouseX
- }
- onMouseXChanged: {
- var dx = mouseX - previousX
- mainWindow.setWidth(mainWindow.width + dx)
- }
- }
- // Центральная область для перемещения окна приложения
- // Здесь уже потребуется использовать положение как по оси X, так и по оси Y
- MouseArea {
- anchors {
- top: topArea.bottom
- bottom: bottomArea.top
- left: leftArea.right
- right: rightArea.left
- }
- onPressed: {
- previousX = mouseX
- previousY = mouseY
- }
- onMouseXChanged: {
- var dx = mouseX - previousX
- mainWindow.setX(mainWindow.x + dx)
- }
- onMouseYChanged: {
- var dy = mouseY - previousY
- mainWindow.setY(mainWindow.y + dy)
- }
- }
- }
Огромное спасибо
Драсте, спасибо за хороший урок.
Это скорее всего баг Qt под конкретной операционной системой. Какую используете?
Дело в том, что я проверил Ваш код под свой рабочей системой (KDE Neon 5.8) и всё работает стабильно, без нареканий. То есть минимизация окна происходит без проблем. Под Windows проверить не могу, на данный момент у меня нет рабочих установок этой системы.
Использую Windows 7 Ultimate.
Тогда это однознано баг, я бы глянул на официальном багтрекере Qt, есть ли информация об этом баге, и возможно стоит создать таск с этим багом.
Спасибо! Этим и займусь. Ещё попробую скинуть проект другу, посмотрю, как QT будет справляться там.
После отключения системного обрамления не работают minimumHeight и minimumWidth. Что делать?
Задать свои property в окне и проверять их в методах изменения размера для topArea, bottomArea, rightArea, leftArea.
Еще не могли бы подсказать как сделать чтобы отображалась иконка, так как она тоже исчезла. Весь интернет обыскал так и не нашел решения.
Какая иконка? Которая была в оформлении окна? Ну всё логично, оформление отключили - иконка исчезла. Хотите иконку, придётся самосттоятельно добавить её в левый верхний угол окна через какой-нибудь QML тип Image.
Извиняюсь за не точность. Я имел в виду иконку в Taskbar.
Вы же под Windows пишете? Есть такой класс QWinTaskbarButton, у него есть property overlayIcon . Возможно, стоит поработать с этим клсассом и установить туда иконку. Вот в этой статье есть пример работы с этим QWinTaskbarButton .
Огромное спасибо, работает.
Я бы вместо совытий mouseXChanged и mouseYChanged использовал positionChanged, так как у двух первых есть один недостаток, они производные от mouseX и Y которые содержат текущие координаты X и Y соответсвенно - это значит что они обновляются (записываются) регулярно при нажатой кнопки мыши (если свойство hoverEnabled будет true то они будут обновляться и без нажатия кнопок мыши). Это значит, что эти свойства вызывают ложную логику, если вы еще не двигали курсор мыши, а просто нажали кнопку мыши. В то время как positionChanged срабатывает только когда положение курсора в действительности было изменено при нажатой кнопки мыши (если hoverEnabled = false, опять же).
Здравствуйте. Сделал подобным образом ресайз и в Qt Widgets, и в QML. Везде получаю, что при изменении размера через левую или верхннюю границы проихсодит мерцание подобно как на этом видео . Всё перелопатил, нигде ответа не нашел. Не знаете как это победить?
Добрый день. Нет, если сами по себе координаты при ресайзе все подсчитываются правильно, то это уже проблема графической подсистемы в ОС и работы с X11, если вы конечно под Linux собирали проект. В том видео в исходниках крутят платформозависимые флаги. На тему тех флагов есть Bug на багтрекере Qt . Возможно также локальная проблема с конкретным дистрибутивом, если на мейнстримовых дистрибутивах всё работает хорошо. В общем скорее всего это та помойка, в которой не хотелось бы копаться.