I wonder why I get this result
As you can see, the Header is above the rectangle.
When I check everything, I got toolBar.parent === rect.parent. So the parent is common at both. Since the parent is the same, when I do anchors.top: parent.top I must not get something like anchors.top: toolBar.bottom.
Here is my full code :
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
import "EasyWidget"
ApplicationWindow {
id: mainWindow;
visible: true;
width: 480;
height: 640;
title: qsTr("Easy Music Video");
header: ApplicationToolBar {
id: toolBar;
width: mainWindow.width;
height: mainWindow.height / 8;
title: qsTr("Music");
onClicked: console.log("clicked");
}
Rectangle {
z: 1;
id:rect;
color: Material.color(Material.BlueGrey);
width: mainWindow.width / 3;
anchors {
bottom: parent.bottom;
top: parent.top;
left: parent.left;
//topMargin: -toolBar.height;
}
}
}
I must use the topMargin: -toolBar.height to solve the problem, but I wonder why I get this result since the parent are the same...
The documentation shows the layout:
https://doc.qt.io/qt-5/qml-qtquick-controls2-applicationwindow.html#details
The parent is the same, but the contentItem is positioned below the header, so anchoring rect to the top of it won't do what you want.
To fix it, add this to your Rectangle:
topMargin: -mainWindow.header.height
Related
I'm being tasked with creating a customized title bar for our application. It needs to have rounded corners and a settings button, amongst other things. It will run exclusively on windows.
Our application uses Qt and QML for the front end.
So the only way I could find how to do this is by making the application window frameless and creating the title bar from scratch.
This is my test code:
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"
}
}
And
Here is the title bar code (TitleBar.js file):
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();
}
}
}
}
Now the problem comes with minimizing the application. The first thing I realize is that when using the Qt.FramelessWindowHint flag, the icon does not appear in the Windows Taskbar. Furthermore if I minimize it this happens:
And If I click on it, it doesn't restore.
So my question is, is there a way to reproduce regular minimize behavior when pressing the minimize button?
Or alternatively, is there a way I can completely customize the title bar of the application so that I can achieve the look and feel set by our UI designer?
NOTE: The current look is just a quick test. I have not set the gradient, font, or the aforementioned settings button.
As for me, playing with frameless windows and transparent background is kind of workaround. As I know, the only way to apply a custom shape to the window is QWindow::setMask. Sinse Window is derived from QWindow you can do that in this way.
For example, in the 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, &QWindow::widthChanged, f);
QObject::connect(wnd, &QWindow::heightChanged, f);
f();
Since you 'cut' the shape from the window itself, excluding title bar and frames you can leave the window flags as is.
Look at this way, I try to create something that you do but change completely your code.
the problem that makes change in your window size after you minimize the window is that you didn't set the initial width and height for the window so when you minimize the app it shows in the minimum width and height.
so you need to add just this in main.qml and set the initial width and height to the maximum.
width: maximumWidth
height:maximumHeight
but In the code below I change something else too.
For example, you didn't need to emit signals and then catch them in main.qml
you have access to mainWindow in TitleBar.qml.
in 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()
}
}
}
}
and in 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
}
}
Say I have the following code in a file called NestedCircle.qml:
import QtQuick 2.12
Rectangle {
color: "blue"
radius: Math.min(width, height)
property Rectangle innerCircle: Rectangle {
radius: Math.min(width, height)
x: 10
y: 10
width: parent.width - 20
height: parent.height - 20
color: "yellow"
}
}
Then in main.qml:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
title: "Three circles"
NestedCircle {
// the line below fails with a syntax error, Expected token `:'
property NestedCircle innerCircle.innerCircle: NestedCircle {
color: "red"
}
}
}
So assuming I need to use NestedCircle.qml and can't edit it (this is a minimal example, not the real application), is there a way to put something inside innerCircle wihtout re-making it?
No need for dynamic object creation here, you can do that purely declaratively. In fact here are 4 ways of doing it, dependings on your needs and the API you want:
// NestedCircle.qml
import QtQuick 2.12
Rectangle {
color: "blue"
radius: Math.min(width, height)
default property alias innerCircleData: innerCircle.data
property alias innerCircle: innerCircle
Rectangle {
id: innerCircle
radius: Math.min(width, height)
anchors.centerIn: parent
width: parent.width - 20
height: parent.height - 20
color: "yellow"
}
}
// main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: 800
height: 640
title: "Three circles"
Row {
anchors.centerIn: parent
spacing: 30
NestedCircle { // setting parent in the nested circle
id: rootCircle
width: 100
height: 100
NestedCircle {
parent: rootCircle.innerCircle
width: 50
height: 50
anchors.centerIn: parent
}
}
NestedCircle { // assigning to the inner circle's children in the outer circle
width: 100
height: 100
innerCircle.children: NestedCircle {
width: 50
height: 50
anchors.centerIn: parent
}
}
NestedCircle { // using an alias to the innerCircle.data
width: 100
height: 100
innerCircleData: NestedCircle {
width: 50
height: 50
anchors.centerIn: parent
}
}
NestedCircle { // using an alias to the innerCircle.data as a default property
width: 100
height: 100
NestedCircle {
width: 50
height: 50
anchors.centerIn: parent
}
}
}
}
If you want to add an item that is inside another, a possible solution is for the first item to be a child of the second.
NestedCircle.qml
import QtQuick 2.12
Rectangle {
color: "blue"
radius: Math.min(width, height)
property Rectangle innerCircle: inner
Rectangle {
id: inner
radius: Math.min(width, height)
x: 10
y: 10
width: parent.width - 20
height: parent.height - 20
color: "yellow"
}
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
title: "Three circles"
Component{
id: provider
NestedCircle{
}
}
NestedCircle {
width: 100
height: 100
Component.onCompleted: {
var obj = provider.createObject(innerCircle, {width: 50, height: 50})
obj.anchors.centerIn = innerCircle
}
}
}
I am developing a file browser interface using QML. However, I find I cannot click any folder and the list covered the top button. I don't know what I did wrongly.
I used ListView and FolderListModel during the development. And I intend to make the interface as below and works like a file browser
The expected interface:
Source Code:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import QtQuick.Window 2.1
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.1
import Qt.labs.folderlistmodel 2.1
import QtMultimedia 5.0
import QtQuick.Controls.Styles 1.4
import Qt.labs.platform 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property int index: 0
property bool isActive: true
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Page1 {
Rectangle {
id:root;
state:"hidden";
color: "#212126";
property string folderPathName: "file:///C:/";
property bool rootPath:false;
signal message(string msg);
property int lineHeight: 90;
signal selectedFolder(string folderPath);
Button{
id:topLine;
text: "...";
width: root.width;
height: root.lineHeight;
onClicked: {
if (folderModel.parentFolder != ""){
root.folderPathName = folderModel.parentFolder;
}
else{
root.state = "hidden";
}
}
}
ListView{
id:listFileView;
anchors{
bottom: rectangleButton.top;
bottomMargin: 4;
right: root.right;
rightMargin: 0;
left: root.left;
leftMargin: 0;
top: topLine.bottom;
topMargin: 0;
}
clip:true;
delegate:Button{
text: fileName;
height:root.lineHeight;
width:root.width;
onClicked: {
if(folderModel.isFolder(index)){
root.folderPathName = folderModel.get(index, "fileURL");
}
}
}
model: FolderListModel{
id:folderModel;
objectName: "folderModel";
showDirs: true;
showFiles: true;
showDirsFirst: true;
nameFilters: ["*.mp3", "*.flac"];
folder:root.folderPathName;
}
}
Rectangle {
id: rectangleButton;
height: 20;
color: "#212126";
anchors{
left: root.left;
leftMargin: 0;
right: root.right;
rightMargin: 0;
bottom: root.bottom;
bottomMargin: 0;
}
Rectangle{
id:rectWhiteLine;
anchors{
left:parent.left;
right: parent.right;
top:parent.top;
}
height: 2;
color:"white";
}
}
}
}
Page {
}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
TabButton {
text: qsTr("Main")
}
TabButton {
text: qsTr("View")
}
}
}
After changing anchors{ bottom: rectangleButton.top; bottomMargin: 4; right: root.right; rightMargin: 0; left: root.left; leftMargin: 0; top: topLine.bottom; topMargin: 0; } to width: 200; height: 600, the interface turns to be below:
The folders cannot be clicked and they are not correctly aligned.
Maybe this example would be of any use to you.
I have added "back" button that goes up one folder, and buttons that represent folders inside ListView are colored orange.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import Qt.labs.folderlistmodel 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: mainRect
x: 20
y: 20
width: 300
height: 450
border.color: "black"
radius: 30
ListView {
y: 30
width: parent.width
height: parent.height - 60
clip: true
model: FolderListModel {
id: folderListModel
showDirsFirst: true
// nameFilters: ["*.mp3", "*.flac"]
}
delegate: Button {
width: parent.width
height: 50
text: fileName
onClicked: {
if (fileIsDir) {
folderListModel.folder = fileURL
}
}
background: Rectangle {
color: fileIsDir ? "orange" : "gray"
border.color: "black"
}
}
}
}
Button {
anchors.left: mainRect.right
anchors.leftMargin: 5
text: "back"
onClicked: folderListModel.folder = folderListModel.parentFolder
}
}
To get clickable top area with "..." I would add Text there and Mouse Area to handle clicks:
Text {
width: parent.width
height: 30
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "..."
MouseArea {
anchors.fill: parent
onClicked: folderListModel.folder = folderListModel.parentFolder
}
}
Add this code inside mainRect i.e. after line radius: 30.
In the example below the Button component doesn't work because Drawer dragMargin overlap it.
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Drawer example")
Drawer {
id: menu
dragMargin: 60
width: window.width * 0.85
height: window.height
background: Rectangle {
color: "blue"
}
}
Button {
id: log
text: "Click me!"
anchors.top: parent.top
anchors.left: parent.left
onClicked: {
console.log("Clicked!");
}
}
}
Is there a way to fix this issue? I tried to change z properties but it doesn't work.
I found this link on the Qt forum. It seems that the problem described is an open issue to be resolved by Qt.
I have a problem using the style property to change the text color of a scrollable TextArea.
I also added the included modules from the .pro file:
QT += qml quick core quickcontrols2
This is what my .qml file looks like:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls.Material 2.0
import QtGraphicalEffects 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Test")
Page {
width: parent.width
height: parent.height
background: Rectangle {
color: "#000000"
width: parent.width
height: parent.height
}
Flickable {
id: flickable
anchors.bottom: parent.bottom
width: parent.width-50
flickableDirection: Flickable.VerticalFlick
height: 200
TextArea.flickable: TextArea {
id: pane1
text: "This is some text"
font.bold: false
font.pointSize: 10
wrapMode: Text.WordWrap
clip: true
style: TextAreaStyle {
textColor: "#4F4F4F"
}
background: Rectangle {
color: "#FFFFFF"
width: parent.width
height: parent.height
}
}
ScrollBar.vertical: ScrollBar { }
}
}
}
The Error message I get when running this example:
QQmlApplicationEngine failed to load component
qrc:/main.qml:38 Cannot assign to non-existent property "style"
I guess I am missing some dependency, but couldn't find anything in the documentation pointing me into the right direction.
Posting #BaCaRoZzo's comment as a community answer.
style property is not available in controls 2. Styling is inlined in the control. See here.
You can also remove import QtQuick.Controls.Styles 1.4 since it is necessary to styling controls 1.x, which you didn't import.