#qt #qml
Вопрос:
Мне поручено создать настраиваемую строку заголовка для нашего приложения. Помимо прочего, она должна иметь закругленные углы и кнопку настроек. Он будет работать исключительно в Windows.
Наше приложение использует Qt и QML для интерфейса. Итак, единственный способ, которым я мог найти, как это сделать, — сделать окно приложения без рамки и создать строку заголовка с нуля.
Это мой тестовый код:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.0
ApplicationWindow {
id: mainWindow
visible: true
visibility: Window.Maximized
title: qsTr("Hello World")
flags: Qt.FramelessWindowHint | Qt.Window | Qt.WA_TranslucentBackground
//flags: Qt.Window | Qt.WA_TranslucentBackground
color: "#00000000"
TitleBar {
id: mainTitleBar
width: mainWindow.width;
height: mainWindow.height*0.018
color: "#aaaaaa"
onCloseApplication: {
Qt.quit();
}
onMinimizeApplication: {
mainWindow.visibility = Window.Minimized
}
}
Component.onCompleted: {
console.log("Size: " mainWindow.width "x" mainWindow.height)
mainTitleBar.width = mainWindow.width
mainTitleBar.height = mainWindow.height*0.023;
}
Rectangle {
id: content
width: mainWindow.width
height: mainWindow.height - mainTitleBar.height
anchors.top: mainTitleBar.bottom
anchors.left: mainTitleBar.left
color: "#00ff00"
}
}
И
Вот код строки заголовка (TitleBar.js файл):
import QtQuick 2.0
import QtQuick.Controls 2.0
Rectangle {
/*
* Requires setting up of
* -> width
* -> height
* -> title text
* -> icon path.
* -> Background color.
*/
id: vmWindowTitleBar
border.width: 0
x: 0
y: 0
radius: 20
signal closeApplication();
signal minimizeApplication();
// The purpose of this rectangle is to erase the bottom rounded corners
Rectangle {
width: parent.width
height: parent.height/2;
anchors.bottom: parent.bottom
anchors.left: parent.left
border.width: 0
color: parent.color
}
Text {
id: titleBarText
text: "This is The Title Bar"
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: parent.width*0.018
}
Button {
id: minimizeButton
width: height
height: vmWindowTitleBar.height*0.8
anchors.right: closeButton.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: parent.width*0.018
background: Rectangle {
id: btnMinimizeRect
color: vmWindowTitleBar.color
anchors.fill: parent
}
onPressed:{
minimizeApplication()
}
scale: pressed? 0.8:1;
contentItem: Canvas {
id: btnMinimizeCanvas
contextType: "2d"
anchors.fill: parent
onPaint: {
var ctx = btnMinimizeCanvas.getContext("2d");
var h = minimizeButton.height;
var w = minimizeButton.width;
ctx.reset();
ctx.strokeStyle = minimizeButton.pressed? "#58595b": "#757575";
ctx.lineWidth = 6;
ctx.lineCap = "round"
ctx.moveTo(0,h);
ctx.lineTo(w,h);
ctx.closePath();
ctx.stroke();
}
}
}
Button {
id: closeButton
//hoverEnabled: false
width: height
height: vmWindowTitleBar.height*0.8
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: parent.width*0.018
background: Rectangle {
id: btnCloseRect
color: vmWindowTitleBar.color
anchors.fill: parent
}
onPressed:{
closeApplication()
}
scale: pressed? 0.8:1;
Behavior on scale{
NumberAnimation {
duration: 10
}
}
contentItem: Canvas {
id: btnCloseCanvas
contextType: "2d"
anchors.fill: parent
onPaint: {
var ctx = btnCloseCanvas.getContext("2d");
var h = closeButton.height;
var w = closeButton.width;
ctx.reset();
ctx.strokeStyle = closeButton.pressed? "#58595b": "#757575";
ctx.lineWidth = 2;
ctx.lineCap = "round"
ctx.moveTo(0,0);
ctx.lineTo(w,h);
ctx.moveTo(w,0);
ctx.lineTo(0,h);
ctx.closePath();
ctx.stroke();
}
}
}
}
Теперь проблема связана с минимизацией приложения. Первое, что я понимаю, это то, что при использовании флага Qt.FramelessWindowHint значок не отображается на панели задач Windows. Кроме того, если я минимизирую это, это произойдет:
И если я нажму на нее, она не восстановится.
Итак, мой вопрос в том, есть ли способ воспроизвести обычное поведение минимизации при нажатии кнопки минимизации?
Или, в качестве альтернативы, есть ли способ полностью настроить строку заголовка приложения, чтобы я мог добиться внешнего вида, установленного нашим дизайнером пользовательского интерфейса?
ПРИМЕЧАНИЕ: текущий вид — это просто быстрый тест. Я не установил градиент, шрифт или вышеупомянутую кнопку настроек.
Ответ №1:
Что касается меня, игра с безрамочными окнами и прозрачным фоном — это своего рода обходной путь. Насколько я знаю, единственный способ применить пользовательскую форму к окну — это QWindow::setMask. Sinse Window
является производным от QWindow
вы можете сделать это таким образом.
Например, в main.cpp:
QWindow *wnd = qobject_cast<QWindow *>(engine.rootObjects().at(0));
auto f = [wnd]() {
QPainterPath path;
path.addRoundedRect(QRectF(0, 0, wnd->geometry().width(), wnd->geometry().height()), 30, 30);
QRegion region(path.toFillPolygon().toPolygon());
wnd->setMask(region);
};
QObject::connect(wnd, amp;QWindow::widthChanged, f);
QObject::connect(wnd, amp;QWindow::heightChanged, f);
f();
Поскольку вы «вырезаете» фигуру из самого окна, исключая строку заголовка и фреймы, вы можете оставить флаги окна как есть.
Комментарии:
1. Я попробую это и посмотрю, что у меня получится. Это подход к взаимному тестированию. Но как бы вы, например, добавили кнопку к этому примеру? Мне нужно добавить кнопку «Настройки» со значком шестеренки, кроме нее.
Ответ №2:
Посмотрите на этот способ, я пытаюсь создать что-то, что вы делаете, но полностью меняете свой код.
проблема, которая приводит к изменению размера вашего окна после сворачивания окна, заключается в том, что вы не установили начальное width
значение и height
для окна, поэтому при сворачивании приложения оно отображается с минимальной шириной и высотой.
итак, вам нужно добавить только это main.qml
и установить начальную ширину и высоту на максимум.
width: maximumWidth
height:maximumHeight
но в приведенном ниже коде я также меняю кое-что еще.
Например, вам не нужно было излучать сигналы, а затем перехватывать их в main.qml, к которому у вас есть доступ mainWindow
TitleBar.qml
.
в TitleBar.qml :
import QtQuick 2.0
import QtQuick.Controls 2.0
Rectangle {
anchors.fill: parent
height: 30
Row {
id: row
anchors.fill: parent
Label {
id: label
text: qsTr("Title ")
}
Button {
id: button
x: parent.width -80
text: qsTr("close")
onClicked:
{
mainWindow.close()
}
}
Button {
id: button1
x: parent.width -160
width: 90
text: qsTr("Minimized")
onClicked:
{
mainWindow.showMinimized()
}
}
}
}
и в main.qml :
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.0
import "."
Window {
id: mainWindow
visible: true
visibility: Window.FullScreen
title: qsTr("Hello World")
flags: Qt.FramelessWindowHint | Qt.Window | Qt.WA_TranslucentBackground
width: maximumWidth
height:maximumHeight
Rectangle {
id: content
anchors.fill: parent
x: 0
y: 20
width: mainWindow.width
height: mainWindow.height - mainTitleBar.height
anchors.top: mainTitleBar.bottom
anchors.left: mainTitleBar.left
color: "#00ff00"
}
TitleBar {
id: mainTitleBar
color: "#aaaaaa"
anchors.bottomMargin: parent.height -40
anchors.fill: parent
}
}
Комментарии:
1. Привет. Вы пробовали свой код? Из-за добавления строк, которые вы предложили в мой код (в самом начале), мое приложение вообще не отображается. Кроме того, проблема по-прежнему остается, на панели задач нет значка, и при сворачивании появляется точно такое же изображение. Изменение, которое я сделал, — это использование метода showMinimize .
2. @aarelovich. Я не могу запустить ваш код, потому что я изменяю его и добавляю свой код для ответа.
3. ОК. Таким образом, в принципе, пока установлен флаг Qt.FramelessWindowHint, ОС (Windows) в основном не будет создавать значок для приложения на панели задач, а обычного поведения минимизации просто нет.