Difference between Window and ApplicationWindow in QML? - qt

https://doc.qt.io/qt-5/qml-qtquick-controls2-menubar.html
MenuBar is supported in ApplicationWindow and not in Window.
Following throws an error "Invalid property name: MenuBar"
Window
{
visible: true
width: 280; height: 280
menuBar: MenuBar {
Menu {}
}
}
whereas following works:
ApplicationWindow
{
visible: true
width: 280; height: 280
menuBar: MenuBar {
Menu {}
}
}
In the new Qt version 5.12, the default code uses Window and not ApplicationWindow.
What is the difference between Window and ApplicationWindow? Which one should be used in which case?

The docs is very clear:
ApplicationWindow is a Window that adds convenience for positioning items, such as MenuBar, ToolBar, and StatusBar in a platform independent manner.
That is, it is an item that inherits from Window but has certain default attributes, it is similar to QMainWindow with respect to QWidget.
When you say: In the new Qt version 5.12, the default code uses Window and not ApplicationWindow I suppose you mean that QtCreator uses Window by default in creating projects, that's just because the developers wanted to and there is no science in it, just a choice.
When you should use one or the other depends on when you want to customize and if you are comfortable with the ApplicationWindow structure since as you can see the latter has a predefined structure.
Note: There are 2 items called ApplicationWindow 1, 2

Related

QML: Qt.labs.platform.MenuItem's icon

There's a plugin called Qt.labs.platform. Among other things, it provides tray icon with a menu. That menu has a list of MenuItems. Any menu item may have an icon, which would be displayed on the left side of item's text.
There's two ways of setting the icon, none of which work for me:
1) Version 1.0 defined iconSource and iconName properties.
Silently does not work, just shows no icon.
2) Revision 1.1 (declared as Q_REVISION(1)) introduces icon.name, icon.source and icon.mask "sub-properties" (not sure what's the right name for it?)
Fails QML engine with a message:
"MenuItem.icon" is not available in Qt.labs.platform 1.1.
I tried both import Qt.labs.platform 1.1 and 1.0.
Am I missing something in the mechanics of QML revisions or this is a bug in Qt?
A MenuItem is declared in qquickplatformmenuitem_p.h and defined in qquickplatformmenuitem.cpp files.
I'm using ArchLinux, KDE/Plasma. Some other apps (like electron-based) do have their icons in menu showing properly.
UPD Reported as a Qt bug.
I don't know what exactly you are doing to achieve your goal, because there is no minimal reproducible example.
But take a look at here
import QtQuick 2.12
import QtQuick.Window 2.12
// import Qt.labs.platform 1.1
import QtQuick.Controls 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
width: 200
height: 200
anchors.centerIn: parent
MenuBar {
id: menuBar
Menu {
id: firstMenu
MenuItem {
icon.name: "download"
icon.source: "icons/cloud-down-icon.png"
}
MenuItem {
text: qsTr("Rewrap Paragraph")
onTriggered: rewrapParagraph()
}
}
}
}
}
Note: put your icon inside the icons folder in the project folder.
If you click on the menu then you should get a dropdown with two items, first one is just an icon without the text (you can include some text by yourself), second item is just a text.

Dynamically add Menu in MenuBar of ApplicationWindow in QML

I'm trying to create an application that is extensible with plugins. Now the plugins should be able to add a Menu dynamically in the MenuBar.
From documentation I can find a MenuBar that is provided by QtLabsPlatform. This has a method addMenu. But Windows was not in the list of supported platforms. So I cannot benefit from it.
I tried the placeholder technique suggested in Error adding a Menu in QML, but this does not work with QtQuick.Controls 2.13
In the #timday answer in the question you indicate indicates the answer but does not show an example:
...
Dynamic creation of Menus is a little harder; see Qt.createQmlObject
or Qt.createComponent docs. (It may be simpler to just declare all the
ones you need in your code, but with their visible property wired to
whatever logic is appropriate). ...
(emphasis mine)
So my answer is just to show you how to do it although I think you want to add MenuItem to a Menu dynamically, instead of a Menu to a MenuBar:
import QtQuick 2.13
import QtQuick.Controls 2.13
ApplicationWindow {
id: root
width: 640
height: 480
visible: true
menuBar: MenuBar {
Menu {
id: plugins_menu
title: qsTr("&Plugins")
}
}
function onTriggered(item){
console.log(item.text)
}
Component.onCompleted:{
var plugin_names = ["plugin1", "plugin2", "plugin3"]
for(var i in plugin_names){
var item = Qt.createQmlObject('import QtQuick 2.13; import QtQuick.Controls 2.13; MenuItem {}',
plugins_menu)
item.text = plugin_names[i]
plugins_menu.addItem(item)
var f = function(it){
it.triggered.connect(function (){ root.onTriggered(it)
})}
f(item)
}
}
}

Why is loop created in this case?

This examples gives me property binding errors:
file:///home/user/qmltests/layouts.qml:22:4: QML Label: Binding loop detected for property "font.pixelSize"
file:///home/user/qmltests/layouts.qml:22:4: QML Label: Binding loop detected for property "font.pixelSize"
file:///home/user/qmltests/layouts.qml:18:4: QML Label: Binding loop detected for property "font.pixelSize"
Code:
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
Page {
id: root
width: 400
height: 200
StackLayout {
id: main_container
Layout.fillWidth:true
Layout.fillHeight:true
ColumnLayout {
id: sub_container
Layout.fillWidth:true
Layout.fillHeight:true
Label {
text: "One"
font.pixelSize: sub_container.height*0.2
}
Label {
text: "Two"
font.pixelSize: sub_container.height*0.2
}
}
}
}
By logic, this shouldn't happen, because I am copying the width and height down to lower level components by using Layout.fillWidth=true and layout.fillHeight=true
To fix this error, I have to copy the heigth from the root element:
import QtQuick 2.11
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11
Page {
id: root
width: 400
height: 200
StackLayout {
id: main_container
Layout.fillWidth:true
Layout.fillHeight:true
ColumnLayout {
id: sub_container
Layout.fillWidth:true
Layout.fillHeight:true
Label {
text: "One"
font.pixelSize: root.height*0.2
}
Label {
text: "Two"
font.pixelSize: root.height*0.2
}
}
}
}
Why aren't width and height propagated from the root elements down to children layouts?
How can I reference sub_container.width and sub_container.height (because it is known before items are laid out) without getting binding loop error? I don't want to reference the root item because due to complexity there may be many layouts inside root item and in order to lay out components in a scalable way I need to know the width and height of the parent layout.
If you use layouts, the elements they manage must not change their size based
on size given by the layout. To do what you wish to do, you shouldn’t be using a layout, but anchors, since you want to manage the child sizes manually. The loop is there because the layout uses the size of your item to resize itself, that your item then uses to resize itself, endlessly. If you don’t need that functionality, it will interfere – as you have seen. The reason it worked via root is that root’s size is not managed by the layout: it’s fixed. And that’s what you wanted all along, isn’t it?
Another approach would be for the label not to change its size hint based on font size, so that the layout wouldn’t react to the font size change.
TL;DR: Layouts size themselves based on child sizes, thus there’s a loop if the child sizes itself based on the layout’s size.

QML Applicationwindow resize stutter

I am encountering a problem that I hope is because I am bad at coding QML and not because of some fundamental bug in Qt.
Whenever I resize the application window in the horizontal direction (width change) the window doesn't resize to where I release the mouse but "snaps" back to its minimumwidth. I have managed to strip it down to the most basic requirements to reproduce the bug.
Not releasing the mousepress causes the width to dance back and forth between the minimumwidth and where the mouse is.
Removing item removes the bug
Resizing vertically (changing height) MAY sometimes crashes the application if the mouse isn't released for a long time (eg is in state of resizing)
It is practically impossible to resize because of this
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: root
visible: true
minimumHeight: 768
minimumWidth: 1024
title: qsTr("Test")
color: "#292525"
Item {
width: 0.9*parent.width
height: 0.1*parent.height
}
}
Any idea why this is happening?
You have a form of subtle binding loop. QtQuickControls' ApplicationWindow attempts to keep the size of the window's content to match that of the content inside it, called contentItem, which all children of the ApplicationWindow are (silently) reparented into, but you are making the size of your content dependent on the window that it is residing in.
So, you resize your window, which changes the size of your Item, which changes the size of the contentItem, which makes ApplicationWindow resize your window (fighting with you).
Something like this might work:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
id: root
visible: true
minimumHeight: 768
minimumWidth: 1024
title: qsTr("Test")
color: "#292525"
// This item will just match the Window's size...
Item {
anchors.fill: parent
// ... and here, we'll fill a part of it with a rectangle.
Rectangle {
color: "red"
width: 0.9*parent.width
height: 0.1*parent.height
}
}
}

Qt5 QML, when to use a ColumnLayout vs Column?

For example, this works:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.2
ApplicationWindow
{
visible: true
width: 640
height: 480
title: qsTr("Hello World")
function thingWidth()
{
return width*80/100
}
Column
{
spacing: 10;
anchors.horizontalCenter: parent.horizontalCenter
Thing { color: "red"; width: thingWidth(); }
Thing { color: "yellow"; width: thingWidth(); }
Thing { color: "green"; width: thingWidth(); }
}
}
But change Column to ColumnLayout and it doesn't (resizing window causes layout to go wrong).
any help, thanks.
EDIT 1:
Here's also Thing.qml as requested,
import QtQuick 2.0
Item {
property alias color: rectangle.color
width: 50; height: 50
Rectangle
{
id: rectangle
border.color: "white"
anchors.fill: parent
}
}
It looks like my post is mostly code. Yes, nanny it does! that's because people post code on here.
As from the documentation of Column:
Column is a type that positions its child items along a single column. It can be used as a convenient way to vertically position a series of items without using anchors.
Moreover, it eases transitions during insertion, deletion and so on. It also attaches properties to the items to give them notions about their positions.
On the other side, this is the documentation of GridLayout (please, note that ColumnLayout is a convenience utility, but it is nothing more than a grid with one column, as from its documentation).
It has a completely different set of properties, as well as attached properties, completely oriented to the arrangement of the items.
I guess anyway that the most interesting page from the documentation is that one.
I simply cite it:
Positioner items are container items that manage the positions of items in a declarative user interface. Positioners behave in a similar way to the layout managers used with standard Qt widgets, except that they are also containers in their own right.
Positioners make it easier to work with many items when they need to be arranged in a regular layout.
Qt Quick Layouts can also be used to arrange Qt Quick items in a user interface. They manage both the positions and the sizes of items on a declarative user interface, and are well suited for resizable user interfaces.
Please, note that a Column is a Positioner, while a ColumnLayout is a Layout. When to use them depends mainly on your goal, as usual.

Resources