Reading n random files from a folder in Qt Quick - qml

I'm writing my first Qt Quick application and I'm having lots of trouble doing things that are simple in other environments. I want to display n random images from a folder. For this purpose I'm using FolderListModel, but the trouble is that I don't see any methods to access list of files directly. So here's my hackish approach:
Use FolderListModel to read files
Use Text component as delegate
onTextChanged of Text component gets the filename (this part works) and adds it to some ListModel
randomize the ListModel and then use it to display files
I have many problems and questions, but first of all, what is the sane way to do this (please make it so that the list part doesn't have to be written in c++)?
There are 2 problems for now - I can't figure out how to access the ListModel from Text component; and I can' t figure out how to make the ListModel public/accessible from another component that will display the images.
Below is the code:
import QtQuick 1.0
import Qt.labs.folderlistmodel 1.0
ListView {
width: 200; height: 300
FolderListModel {
folder: "file:///C:/somefolder"
id: folderModel
nameFilters: ["*.jpg"]
}
Component {
id: fileDelegate
Text { id: intext
text: fileName
//the next line fails, Can't find variable: anotherModel
onTextChanged: anotherModel.append([{name: intext.text}]
)
}
}
model: folderModel
delegate: fileDelegate
ListModel {
id: anotherModel
}
}

Your code almost works for me. I get the error "QML ListModel: append: value is not an object". This is because you append arrays.
If you remove the brackets in line
anotherModel.append([{name: intext.text}])
it works. To make anotherModel a public property write it as
property ListModel anotherModel: ListModel {}

Related

How to assign a context-variable to a property with the same name in QML?

This is the result of the following code:
main.qml
import QtQuick 2.8
Item {
Reusable {
index: 1234 // reusable with a custom index
}
ListView {
anchors { fill: parent; margins: 20; topMargin: 50 }
model: 3
// Reusable with an index given by the ListView
delegate: Reusable {
index: index // <- does not work, both 'index' point to
// the index property
}
}
}
Reusable.qml
import QtQuick 2.8
Text {
property int index
text: "Line " + index
}
 Problem description:
The ListView assigns 0, 1, 2, etc. to the variable index on every iteration. However, because I am assigning this to a property, this variable is shadowed and I cannot access it.
If I remove property int index from Reusable.qml, the ListView works, but using Reusable outside of the ListView does not work anymore.
Is there a way to assign index: index?
(I could rename the property which would work, but I would like to avoid that.)
You can address the model related data through a model prefix.
ListView {
model: 3
delegate: Reusable { index: model.index }
}
My recommendation would to do that even if there is no ambiguity, as means to readability. I.e. a developer reading the code can immediately see which data is a local property and which data is provided by the model.

How to get JS eval() to operate in the parent scope of a QML element

If I have some JS code as text and I call it in eval(), I can then use the functions defined by this statement only in the scope of where the eval() occurred. As far as I can tell, this means that any new JS definitions created from the eval are invisible to the rest of QML. Consider this QML signal handler:
Item {
id: testitem
onThesourceChanged: {
eval(thesource)
testfunction()
}
}
The testfunction() was defined in the text “thesource” and does indeed work in the signal handler above, printing out some test text; but it is not in the scope of the QML element and therefore cannot be called ever again, as far as I can see. I’ve tried various ideas like putting the eval() in a function, or inside Component.onCompleted, etc, but I can’t seem to figure out how to get anything created by the eval() to be recognized as part of the parent QML element.
For example I want to be able to call testitem.testfunction() — but it is not defined outside the scope of this handler.
You need to declare the variable in the scope where you want to access it later. Use eval() to initialize it in a child-scope:
import QtQuick 2.1
Rectangle {
width: 360
height: 360
MouseArea {
anchors.fill: parent
onClicked: {
testitem.thesource = "myfunction = function(text) { return text.toLowerCase() }"
}
}
Text {
id: testitem
property var myfunction: function(text) { return text.toUpperCase() }
property var thesource;
anchors.centerIn: parent
text: myfunction("Kullo – Secure Messaging")
onThesourceChanged: {
eval(thesource);
text = myfunction("Kullo – Secure Messaging")
}
}
}

Dynamically set Label's "id" property

I'm developing an application for SailfishOS using the QML language.
I want to dynamically set the id property of a Label by using an if condition.
This is my code:
Label {
id: {
if(myBool == false) {
thisText()
} else {
notThatText()
}
}
width: parent.width
horizontalAlignment: Text.AlignRight
text: ""
font.pixelSize: Theme.fontSizeLarge
}
This code is placed into my CoverPage.qml file, the one that display things on the application's cover while in background.
By doing this, the cover is simply black, nothing is displayed.
Is it possible in QML to do this?
Thanks in advance!
The Qt doc says this.
While it may look like an ordinary property, the id attribute is not an ordinary property attribute, and special semantics apply to it;
You cannot set the id of a QML component at runtime.(Correct me if I am wrong). You might find objectName property useful. But I don't understand why you are trying to assign dynamic id.
I have a use case where use a dynamic/specific id could be useful. The id could be view with Gammaray, it can help for debugging.
GridLayout {
id: layout
Repeater {
model: foo
Bar {
id: bar_X_Y // bar_{model.row}_{model.column}
}
}
}
But as far as I know, it's not possible.

dynamically change the model used as base for a qml item

Im starting to work with qtquick 1.1. And i have designed a component consisting mainly out of a pathview.
Rectangle {
id: pathViewElement
PathView {
id: pathView
pathItemCount: 4
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
highlightRangeMode: PathView.StrictlyEnforceRange
model: myModel
delegate: Item {
width: valueText.width
height: 50
scale: 1.0-2*Math.abs(pathViewElement.width/2-(x+width/2)) / pathViewElement.width
opacity: scale
smooth: true
Text {
id: valueText
anchors.centerIn: parent
text: myModel.value
font.pointSize: 35
}
}
path: Path {
startX: 0; startY: 25
PathLine { x: pathViewElement.width; y: 25;}
}
}
}
This PathView is using a model called myModel. Which might be located in any other file.
The question now is the following:
I'm using the same component to be able to change different values. Each of these values is coming with another QML ListModel.
So how can i dynamically change the model used in the PathView (myModel)?
Also, while creating the PathView i can statically set the model using
model: MyListModel{}
where MyListModel is a qmlFile consisting only of a ListModel {} declaration. But when i dynamically create the PathView from within a third file, say MyApplication.qml I cannot set pathViewElement.model: MyListModel{} as the compiler is expecting a ";" instead of {}. Why is this?
So how can i dynamically change the model used in the PathView
(myModel)?
On the occurrence of respective event, you can directly change the model assigned for your view.
eg. Assuming you want this change to be done on click of some mouse button:
onClicked:
{
pathView.model = myNewModel
}
Here, myNewModel is the id for your new model to replace with.
But when i dynamically create the PathView from within a third file,
say MyApplication.qml I cannot set pathViewElement.model:
MyListModel{} as the compiler is expecting a ";" instead of {}. Why is
this?
Can you state this part more clearly ?

QML application launcher similar to iOS

I'm trying to write an application launcher using QtQuick\QML, and I'd like the user experience to be similar to iOS, in terms of having a grid of icons that can be rearranged with icons that "move out of the way" via animated transitions and a "snap to grid" effect if the icon is dropped in an intermediate position. I've tried using GridView and the drag properties, but I can't seem to get the layout do what I want. What would be the best way to implement this type of app using QML? I'm fairly new to QtQuick, and I feel like maybe I'm missing something fundamental that would make this fairly easy\obvious to write.
For putting icons in a grid, you can use the grid view:
http://developer.qt.nokia.com/doc/qt-4.8/qml-gridview.html
Go through the Qt Quick documentation, you will find out how to do this.
This is not directly relevant to implementing the grid of icons, but I recently came across the QML component Loader. This lets you load QML components on demand, and could be useful for the code that launches an app after the icon is selected.
http://doc-snapshot.qt-project.org/5.0/qml-qtquick2-loader.html
I have made Nokia N9 launched look and feel (Maemo 6, or also known as MeeGo).
It is similar, I just scroll from up to down with icons, while you change "pages" from left to right (and vice versa).
I don't know is it best way, but this is how I did icon manager (its shrinked, this is only to give you idea - in reality it is considerably larger):
Item
{
id: root
function getChildAt(x, y) {}
function getIndexOfChild(child) {}
function moveChild(child, x, y)
{
//moving around icons
}
function setIndexToChild(child)
{
//index of child in Grid element (where to drop)
}
Flickable
{
id: scroller
clip: true
//you most likely want HorizontalFlick ("paging" effect you can add on onBeginingXChanged)
flickableDirection: Flickable.VerticalFlick
contentHeight: iconTable.height
contentWidth: iconTable.width
Grid
{
id: iconTable
width: root.width
anchors.top: parent.top
flow: Grid.LeftToRight
spacing: 10
add: Transition
{
NumberAnimation
{
properties: "x,y"
//make desired transition
}
}
move: Transition
{
NumberAnimation
{
properties: "x,y"
//make desired transition
}
}
}
}
}
You could also write down your own implementation of manager in C++ and later on use it in QML.
This is how it looks like:
I created something distantly connected to this recently, the idea is: create a ListView with snapping. Its delegate should contain a GridView. Separate all of the apps into n-element chunks. Then (it's only the idea)
ListModel
{
ListElement { apps: [app1, app2, ..., appn] }
ListElement { apps: [app1, app2, ..., appn] }
....
ListElement { apps: [app1, app2, ..., appk] }
}
Then populate the ListView with this model and the GridView with the apps property.
I don't know whether you can provide drag and drop here, though