QML Window is not visible - qml

I have got QML application and there should be a lot of dialogs. When user press ToolButton appropriate dialog should be visible so that user can modify contols of that dialog. Here is minimum code for that:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
visible: true
property variant dialog: Loader{sourceComponent: wind}
toolBar: ToolBar {
Row {
anchors.fill: parent
ToolButton {
iconSource: "1.png"
checkable: true
checked: false
onClicked: dialog.visible=checked
}
}
}
Component {
id: wind
Window{
visible: false
flags: Qt.Dialog
Button{
text: "hello"
}
}
}
}
However when I press ToolButton dialog is not visible. What is wrong?

property variant dialog: Loader{sourceComponent: wind} - that is wrong, don't expect the element to show when declared as a property, it has to be a child of its parent component.
onClicked: dialog.visible=checked - this is wrong, you need to use the item property of the dialog to refer to the object the loader instantiates
Code that works:
ApplicationWindow {
visible: true
toolBar: ToolBar {
Row {
anchors.fill: parent
ToolButton {
checkable: true
checked: false
onClicked: dialog.item.visible = checked
}
}
}
Loader {
id: dialog
sourceComponent: wind
}
Component {
id: wind
Window {
width: 100
height: 100
Button {
text: "hello"
}
}
}
}

Related

Storing a user's code in a combo box that calls out for its name when selected

I want to make two input text fields (let's call them X and Y) that are in page A,
X: code of the person, Y: name of the person,
Page A contains two text fields for input, and a combo box for selection (for delete purpose), an adding button, and a delete button,
Once the X and Y are filled in the text fields they are inputed using an 'add' button, I want them to be stored when the button is pressed so I can call them back in the page B, or in the combo box in page A,
Page B contains a combo box and a casual text output next to it, the X goes to the combo box, and the Y goes to the text that both are in page B
When I select in page B one X of the many X that already have been inputed, I want the text to change with what have been selected accordingly,
if I want to delete one of the X, I do so by selecting the combobox that exists in Page A and proceed pressing the delete button,
how to store both the X and Y in variables and insert them in comboboxes and the texts, and make a bond between them, connecting each name with its own code ?
PageA
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.VirtualKeyboard 2.14
Item {
id:pageA
width: 1920
height: 1080
property alias codeIn: code.text
property alias nameIn: name.text
TextField{
id:code
y: 0
width: 200
height: 50
placeholderText: qsTr("Type the code here")
}
TextField{
id:name
x: 0
y: 65
width: 200
height: 50
placeholderText: qsTr("Type the name here")
}
ComboBox{
id:selectionForDelete
x: 320
y: 65
width: 200
height: 50
}
Button{
id:adding
x: 29
y:155
text: "add"
onClicked: {
code.clear()
name.clear()
}
}
Button{
id:deleting
x: 355
y: 155
text: "delete"
}
}
PageB
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.VirtualKeyboard 2.14
Item {
id:pageB
width: 1920
height: 1080
ComboBox{
id:codeList
}
Text {
id: relatedName
y:70
text: qsTr("")
}
}
One very simple solution is to declare a ListModel in your main app and when you instantiate either PageA or PageB they will have read/write access to the ListModel.
//MainApp.qml
Page {
ListModel { id: listModel }
PageA { }
PageB { }
}
//PageA.qml
Page {
}
//PageB.qml
Page {
}
As an example, PageA gives the ability to add new users as well as delete existing users, whereas PageB gives the ability to search for existing users:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
RowLayout {
anchors.fill: parent
PageA {
Layout.fillWidth: true
Layout.preferredWidth: 200
Layout.fillHeight: true
}
PageB {
Layout.fillWidth: true
Layout.preferredWidth: 200
Layout.fillHeight: true
}
}
ListModel {
id: listModel
function appendUser(code, name) { append( { code, name } ); }
}
}
//PageA.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
ColumnLayout {
anchors.fill: parent
Frame {
Layout.fillWidth: true
Text { text: qsTr("PageA") }
}
Label { text: qsTr("Users") }
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
model: listModel
delegate: Frame {
width: ListView.view.width
RowLayout {
width: parent.width
Text {
Layout.fillWidth: true
text: model.code + " " + model.name
}
Button {
text: qsTr("Delete")
onClicked: listModel.remove(model.index)
}
}
}
}
Label { text: qsTr("Create new user") }
TextField {
id: code
Layout.fillWidth: true
placeholderText: qsTr("Code")
}
TextField {
id: name
Layout.fillWidth: true
placeholderText: qsTr("Text")
}
Button {
enabled: code.text && name.text
text: qsTr("Add")
onClicked: listModel.appendUser(code.text, name.text)
}
}
}
//PageB.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
ColumnLayout {
anchors.fill: parent
Frame {
Layout.fillWidth: true
Text { text: qsTr("PageB") }
}
Label { text: qsTr("Select Code") }
ComboBox {
id: comboBox
model: listModel
textRole: "code"
valueRole: "name"
}
Label { text: qsTr("Selected Name") }
Text {
text: comboBox.currentValue ?? ""
}
Item {
Layout.fillHeight: true
}
}
}
You can Try it Online!

How to show/hide KDE plasmoid's tooltip programatically?

Is there a way to make a plasmoid tooltip to show/hide programatically?
I tried by setting a ToolTipArea over the compact representation, and trying to trigger it with a Timer - it does not work (the regular tooltip keeps showing but only when hovering the plasmoid icon (aka compactRepresentation):
import QtQuick 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Item {
Layout.preferredWidth: 200
Layout.preferredHeight: 300
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
Plasmoid.compactRepresentation: Item
{
anchors.fill: parent
MouseArea
{
onClicked:
{
plasmoid.expanded = !plasmoid.expanded
}
}
PlasmaCore.ToolTipArea
{
id: toolTip
width: parent.width
height: parent.height
anchors.fill: parent
mainItem: tooltipContentItem
active: false
interactive: true
}
Timer
{
interval: 3000
running: true
repeat: true
onTriggered:
{
if (tooltipContentItem.active == false)
{
toolTip.showToolTip()
toolTip.active == true
}
else
{
toolTip.hideToolTip()
toolTip.active == false
}
}
}
}
Item
{
id: tooltipContentItem
implicitWidth: 300
implicitHeight: 200
ColumnLayout
{
id: mainLayout
anchors
{
left: parent.left
top: parent.top
margins: PlasmaCore.Units.gridUnit / 2
}
PlasmaExtras.Heading
{
id: tooltipMaintext
level: 3
Layout.minimumWidth: Math.min(implicitWidth, preferredTextWidth)
Layout.maximumWidth: preferredTextWidth
elide: Text.ElideRight
text: "Test"
}
PlasmaComponents.Label
{
id: tooltipSubtext
Layout.minimumWidth: Math.min(implicitWidth, preferredTextWidth)
Layout.maximumWidth: preferredTextWidth
text: "Testing text"
opacity: 0.6
}
}
}
}
There's the toolTipItem QQuickItem too, but I cannot figure out if it is possible to make it show or hide on command (this bit was borrowed from KDE's digitalclock plasmoid:
import QtQuick 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Item {
Layout.preferredWidth: 200
Layout.preferredHeight: 300
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
Plasmoid.compactRepresentation: Item
{
anchors.fill: parent
MouseArea
{
onClicked:
{
plasmoid.expanded = !plasmoid.expanded
}
}
}
plasmoid.toolTipItem: Loader
{
id: toolTipLoader
source: "Tooltip.qml" // Just holds the tooltip contents
}
}

Unable to assign [undefined] to QString

I am new to QML so kindly help me out as why QML throws error when trying to build this one
import QtQuick
import QtQuick.Window
import QtQuick.Controls 2.4
Window {
width: 640
height: 480
visible: true
title: qsTr("App title")
ListModel {
id: modelName
ListElement { name: "alpha" }
ListElement { name: "beeta" }
ListElement { name: "gamma" }
}
Component {
id: delegateName
Text {
text: modelName.name // QML throw error here
font.pixelSize: 32
}
}
ListView {
anchors.fill: parent
model: modelName
delegate: delegateName
clip: true
}
}
I'm building this using QT-Creator. Any help would be appreciated
In a delegate, try this one: text: model.name. Every delegate has its own model property with accordingly model's data

Changing model doesn't affect ComboBox

Suppose, we have the following code:
import QtQuick 2.4
import QtQuick.Window 2.0
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
Window {
id: win
width: 800
height: 600
ListModel {
id: listModel
ListElement { name: "element1" }
ListElement { name: "element2" }
ListElement { name: "element3" }
}
ColumnLayout {
anchors.centerIn: parent
width: 200
height: 200
ComboBox {
model: listModel
currentIndex: 1
Layout.fillWidth: true
}
ListView {
model: listModel
delegate: Text {
text: name
}
Layout.fillHeight: true
Layout.fillWidth: true
}
Button {
text: "Change model"
onClicked: {
listModel.get(1).name = "changed text";
//listModel.setProperty(1,"name","changed text"); this line not works too
}
}
}
}
So clicking the button have to change model's element with index 1. But changing the model affects only ListView. The ComboBox remains unchanged.
Why that happens? Is it bug or feature? Is there a way to update ComboBox after changing its model?
I had a similar problem, I used a workaround. In onClicked function of button, create copy of model, change it as you want and then assign it again to ListViews model:
ListView {
id: listView
...
}
Button {
onClicked: {
var copy = listView.model;
copy.get(1).name = "changed text";
listView.model = copy; }
}
}

QML StackView: Item Destroyed on pop

Consider the following example:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
Window {
visible: true
width: 320
height: 320
StackView {
id: stackView
anchors.fill: parent
Component.onCompleted: {
stackView.push( { item: comp1, destroyOnPop:false } )
}
}
Component {
id: comp1
Rectangle {
color: "lightgray"
Text {
id: mtext
anchors.centerIn: parent
text: "First Page"
}
}
}
Component {
id: comp2
Rectangle {
color: "lightgreen"
Text {
id: mtext
anchors.centerIn: parent
text: "Second Page"
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: mtext.text += " Clicked"
}
}
}
Row {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
Button {
id: next
text: "Next"
onClicked: {
stackView.push( { item: comp2, destroyOnPop:false } )
enabled = false
prev.enabled = true
}
}
Button {
id: prev
text: "Prev"
enabled: false
onClicked: {
stackView.pop()
enabled = false
next.enabled = true
}
}
}
}
Here I'm pushing 2 Components into the StackView on the each button clicks, i.e. clicking the "Next" button loads the second page. When I click on it, it displays an updated text("Second Page Clicked"). Then clicking "Prev" loads the first page as expected.
Now if I click "Next" again, it should load the second page with that updated text ("Second Page Clicked"), but it doesn't. It shows the initial text ("Second Page").
So the question is whether the Item is destroyed on pop? If not then shouldn't the second page display the updated text ("Second Page Clicked")?
I have even set the flag destroyOnPop to false. Have I misunderstood the concept of StackView? Any possible way to solve this?
I want to load any page from any point in StackView and that the state of Item be as it is where I left it. Just like QStackWidget, where we use setCurrentIndex().
Documentation is referring to Item object whereas you are using Components. The documentation is pretty clear about the fact that a component is not an Item since it is not derived from Item. Indeed a Component act like a Class which is instanced to a specific object.
Each time you call
stackView.push( { item: comp2, destroyOnPop:false } )
a new "instance" of the component comp2 is generated and such new instance is used instead of the previous one. I strongly suggest to read this article to better understand the correlation between Component objects and generated instances.
Instances can be generated via createObject function. Hence, you can create an array of Items and use such Items instead of the Components. Final code looks like this:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
Window {
visible: true
width: 320
height: 320
StackView {
id: stackView
anchors.fill: parent
Component.onCompleted: {
push( { item: items[0], destroyOnPop:false })
}
property variant items: [comp1.createObject(), comp2.createObject()] // objects from the components
}
Component {
id: comp1
Rectangle {
color: "lightgray"
Text {
id: mtext
anchors.centerIn: parent
text: "First Page"
}
}
}
Component {
id: comp2
Rectangle {
color: "lightgreen"
Text {
id: mtext
anchors.centerIn: parent
text: "Second Page"
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: mtext.text += " Clicked"
}
}
}
Row {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
Button {
id: next
text: "Next"
onClicked: {
stackView.push({ item: stackView.items[1], destroyOnPop:false })
enabled = false
prev.enabled = true
}
}
Button {
id: prev
text: "Prev"
enabled: false
onClicked: {
stackView.pop()
enabled = false
next.enabled = true
}
}
}
}
The same correct result could be achieved by defining directly the Rectagle objects in the source. In this case we have two Items which are reparented to the Window thanks the destroyOnPop set to false.
Rectangle {
id: comp1
color: "lightgray"
visible: false
Text {
id: mtext
anchors.centerIn: parent
text: "First Page"
}
}
Rectangle {
id: comp2
color: "lightgreen"
visible: false
Text {
id: mtext2
anchors.centerIn: parent
text: "Second Page"
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: mtext2.text += " Clicked"
}
}