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