- 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 . Возможно также локальная проблема с конкретным дистрибутивом, если на мейнстримовых дистрибутивах всё работает хорошо. В общем скорее всего это та помойка, в которой не хотелось бы копаться.