Це свіжі новини про нову функцію в Qt 5.15, яка дуже порадувала.
Зазвичай оформлення вікон були досить нудною річчю. Заголовок, обмежити, мінімізувати, максимізувати, змінити розмір, вийти... і все.
Однак, останнім часом програми все частіше і частіше включають інтерфейс користувача (application specific UI) і оформлення тем. Пара скріншотів для пояснення, про що тут йдеться:
MacOS займається цим досить давно.
... і Chrome, і будь-який інший веб-браузер.
Вбудовування меню в оформлення може заощадити багато місця на екрані.
... або це може бути важливим для брендингу або дизайну.
На жаль, подібні речі раніше не були можливі з Qt.
Однак можна було прибрати оформлення з вікна, тобто:
Window { flags: Qt.FramelessWindowHint }
Але це тільки залишило вас із вікном без оформлення. Таким чином, це не могло бути переміщене або змінене. Якщо б ви спробували реалізувати рух вікна або змінити розмір, схопивши мишу і вручну встановивши розмір і положення вікна, ви швидко виявили б, що це не дуже добре. Менеджери вікон зазвичай мають дуже специфічну поведінку при переміщенні або зміні розмірів вікон. Звичайні дії: перетягування вгору, щоб максимізувати, перетягування ліворуч/праворуч на плитку, прив'язка до інших вікон або панелі завдань, зміна розмірів двох вікон одночасно, якщо вони розташовані поруч один з одним і так далі.
Заради справедливості, раніше був наданий один помічник - QSizeGrip. Він дозволяє змінити розмір будь-якого заданого кута вікна, але працює тільки з кутами, а не з межами вікна, і доступний тільки для програм віджетів.
У Qt 5.15 було додано два нових методи QWindow: startSystemMove і startSystemResize. Ці методи просять віконний менеджер вступити у володіння та розпочати власну операцію зміни розміру чи переміщення. Це означає, що прив'язка, розбиття на тайли і так далі повинні працювати просто чарівним чином, а реалізація заголовка в QML стає майже однорядковою:
DragHandler { onActiveChanged: if (active) window.startSystemMove(); target: null }
Помістивши цей фрагмент коду елемент QtQuick, всі тригер операції перетягування викличуть операцію переміщення власного вікна.
startSystemResize працює аналогічно, за винятком того, що він приймає аргумент Qt::Edges, який є бітовим полем меж вікна, які ви захопили, тобто для нижнього правого кута, ви б викликали:
startSystemResize(Qt.RightEdge | Qt.BottomEdge)
Це також дуже зручно, так як ви можете легко мати один обробник для всіх чотирьох меж вікна і просто створити аргумент кордону наступним чином:
DragHandler { id: resizeHandler grabPermissions: TapHandler.TakeOverForbidden target: null onActiveChanged: if (active) { const p = resizeHandler.centroid.position; let e = 0; if (p.x < border) e |= Qt.LeftEdge; if (p.x >= width - border) e |= Qt.RightEdge; if (p.y < border) e |= Qt.TopEdge; if (p.y >= height - border) e |= Qt.BottomEdge; window.startSystemResize(e); } }
Якщо ви хочете отримати повний приклад того, як це можна використовувати, було зроблено макет браузера з використанням нового API.
Зверніть увагу, що, хоча це кроссплатформенний API, не всі платформи підтримують його. startSystemMove в даний час підтримується в Wayland, X11, macOS і Windows, а startSystemResize, з іншого боку, підтримується в Wayland, X11 і Windows, але не в macOS.
Щоб упоратися з цим, обидва методи повертають логічне значення, яке вказує, чи була операція підтримана чи ні. Це означає, що якщо ви хочете реалізувати зміну розміру і в macOS, вам доведеться перевірити значення startSystemResize, що повертається, і постаратися зробити все можливе, щоб реалізувати запасний варіант у разі збою, тобто:
if (!window.startSystemResize(edges)) { // your fallback code for setting window.width/height manually }
Подальша робота в Qt буде полягати в тому, щоб надати запасні варіанти або абстракції, які зробили б цю роботу за вас, але, принаймні, ніщо не повинно завадити вам зробити це самостійно.
Інша область покращення - узгодження з віконним менеджером у тому, чи слід використовувати оформлення на стороні клієнта або сервері. Деякі програми можуть захотіти підтримувати обидва режими і дозволити віконному менеджеру вирішувати, але це неможливо. Після встановлення FramelessWindowHint оформлення на стороні сервера не буде.
Третя область – тінь вікна. Принаймні на Wayland тінь має бути намальована як частина оформлення вікна. І хоча можна малювати тіні за допомогою QtQuick, в даний час немає способу повідомити плагін QPA, яка частина поверхні є тінню, а яка - віконною рамкою, що означає, що, якщо ви спробуєте намалювати тіні, менеджер вікон в даний час буде розглянути тіньову частину вікна, і це зіпсує мозаїку та прив'язку з іншими вікнами. На інших платформах диспетчер вікон зазвичай малює тіні навіть для вікон, оформлених на стороні клієнта, тому цю проблему складно вирішити.