I’m a newbie, and I’m trying to get a child window to work. I followed after the controls gallery example, and it doesn’t work right, in my opinion. When you click the button to show the child window, it works fine, and if you click the button that says close it does window1.visible = false, which works fine.
However, if instead of clicking the button you close the window using the x box on the window, it destroys the window and if you try to open it again it displays a window, but the controls are missing.
This program initializes the child window before at the beginning of main.qml. It seems to me that if I initialized the window when I actually click the button, that would work, but I can’t figure out how to do it.
Any ideas?
Here's the code sample:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
title: qsTr("Child Window")
width: 640
height: 480
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
Window {
id: window1
width: 200
height: 200
title: "child window"
flags: Qt.Dialog
Rectangle {
color: syspal.window
anchors.fill: parent
Text {
id: dimensionsText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
width: parent.width
horizontalAlignment: Text.AlignHCenter
}
Text {
id: availableDimensionsText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: dimensionsText.bottom
width: parent.width
horizontalAlignment: Text.AlignHCenter
}
Text {
id: closeText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: availableDimensionsText.bottom
text: "Child Window Test"
}
Button {
anchors.horizontalCenter: closeText.horizontalCenter
anchors.top: closeText.bottom
id: closeWindowButton
text:"Close"
width: 98
tooltip:"Press me, to close this window again"
onClicked: window1.visible = false
}
}
}
Button {
text: qsTr("Open Child Window")
anchors.centerIn: parent
onClicked: {
window1.visible = !window1.visible
}
}
}
If you click on the button in the child window to close it, it works fine. If you click on the x in the corner to close the window, it closes it but next time you open it the control (close window button and text) are not visible.
Related
I have 4 QML files: MainMenu.qml, AppArea.qml, Result.qml and main.qml.
When my app starts, I want to see first page as MainMenu.qml fullscreen. There is a button (on MainMenu.qml) to start AppArea.qml. When I click the the button, I want to start AppArea.qml as fullscreen new window.
There is a button (on AppArea.qml), when I click that button, I want to show Result.qml but I want to see Result.qml on AppArea.qml, I mean when Result.qml come outs, AppArea.qml will not disappear but Result.qml will appear on AppArea.qml.
There is a button on Result.qml. When I click the button, the Repeater in AppArea.qml will regenerate, because maybe model of Repeater changing like 1, 2, 3, 4.... There is a button on AppArea.qml, when I click the button, I want to open MainMenu.qml as a fullscreen new window like AppArea.qml.
Actually you can think basic: My app is a game like this:
How way should I choose for these jobs?
In addition to the mentioned post, in your case you are using the component from qml file, so you need to load the component first, your main.qml can be like this:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
id: mainWindow
title: "Main window"
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Loader{
id: mainMenuLoader
}
Component.onCompleted: {
mainMenuLoader.source="mainMenu.qml"
var mainMenu = mainMenuLoader.item.createObject(mainWindow);
mainWindow.hide()
}
}
and your mainMenu.qml can look like this:
import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Controls 2.2
Component {
id: mainMenu
Window {
id:mmenu
title: "Main Menu"
width: 600
height: 600
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Loader{
id: appAreaLoader
}
Text {
text: "This is mainMenu"
}
Button{
id: loadAppArea
anchors.centerIn: parent
text: "Start Game"
onClicked: {
appAreaLoader.source="appArea.qml"
var appArea = appAreaLoader.item.createObject(mainMenu);
hide()
}
}
}
}
you will need to do the same for successive windows ...etc.
While for result, you need to use a MouseArea:
appArea.qml:
Component {
id: appMenu
Window {
id:appMenuWindow
title: "App Menu"
width: 600
height: 600
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Loader{
id:anotherLoader
visible: true
anchors.left: appMenuText.left
anchors.top: appMenuText.bottom
width: parent.width/3
height: parent.height/3
}
Text {
id: appMenuText
text: "This is App Area"
anchors.centerIn: parent
}
Button{
id: loadResult
text: "Show Result"
onClicked: {
anotherLoader.source = "result.qml"
anotherLoader.visible=true
}
}
Button{
anchors.right: parent.right
id: loadMainMenu
text: "Open main Menu"
onClicked: {
hide()
//mmenu.show()
anotherLoader.setSource("main.qml")
}
}
}
}
result.qml:
Rectangle{
color: "green"
Text {
anchors.centerIn: parent
id: resultxt
text: qsTr("This is result, Click to close")
}
MouseArea {
anchors.fill: parent
onClicked: { anotherLoader.visible = false
}
}
}
I have a SwipeView that loads its internal elements through a Repeater and a Loader.
I would like to swipe between the items forward and backward by just clicking the arrows on the right and left of the SwipeView.
How can I implement this behavior in QML?
SwipeView {
id: __swipeView
Layout.fillHeight: true
Layout.fillWidth: true
Repeater {
model: 3
Loader {
source: "qrc:/../SwipeDelegate.qml"
}
}
}
Within your delegate, you can access the SwipeView via the SwipeView attached property, and then increment or decrement the current index as necessary:
import QtQuick 2.6
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
SwipeView {
anchors.fill: parent
Repeater {
model: 3
Item {
id: delegate
Button {
text: "<"
enabled: index > 0
onClicked: delegate.SwipeView.view.decrementCurrentIndex()
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
}
Label {
text: "Page " + (index + 1)
anchors.centerIn: parent
}
Button {
text: ">"
enabled: index < delegate.SwipeView.view.count - 1
onClicked: delegate.SwipeView.view.incrementCurrentIndex()
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
It's important to use the functions as opposed to setting currentIndex directly, for the reasons described here.
I've been playing around with dialogs and there is something that bothers me.
I have the following code:
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Button {
id: click
x: 285
y: 189
text: qsTr("Click")
onClicked: dlgTest.open()
}
Dialog{
id:dlgTest
visible:false
contentItem: Rectangle{
width: 300
height: 300
TextField{
id: tfText
anchors.top: parent.top
}
Button{
anchors.top: tfText.bottom
onClicked: dlgTest.close()
text: "Close"
}
}
}
}
When I open it the first time I add some text to the TextField and then I close it. However, If I open it again, the text will still be there. What I want is to "reset" the dialog to it's original state when I opened it the first time (with an empty TextField). It seems that calling the method "close" is exactly the same as changing visible to false.
Is there a way of doing this "reset"?
I have an other dialog with a lot of controls and it's annoying having to restore everything manually.
In your code you create the Dialog once, as a child of the ApplicationWindow.
To 'reset' it, you have two options:
Have a reset-function, that you call, and restores everything. You can use this to set it up in the first place as well
Create a new Object with everything set in place.
For the latter you can either use JavaScript Dynamic Object Creation or a Loader.
JavaScript Dynamic Object Creation:
Button {
id: click
x: 285
y: 189
text: qsTr("Click")
onClicked: {
var d = diaComp.createObject(null)
d.open()
}
}
Component {
id: diaComp
Dialog{
id:dlgTest
visible:false
contentItem: Rectangle{
width: 300
height: 300
TextField{
id: tfText
anchors.top: parent.top
}
Button{
anchors.top: tfText.bottom
onClicked: {
dlgTest.close()
dlgTest.destroy()
}
text: "Close"
}
}
}
}
However, as you destroyed the Object, the contents of your properties are lost, and you can't access them anymore. So you need to make sure, to copy them (not bind them) to some property that is not destroyed, first.
With the Loader you have the posibility to unload the Dialog right before you load it again, which basically resets it. But until you unloaded it, you can still access it's values, as you can see in the Buttons onClicked-handler.
Button {
id: click
x: 285
y: 189
text: qsTr("Click")
onClicked: {
console.log((dlgLoad.status === Loader.Ready ? dlgLoad.item.value : 'was not loaded yet'))
dlgLoad.active = false
dlgLoad.active = true
dlgLoad.item.open()
}
}
Loader {
id: dlgLoad
sourceComponent: diaComp
active: false
}
Component {
id: diaComp
Dialog{
id:dlgTest
visible:false
property alias value: tfText.text
contentItem: Rectangle{
width: 300
height: 300
TextField{
id: tfText
anchors.top: parent.top
}
Button{
anchors.top: tfText.bottom
onClicked: {
dlgTest.close()
}
text: "Close"
}
}
}
}
Of course, you could also copy the values from the Loader's item as well, and then unload it earlier, to possible free the memory.
But if the Dialog is frequently (most of the time) shown, it might be the wisest to avoid the creation and destruction of the objects, by reusing it and resetting it manually.
I'd like to have an ApplicationWindow have an auto-hiding menuBar, which shows up when mouse cursor is positioned on the uppermost part of the window. Is this possible in QML?
PS: I'm using Qt 5.3.
Thanks in advance.
You can exploit internal properties, i.e. properties starting with "__". Since they are internal, functionality could break in future releases even if IMO it is unlikely in this case.
By using internal properties you can exploit __contentItem, the graphical container of the MenuBar and animate its properties to achieve the desired result. Here is a possible approach; it works with Qt 5.3/ Qt 5.4/ Qt 5.5 (the ones I could test it on):
ApplicationWindow {
id: app
visible: true
width: 400
height: 300
property real hideValue: 0
Behavior on hideValue {
NumberAnimation {duration: 200}
}
menuBar: MenuBar {
id: menu
//__contentItem.scale: value // (1)
//__contentItem.opacity: hideValue // (2)
__contentItem.transform: Scale {yScale: hideValue} // (3)
Menu {
id: m1
title: "File"
MenuItem { text: "Open..."
onTriggered: {
hideValue = 0 // hide the bar
}
}
MenuItem { text: "Close"
onTriggered: {
hideValue = 0 // hide the bar
}
}
}
}
Button{
id: b1
anchors.centerIn: parent
text: "CLICK ME!"
width: 100
height: 100
}
MouseArea {
id: ma1
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: menu.__contentItem.implicitHeight
hoverEnabled: true
onEntered: {
hideValue = 1 // show the bar
}
}
MouseArea {
id: ma2
anchors.fill: parent
hoverEnabled: true
z: -1
onEntered: {
m1.__dismissMenu()
hideValue = 0 // hide the bar
}
}
}
Summarizing the code:
Two MouseArea are defined: ma1 which covers the MenuBar and ma2 which fills the ApplicationWindow. The latter has a z negative to be positioned under any other element of the window, inclusing ma1: this way it cannot interfere with events related to any element added (such as the example button b1).
ma1 sets a property called hideValue to 1 whereas ma2 brings it back to 0. The property is used over a visual property of __contentItem (see (1), (2) and (3) in the code) to hide/show the MenuBar. A simple Behaviour over the hideValue property ensures that the transition is smooth.
Internal function __dismissMenu() is used to ensure that an opened Menu is closed when the MenuBar loses focus.
When a MenuItem is triggered the hideValue property is directly reset to ensure correct hiding.
I managed to get some results with this code:
ApplicationWindow {
id: app
MenuBar {
id: menu
Menu {
title: "Menu 1"
MenuItem {
text: "item 1"
}
MenuItem {
action: "item 2"
}
}
}
MouseArea {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 20
hoverEnabled: true
onEntered: {
if (app.menuBar === menu)
app.menuBar = null;
else
app.menuBar = menu;
}
}
}
The change however is abruptly and QML debugging report errors when trying to access null.__contentItem when the bar is hidden. And, of course, there's an absolute size in the code which could cause problems.
I am creating desktop application using QML and QtQuick.Components. I want to place on the toolbar buttons like the standard MacOS settings dialogs do:
I use ToolBar and ToolButton, but I can't find the way to do it. For instance with the following code it shows icons only:
ApplicationWindow {
// ...
toolBar: ToolBar {
RowLayout {
ToolButton {
text: qsTr("Main")
iconSource: "main.png"
}
ToolButton {
text: qsTr("System")
iconSource: "system.png"
}
ToolButton {
text: qsTr("Items Book")
iconSource: "itemsbook.png"
}
}
}
}
And it seems like ToolButton can show either text or icon:
Text {
id: textitem
text: button.text
anchors.centerIn: parent
visible: button.iconSource == "" // <=========
}
A simple yet a powerful approach is to create own QML component.
Create a custom QML component / file:
File -> New File or Project -> Qt -> QML File (choose latest version).
Now enter file name, for example MyToolButton.
Note that it will be also used as
component name.
Add there neccesary imports and code:
MyToolButton.qml (customize for your needs)
import QtQuick 2.0
import QtQuick.Controls 1.4
ToolButton
{
Image {
source: parent.iconSource
fillMode: Image.PreserveAspectFit // For not stretching image (optional)
anchors.fill: parent
anchors.margins: 2 // Leaving space between image and borders (optional)
anchors.bottomMargin:10 // Leaving space for text in bottom
}
Text {
text: parent.text
anchors.bottom: parent.bottom // Placing text in bottom
anchors.margins: 2 // Leaving space between text and borders (optional)
anchors.horizontalCenter: parent.horizontalCenter // Centering text
renderType: Text.NativeRendering // Rendering type (optional)
}
}
Main.QML (where you want to use it):
import QtQuick 2.0
import QtQuick.Controls 1.4
// Usual toolbar declaration
ToolBar {
id: mainToolBar
RowLayout {
// Create MyToolButton. Note that component name (MyToolButton) is the same as file name.
MyToolButton {
id:tbQuit
// Way 1: Add here any icon
iconSource: "qrc:///images/quit.png"
text:qsTr("&Quit")
// Way 2, my favourite: Convert your Action into Button!
action: actQuit
}
}
}
Action {
id: actQuit
text: qsTr("&Quit")
onTriggered: Qt.quit()
shortcut: "Alt+Q"
iconSource: "qrc:///Images/Exit.png"
}
Notes:
It requires QtQuick.Controls 1.4 and should work on Qt 5.2+. (Worked fine on Qt 5.5).
Don't forget to add imports.
Code parts marked as (optional) can be skipped.
Replace ToolButton with Button and it will work as a Button.
Hope it helps!
Have you try to add your own Text control like this:
ApplicationWindow {
// ...
toolBar: ToolBar {
RowLayout {
ToolButton {
text: qsTr("Main")
iconSource: "main.png"
Text {
text: parent.text
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
ToolButton {
text: qsTr("System")
iconSource: "system.png"
Text {
text: parent.text
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
ToolButton {
text: qsTr("Items Book")
iconSource: "itemsbook.png"
Text {
text: parent.text
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
}
And set the ToolButton height with the right value (image + text height)