How to keep a single instance of the window? - qt

I have the next QML:
import Qt.labs.platform 1.0
SystemTrayIcon {
visible: true
iconSource: "qrc:/icons/ic_tray.png"
menu: Menu {
MenuItem {
text: qsTr("Settings")
onTriggered: {
// Don't create a new object if it exists, just show
var settings = Qt.createComponent("main.qml")
var form = settings.createObject(this)
form.show()
}
}
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit() // Just hide an existing
}
}
}
How to create main.qml one time only and after just show/hide?
P.S. I'm learning Qt including QtQuick 2 only

Depending on how your application is structured, the best way could be to pass in the window that the tray icon shall control as a property from "further up" your user interface structure.
First, extend your tray icon component and add a "window" property to it:
import QtQuick 2.9
import QtQuick.Window 2.2
import Qt.labs.platform 1.0
SystemTrayIcon {
id: trayIcon
// this property holds the window the tray icon controls:
property Window window
visible: true
iconSource: "qrc:/icons/ic_tray.png"
menu: Menu {
MenuItem {
text: qsTr("Settings")
onTriggered: {
trayIcon.window.show();
}
}
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit() // Just hide an existing
}
}
}
Now, you could instantiate your tray icon e.g. in your main window like this:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: mainWindow
width: 800
height: 600
TrayIcon { window: mainWindow }
}
In this case, the tray icon would control the main window itself; however, you can easily create a single instance of a settings window within the main window and pass that one to the tray icon.

You can create the component in the onCompleted.
SystemTrayIcon {
visible: true
iconSource: "qrc:/icons/ic_tray.png"
menu: Menu {
MenuItem {
text: qsTr("Settings")
property var form
onTriggered: {
form.show()
}
Component.onCompleted: {
// Don't create a new object if it exists, just show
var settings = Qt.createComponent("Test.qml")
form = settings.createObject(this)
}
}
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit() // Just hide an existing
}
}
}

Related

Qt QSwipeView with dynamic "interactive" breaks "currentIndex" binding

I'm trying to create a SwipeView where the first page has the interactive property false, while the others have it enabled. The effect that I'm trying to achieve is to have the main page with a link to the others, but the others can only go back to the main page (like the iOS settings menu).
The issue is that after the first change page, the currentIndex property loses binding causing the SwipeView to break.
Here's the application output:
qrc:/main.qml:10:5: QML SwipeView: Binding loop detected for property "currentIndex"
file:///home/rcc/Qt/5.12.6/gcc_64/qml/QtQuick/Controls.2/SwipeView.qml:49:18: QML ListView: Binding loop detected for property "currentIndex"
and here's the default swipe view application (QtCreator -> New Project -> Qt Quick Application - Swipe) main.qml:
import QtQuick 2.12
import QtQuick.Controls 2.5
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Tabs")
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
interactive: false
onCurrentIndexChanged: {
if (currentIndex === 0) {
interactive = false
} else {
interactive = true
}
}
Page1Form {}
Page2Form {}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
TabButton {
text: qsTr("Page 1")
}
TabButton {
text: qsTr("Page 2")
}
}
}
To reproduce the bug:
Click on Page 2.
Swipe left.
Click again on Page 2.
Any suggestions to solve this issue?
I'm still looking into this, but for now you should be able to work around it by delaying the assignment to the interactive property:
onCurrentIndexChanged: {
if (currentIndex === 0) {
Qt.callLater(function() { interactive = false })
} else {
Qt.callLater(function() { interactive = true })
}
}

QML Cannot create Submenu in Menu

I'm trying to create a menu
import QtQuick 2.0
import QtQuick.Controls 2.2
...
Menu {
id: menu
title: "mainMenu"
MenuItem {
text: "menuItem1"
}
MenuItem {
text: "menuItem2"
}
Menu {
title: "contextMenu"
MenuItem {
text: "item1"
}
MenuItem {
text: "item2"
}
}
}
But when I'm trying menu.open() there is no contextMenu
Please find a screenshot below.
How do I fix this?
Qt Quick Controls 2.3 (Qt 5.10) adds support for nested menus and cascading sub-menus.
Maybe you meant to use QtQuick.Controls 1.x where those sub-menus are supported.
In QtQuick.Controls 2.2 - the version you are using - Menu inherits from Popup and therefore behaves like such - meaning, they are closed by default, and you need to set them visible or open() them.
The MenuItem on the other hand are AbstractButtons, that are preconfigured, to close Popups when clicked. If you want to use the QtQuick.Controls 2.x-style Menu you can define your own child type SubMenu which is a button that does not close the parent Popup but opens a second Menu as needed or inserts the right MenuItems when clicked (Accordion-style).
The right implementation depends on your requirements but should not be too challenging. Feel free to ask, if you need more help on this.
Maybe you can use Button instead of MenuItem,and adjust the background of Button yourself,Wrap them up
Item {
id: root
width: 500
height: 500
MouseArea {
id: mouse
anchors.fill: parent
onClicked: {
rootMenu.open()
}
}
Menu {
id: rootMenu
title: "rootMenu"
Button {
text: "menuItem1"
onClicked: {
console.log("choose A")
rootMenu.close()
}
}
Button {
text: "menuItem2"
onClicked: {
console.log("choose B")
rootMenu.close()
}
}
Button {
id: menu_c
text: "menuItem3"
onClicked: secondMenu.open()
}
}
Menu {
id: secondMenu
x: rootMenu.width
y: menu_c.y
MenuItem {
text: "item1"
onTriggered: {
console.log("item1")
rootMenu.close();
}
}
MenuItem {
text: "item2"
onTriggered: {
console.log("item2")
rootMenu.close();
}
}
}
}

Adding TabButton dynamically to TabBar in QML

I am trying to add a tabButton to TabBar dynamically on pressing a button but i have spent a lot of time searching but i am not getting how to add, below is the code which i am working on :
MyTabButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
Item
{
property int BtnWidth:0
property int BtnHeight:0
property string BtnText: ""
property bool isChecked : false
TabButton
{
id:tabBtn
text:BtnText
width:BtnWidth
height:BtnHeight
}
}
MainForm.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
Rectangle
{
Button
{
id:button
width:100
height:100
anchors.top:parent.top
text:qStr("Add")
onClicked{
//How to add logic here to add tab in below tabBar.
}
}
TabBar
{
id:tabBar
anchors.top:button.bottom
width:500
height:500
}
}
Example:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
width: 360
height: 630
visible: true
header: TabBar {
id: tabBar
}
Component {
id: tabButton
TabButton { }
}
Button {
text: "Add"
anchors.centerIn: parent
onClicked: {
var tab = tabButton.createObject(tabBar, {text: "Tab " + tabBar.count})
tabBar.addItem(tab)
}
}
}
You need to have something like a Component that is a TabButton. Your file MyTabButton.qml won't result in a TabButton, but instead an Item containing a TabButton, but with this, your TabBar does not know what to do.
So your file will need to have TabButton as root element
//MyTabButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
TabButton
{
id: tabBtn
// customize as you like
}
Then you create a Component of this in your file where you want to use it. (e.g. main.qml)
import QtQuick 2.4
import QtQuick.Controls 2.0
ApplicationWindow {
width: 800
height: 600
visible: true
TabBar {
id: tabBar
width: 800
height: 50
}
// The component is like a factory for MyTabButtons now.
// Use myTabButton.createObject(parent, jsobject-with-property-assignments) to create instances.
Component {
id: myTabButton
MyTabButton {
/// EDIT ACCORDING TO YOUR COMMENTS ***
Connections {
target: tabBar
onCurrentIndexChanged: doSomething()
}
/// EDIT OVER
}
}
Button {
anchors.centerIn: parent
// Create a object out of the component, and add it to the container
onClicked: tabBar.addItem(myTabButton.createObject(tabBar /*, { object to set properties }*/))
}
}
TabBar inherits Container, which has addItem().
Try it in Window
Row {
anchors.fill: parent
TabBar {
id: tabBar
currentIndex: 0
width: parent.width - addButton.width
TabButton { text: "TabButton" }
}
Component {
id: tabButton
TabButton { text: "TabButton" }
}
Button {
id: addButton
text: "+"
flat: true
onClicked: {
tabBar.addItem(tabButton.createObject(tabBar))
console.log("added:", tabBar.itemAt(tabBar.count - 1))
}
}
}

How to edit App menu from Qt Creator?

I start "QML App with controls" project in Qt Creator. I see that I can add to canvas different kind of controls, but I do not see how I can in graphical mode edit menu like: File, View, Edit... In constructor on canvas it's simple do not exists, but it's exists of running app, like http://img.ctrlv.in/img/15/10/03/560f856edb26c.png
You can create the menu in the main.qml file, here is an example application:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("Save")
onTriggered: messageDialog.show(qsTr("Save action triggered"));
}
}
Menu {
title: qsTr("&Help")
MenuItem {
text: qsTr("About")
onTriggered: messageDialog.show(qsTr("About: test QML app with menu"));
}
}
}
MainForm {
anchors.fill: parent
button1.onClicked: messageDialog.show(qsTr("Button 1 pressed"))
button2.onClicked: messageDialog.show(qsTr("Button 2 pressed"))
}
MessageDialog {
id: messageDialog
title: qsTr("Message Test")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}

Can't close the window with button: QML

I've created an item, that contains a button. I'm trying to close parent window of item with this button, but I'm getting this message, when click the item:
TypeError: Property 'close' of object QQuickRootItem(0x1d8efed8) is not
a function
Can you help me with this?
Code of item:
import QtQuick 2.4
Item {
id: backButton
ItemForButton{
id: baseButton
text: "Back"
onClicked: {
backButton.parent.close()
}
}
}
Code for window:
Window {
id: window
visible: true
BackButton {
}
x: 30
y: 30
}
That seems a bit messy. If I were you, I'd add a clicked signal to the custom button type. For example:
Item:
import QtQuick 2.4
Item {
id: backButton
// Add a clicked signal here
signal clicked()
ItemForButton{
id: baseButton
text: "Back"
onClicked: {
// Emit the new clicked signal here:
backButton.clicked();
}
}
}
Window:
Window {
id: window
visible: true
BackButton {
// Respond to the signal here.
onClicked: window.close();
}
}
This provides the flexibility of using your custom BackButton type in other ways in the future.

Resources