I have two QML files
Level1.qml and level2.qml
in main.qml,
StackView {
id: idMyStackView
focus: true
anchors.fill: parent
initialItem: Level1{
focus: true
}
}
in Level1.qml
Component.onCompleted:
{
idMyStackView.push(idLevel2.qml)
}
In this case I am getting error like
W] (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:790) Warning: StackView: You cannot push/pop recursively!
[D] (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:791) __recursionGuard (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:791)
push (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:568)
onCompleted (qrc:/setup/qml/setup_menu/setup_top/SetupTop.qml:250)
__loadElement (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:825)
__performTransition (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:911)
push (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:605)
expression for onCompleted (file:///C:/Qt/5.13.0/msvc2017/qml/QtQuick/Controls/StackView.qml:777)
Related
Dynamic loading data into a QML SwipeView loaded asyncronous is autmomatically increment the current index.
Loader{
asynchronous: true
anchors.fill: parent
sourceComponent: ColumnLayout{
//Any content here that can take some time to load
TabBar{
Layout.fillWidth: true
Repeater{
model: swRepeater.model
delegate: TabButton{
text: "Tab button "+index
}
}
}
SwipeView{
// anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
currentIndex: 0
Repeater{
id: swRepeater
model: 5
delegate: Item{
Label{
anchors.centerIn: parent
text: qsTr("Test "+index)
}
}
}
onCurrentIndexChanged: {
console.debug("Index was modified to ",currentIndex)
}
}
}
}
At the end of the loading data the current item and index will be 4, and not 0 as explected.
Also is displayed the last item from stack.
The same behavior can be se on the TabBar item so the problem looks to came from ListView or Container.
Any suggestion on this behavior?
I have this code:
//main.qml
Window {
id: root
width: 640
height: 480
visible: true
title: qsTr("Hello World")
objectName: "Window"
onActiveFocusItemChanged: console.log("***** ACTIVE FOCUS:", activeFocusItem, "*****")
StackView {
anchors.fill: parent
initialItem: "qrc:/LoaderPage.qml"
objectName: "StackView"
onCurrentItemChanged: currentItem.forceActiveFocus()
}
}
//LoaderPage.qml
Item {
objectName: "ItemLoaderPage"
// Keys.forwardTo: loader
Loader {
id: loader
anchors.fill: parent
objectName: "Loader"
focus: true
sourceComponent: rect1
}
Component {
id: rect1
Rectangle {
Keys.onReleased: {
if(event.key === Qt.Key_Escape || event.key === Qt.Key_Back)
{
console.log("Esc or back pressed from", objectName)
event.accepted = true
}
}
objectName: "Rectangle"
focus: true
color: "blue"
}
}
}
I am trying to give the focus to the Rectangle in rect1 Component and catch key events, but with this code, the focus is always given to ItemLoaderPage and I am not able to catch key events. How can I solve that?
I find that maintaining keyboard focus is a big weakness in Qt. The docs make it all sound so straightforward, but in practice I am always ending up in situations where I can't even tell where the focus went.
I usually resort to manually calling forceActiveFocus() rather than depending on Qt to do the right thing automatically. It's a fragile solution, but it's at least one that I feel I have control over.
Loader {
sourceComponent: rect1
onLoaded: {
item.forceActiveFocus();
}
}
The Loader and the rectangle has requested the focus by your attribute:
focus: true
You should try to set the focus only once if I get the idea of the focus-attribute right.
I am using Qt 5.9.4 on Ubuntu 18.04.
When my application starts, I want to automatically adjust TableView's column size to its contents. A model have some data on start.
I know about the resizeColumnToContents function, but I have no idea where to call it.
onDataChange does not work in TableView: The QML engine says that this signal does not exist. But intellitype allows me to type it in the code.
How to accomplish that?
EDIT 18/09/18
If you use a StackView or else you can preload your TableView
// main.qml
Loader {
id: tableViewLoader
active: true
sourceComponent: TableView { id: tableView }
}
StackView {
id: stackView
initialItem: listViewLoader
function onContentReceived()
{
stackView.push(tableViewLoader);
tableViewLoader.item.resizeColumnsToContents()
}
function onContentClosed()
{
swipeView.pop()
}
}
EDIT 17/09/18
You are right Danil.
There is specified in TableView.qml that
Depending on how the model is populated, the model may not be ready when
TableView Component.onCompleted is called. In that case you may need to
delay the call to positionViewAtRow by using a \l {QtQml::Timer}{Timer}
For me this is working
Component.onCompleted: resizeColumnsToContentsTimer.start()
Timer {
id: resizeColumnsToContentsTimer
interval: 50
running: false
repeat: false
onTriggered: parent.resizeColumnsToContents()
}
You can also see this discussion about it
http://lists.qt-project.org/pipermail/interest/2016-June/023018.html
Maybe, you can call it in onModelChanged which called when you set your model (your model must be populated before).
onModelChanged: tableView.resizeColumnToContents()
Otherwise, you can use signals/slots when your data ready.
But beware with this function : if you have delegate you must specify implicitWidth in, or this is will not to work.
headerDelegate: Rectangle {
id: headerDelegate
height: 36
implicitWidth: textItem.implicitWidth + textItem.padding * 2
color: Style.lightColor
Text {
id: textItem
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
padding: 10
text: styleData.value
elide: Text.ElideRight
color: Style.darkColor
font.pixelSize: Style.bigFontPixelSize
}
}
I want to instantiate items and then display them using a StackView, via
MyItem0
{
id: item0
}
MyItem1
{
id: item1
}
myStackView.push(item0)
...
myStackView.pop()
myStackView.push(item1)
The problem is that when I create items item0 and item1, they are all shown, which is obviously not what I want.
I guess it somehow relates to this post.
Any idea?
You can implement the items as properties rather than children, which will result in them not showing until they are pushed on the stack view:
property Item item0: MyItem0 { }
property Item item1: MyItem1 { }
However, if you pop, the item will remain visible, as its parent will no longer be null.
pop() is said to return the popped item, so pop().parent = null should do the trick, but for me for some reason it returns a null.
So instead you can simply set the parent explicitly to null:
pop()
item0.parent = null
Naturally, you can just as well set the visible or opacity properties. Which may be preferable, as even more funky and illogical behavior surfaces. if you try to push the same item again after it has been pushed and popped once, it doesn't work, and there is an nothing to push error message in the debug console.
Edit: OK, regarding the last paragraph, it seems that whatever method used, once an object has been pushed and popped, the same object cannot be pushed again, even if the parent is not set to null. This looks like a bug.
Create them with no parent:
import QtQuick 2.5
import QtQuick.Controls 2.0
import QtQuick.Window 2.0
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
StackView {
anchors.fill: parent
id: sv
initialItem: Button {
id: b
onClicked: sv.push(b1)
text: "0"
}
}
Button {
id: b1
parent: null
onClicked: sv.push(b2)
text: "1"
x: 100
onParentChanged: console.log('parent', parent, 1)
onVisibleChanged: console.log('visible', visible, 1)
}
Button {
id: b2
parent: null
onClicked: sv.push(b3)
text: "2"
x: 200
onParentChanged: console.log('parent', parent, 2)
onVisibleChanged: console.log('visible', visible, 2)
}
Button {
id: b3
parent: null
onClicked: sv.pop()
text: "3"
x: 300
onParentChanged: console.log('parent', parent, 3)
onVisibleChanged: console.log('visible', visible, 3)
}
Button {
id: back
onClicked: sv.pop()
text: 'pop'
Binding {
target: back.background
property: 'color'
value: 'orange'
}
}
Button {
id: clear
x: 150
onClicked: sv.clear()
text: 'clear'
Binding {
target: clear.background
property: 'color'
value: 'orange'
}
}
}
In QtQuick.Controls 2.x the will be reparented to null when you pop() them, effectively hiding them.
In QtQuick.Controls 1.x they will be reparented to some ContentItem but their visible property will be set to false, hiding them aswell.
To test it, just change line 2 to import QtQuick.Controls 1.4
Remember: pop() will leave the item with index 0 on the stack. To remove that, call clear()
Here is the code of the window I wanna be opened in file PopUpFreeCoins.qml:
import QtQuick 2.0
import QtQuick.Controls 2.1
Item {
property int t
property int c
ListModel{
id:ff
ListElement {
name: "ByFollow"
s: "Images/follow.png"
}
ListElement {
name: "ByLike"
s: "Images/care.png"
}
ListElement {
name: "ByComment"
s: "Images/chat.png"
}
}
ListView{
width:t-t/10
height: c/5
layoutDirection:Qt.LeftToRight
orientation: ListView.Horizontal
model: ff
spacing:50
delegate: Button{
contentItem: Image{
source: s
}}
}
}
property t is set equal to window width in main file and property c is set to window height. This is code of my Button.qml:
Button{//Below Right
width:profilePicture.width/2
height:profilePicture.width/2
x:profilePicture.x+profilePicture.width
y:profilePicture.y+profilePicture.height
contentItem: Image {
source: "Images/freecoins.png"
anchors.fill: parent
}
onClicked: PopUp{height:100;width:300;PopUpFreeCoins{t:a;c:b;}}
}
property a is window width and b is window height.
this line onClicked: PopUp{height:100;width:300;PopUpFreeCoins{t:a;c:b;}} has an error I don't know how to handle!
Here is the error:
Cannot assign object type PopUpFreeCoins_QMLTYPE_0 with no default
method
You need to create the Object somehow. You have multiple ways for dynamically create Objects. One way is to use Component.createObject(parent) which requires you to have a Component instantiated in your file.
Here you can also pass a Object ({property0 : value, property1:value ... }) as second argument, to set the properties of the Component to be instantiated. You should not set the parent to null as it might happen, that the JS-garbage collector is too aggressive once again.
Alternatively you can use the Loader to load it from either a source (QML-file) or sourceComponent. Here you won't have problems with the garbage collector.
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
width: 1024
height: 800
visible: true
Button {
text: 'create'
onClicked: test.createObject(this)
}
Button {
x: 200
text: 'load'
onClicked: loader.active = !loader.active
}
Loader {
id: loader
source: 'TestObj.qml'
active: false
}
Component {
id: test
TestObj {}
}
}
TestObj.qml includes the Window to be opened.
Alternatively you can have the Window created from the beginning, and just change the visible to true or false.