Why does my custom TabBar lose it's content children in this example? - qml

I am trying to create a TabBar has preview images of the connected layout's children. However after adding several tabs (the exact number depends on the number of elements within the tabs) QML throws an error and the PreviewTabBar loses all its content children.
The following is a minimal working example:
My main.qml:
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
StackLayout {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
}
Timer {
interval: 50; running: true; repeat: true
onTriggered: addTab()
}
function addTab() {
console.log("add Tab")
var component = Qt.createComponent("qrc:/TabContent.qml")
if(component.status !== Component.Ready)
console.log("component not ready")
var item = component.createObject(swipeView)
tabBar.addTab(item)
tabBar.currentIndex = tabBar.contentChildren.length - 1
console.log("current index " + tabBar.currentIndex)
}
header: PreviewTabBar {
id: tabBar
currentIndex: swipeView.currentIndex
}
}
The PreviewTabBar.qml containing previews of the content:
import QtQuick 2.8
import QtQuick.Controls 2.1
TabBar {
signal closeCurrentTab
clip: true
background: Rectangle {
color: "white"
}
function addTab(imageSource) {
var component = Qt.createComponent("PreviewTabButton.qml")
if(component.status !== Component.Ready)
console.log("component not ready")
else {
var item = component.createObject()
item.setSource(imageSource)
addItem(item)
}
}
function closeTab() {
console.log("closeTab")
closeCurrentTab()
}
}
and last but not least the PreviewButton.qml using a ShaderEffectSource to render the preview:
import QtQuick 2.8
import QtQuick.Controls 2.1
TabButton {
height: 80
width: 140
function setSource(source) {
preview.sourceItem = source
}
contentItem: ShaderEffectSource {
id: preview
}
}
This example gets to about 80 tabs on my machine, after that the PreviewTabBar loses all its children (not so the StackLayout). However in the real life example with more complicated tab contents I only get up to around 8 tabs. What could I be doing wrong?
Here is the relevant part of the application output:
qml: current index 99
qml: add Tab
file:///usr/lib/qt/qml/QtQuick/Controls.2/TabButton.qml:65: TypeError: Cannot read property of null
qml: current index 100
qml: add Tab
qml: current index 1
I tried finishing the dynamic component creation in a callback as described here:
http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html#creating-a-component-dynamically
however that brough no improvement.
Here is a link to the example project:
https://www.file-upload.net/download-12341284/tabtestshader.zip.html

The most probable cause is line 17 in PreviewTabBar.qml which reads:
var item = component.createObject()
As you have no parent set in the createObject()-function the GarbageCollector tends to run wild, and delete your object, even if it is still referenced.
Though not documented that way, you should always pass a parent object, to make sure it survives the GC.
A more stable way would be to generate the Tabs from a model, and add the according model entries in the addTab-functions.
As a little remark on the side: You create a new component everytime you call one of your addTab-functions. Why don't you declare it once like
Component {
id: myComp1
...
}
and create the objects from that?

Related

Qt Quick Controls 2 TextArea `tabChangesFocus`, how to use Tab key to change focus, not type Tab character

QML TextArea from Qt Quick Controls 1.x (http://doc.qt.io/qt-5/qml-qtquick-controls-textarea.html) had a property called tabChangesFocus, which could be set to toggle the behaviour of the Tab key between two possible actions:
true: enter Tab character in the TextArea
false: move the focus to next item in the tab Chain
This property doesn't seem to exist for TextArea in Quick Controls 2.x (https://doc.qt.io/qt-5/qml-qtquick-controls2-textarea.html).
The default is the true behaviour, but I would like the false behaviour (focus change).
Does anyone know a simple way to achieve the same effect for Quick Controls 2?
Another way is to use Item::nextItemInFocusChain(). This way, you don't need to know the next item in focus chain:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: window
width: 300
height: 300
visible: true
Column {
spacing: 20
TextArea {
id: textArea1
focus: true
text: "TextArea1"
Keys.onTabPressed: nextItemInFocusChain().forceActiveFocus(Qt.TabFocusReason)
}
TextArea {
id: textArea2
text: "TextArea2"
objectName: text
Keys.onTabPressed: nextItemInFocusChain().forceActiveFocus(Qt.TabFocusReason)
}
}
}
This should probably be made more convenient in the future, but you can setup tab navigation with QML KeyNavigation:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: window
width: 300
height: 300
visible: true
Column {
spacing: 20
TextArea {
id: textArea1
focus: true
text: "TextArea1"
KeyNavigation.tab: textArea2
KeyNavigation.backtab: textArea2
KeyNavigation.priority: KeyNavigation.BeforeItem
}
TextArea {
id: textArea2
text: "TextArea2"
KeyNavigation.tab: textArea1
KeyNavigation.backtab: textArea1
KeyNavigation.priority: KeyNavigation.BeforeItem
}
}
}

How Can I Scroll the Images In QML Automatically?

I have a ListView Containing only Images. I assigned the orientation of ListView as horizontal Direction. How can I change, i.e. scroll, the images automatically with some time gap?
Use a Timer. When it is triggered, update the currentIndex of the ListView. This will scroll automatically with default animations. Finally, according to the documentation, positionViewAtIndex is
The correct way to bring an item into view is with positionViewAtIndex
Indeed the method provides a more fine-grained control over the appearance of Items via the PositionMode parameter. See the documentation for further details.
Minimal example:
import QtQuick 2.5
import QtQuick.Window 2.0
Window {
visible: true
width: 200
height: 15
ListView {
id: list
anchors.fill: parent
orientation: ListView.Horizontal
model: 10
delegate: Text {
width: 40
id: name
text: index
}
}
Timer {
interval: 500
repeat: true
running: true
onTriggered: {
//list.currentIndex += 1 // this...
//list.incrementCurrentIndex() // ...or this!
//list.positionViewAtIndex(list.currentIndex, ListView.Center)
}
}
}

How are implicit dimensions of QtQuick items propagated?

I am trying to implement a component which should by default (if no width was explicitly set) take up as much space as it needs (i.e. depending on its implicitWidth). And if width was set at definition it should shrink its contents to fit in the provided area.
Here's an example:
import QtQuick 2.2
import QtQuick.Window 2.0
Window {
width: 200
height: 100
visible: true
property bool restricted: false
Component {
id: external
FocusScope {
implicitWidth: column.implicitWidth
implicitHeight: column.implicitHeight
focus: true
Column {
id: column
width: parent.width > 0 ? parent.width : undefined
Text {
id: label
width: parent.width > 0 ? parent.width : undefined
elide: Text.ElideRight
font.pixelSize: 24
text: "1234567890"
}
}
Keys.onRightPressed: label.text += label.text
}
}
Loader {
width: restricted ? 100 : undefined
sourceComponent: external
focus: true
Keys.onReturnPressed: restricted = !restricted
}
}
In this sample two modes are controlled by auxiliary bool property, and I want it to support two forms of declaration:
Explicit width. Text should elide.
Loader {
width: 100
sourceComponent: external
focus: true
}
Loader width should be enough to fit the whole text without eliding.
Loader {
sourceComponent: external
focus: true
}
Motivation is that such a component will be defined in a separate file and is being designed to be placed in different parts of UI with both behaviors desired depending on current needs. This sample with inline component declaration is only for demonstration purpose.
UPDATE:
The following trick parent.width > 0 ? parent.width : undefined works, but only for initial setup. If component contents change and implicitWidth is updated (in an unrestricted mode) the width of the component does not change (i.e. Text remains elided).
For example, press right key just right after launching example. You should see that Text has become elided, but its width did not increased
twice regardless the fact that string was duplicated.

Qml - ReferenceError: Screen is not defined

Trying to build a little fotball game as an project in school but I'm having some issues. So when I run the code it says that ReferenceError: Screen is not defined, but accordign to me I have defined it.
This code is just a prototype, going to change the keys to buttons later on so that it can actually work on a phone.
import QtQuick 2.0
Item {
id:root
width:Screen.width
height:Screen.height-10
focus:true
Keys.onPressed: {
if(event.key===Qt.Key_Up)
{
event.accepted = true;
player.y=(player.y) - 40
}
if(event.Key === Qt.Key_Down){
event.accepted = true;
player.y = (player.y)+ 40
}
if (event.key === Qt.Key_Right)
{ event.accepted=true;
player.x=(player.x)-40
}
if (event.key === Qt.Key_Left)
{event.accepted = true;
player.x=(player.x) +40
}
}
Flickable {
width:Screen.width
height:Screen.height
contentHeight: Screen.height*4
contentWidth:Screen.width
interactive:true
boundsBehavior: Flickable.StopAtBounds
Image{
id: feild
anchors.fill:parent
source:"Namnlös.png"
sourceSize.height:Screen.height*4
sourceSize.width:Screen.width
}
Image {
id: player
source:"asd.png"
x:Screen.width/2
y:Screen.height/2
}
}
}
So if you run this code you'll only get the player showing up, and then disapear instantly, the field is not shown.
You lack the Screen import.
import QtQuick.Window 2.1
Screen docs
Resizing items to screen is abnormal, you should simply use
resizeMode property
and anchor all child items inside root item.

qml viewer loading new window

I test the following code posted at 1
The qml viewer cannot open the new window and its progress is always 0.1 , what is the problem?
import QtQuick 1.0
import QtWebKit 1.0
Grid {
columns: 3
id: pages
height: 300; width: 600
Component {
id: webViewPage
WebView {
id: webView
height: 300; width: 600
newWindowComponent: webViewPage
newWindowParent: pages
url: "newwindows.html"
onLoadStarted: console.log("Started"+url)
onLoadFinished: console.log("Finished"+url)
onLoadFailed: console.log("Failed")
onProgressChanged: console.log(progress)
onUrlChanged: console.log("Changed"+progress+url)
}
}
Loader { sourceComponent: webViewPage }
}
Worth trying to actually create a new window using the Window element to see if you have any luck. I'd expect the window to launch whether or not the data is coming through. See here:
https://www.qt.io/blog/2011/08/26/toplevel-windows-and-menus-with-qt-quick