QtQuick - FolderListModel not showing all the files - qt

I am facing troubles using FolderListModel. I am trying to filter only XML files of a specific directory and display them in a ListView. The problem is, it only displays one file whereas I have several XML files in this directory.
I tried with other types of files (txt, pdf) and it never displays the correct amount of files in the ListView.
Here is my code, what am I doing wrong?
ListView {
id: listView1
x: 0
width: 288
height: 256
anchors.top: parent.top
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
delegate: listviewdelegate
model: listviewmodel
clip: true;
}
FolderListModel{
id:listviewmodel
nameFilters: ["*.xml"]
showDirs: false
showDotAndDotDot: false
folder:"C:/Users/bg/Documents"//serializationpath
}
Component{
id:listviewdelegate
Text {
text: fileName
color: m_colorDefault
font.pixelSize: m_iFontSizeMin
anchors.verticalCenter: parent.verticalCenter
}
}
Can't we use a FolderListModel inside a ListView?
Thanks for your help,
Regards
Edit:
As I am trying to solve my issue, I have noticed that the Qt documentation
isn't correct for the folder property. It says it is an invalid URL by default, but if I don't set the folder, it uses the application's folder.
I tried to set the folder property with absolute path:
FolderListModel {
id: listviewmodel
folder: "F:/QtDev/Sources.ScenarioEditor"
}
But it keeps using the application's folder, without yelling about a wrong path. So I am a bit confused here...
Edit 2:
I finally succeeded in targeting the right folder, but now I am facing a stupide behavior of the nameFilters property...
Here is a snippet:
FolderListModel {
id: listviewmodel
showDirs: false
//works fine and filters XML
// folder:"file:/F:/QtDev/Sources.ScenarioEditor"
// nameFilters: ["*.xml"]
//works fine but doesn't filter XML
folder:"file:/"+scenario.serializationPath
nameFilters: ["*.xml"]
}
The scenario.serializationPath targets my user folder, which is the one I truly need to use. But in that case, the file filtering doesn't not work :/
Any help will be much appreciated, as I am stuck on this problem for a while.
Regards

I stumbled across a similar issue while trying to use a FolderListModel with a dynamic folder name and nameFilter. I was trying to update the folder and/or filter, then refresh a view that is attached to the model using Component.onCompleted. Populating the model seems to be an asynchronous operation and the data isn't ready by the Component.onCompleted call, so as a workaround I triggered the view update on the FolderListModel count value:
property int totalFileCount: folderListModel.count
onTotalFileCountChanged: {
console.log("total files: " + totalFileCount);
// **** Refresh your view here ****
}
FolderListModel {
id: folderListModel
folder: "" // This gets updated by another function
nameFilters: [ "*.png" ]
}

Related

Open a pdf file from local directory on button Click in QML

Image {
id: user_guide_over
source: "qrc:/images/loginPage/user_guide_over.png"
x: ((parent.width/rootItemWidth)*1004)
y: ((parent.height/rootItemHeight)*646)
opacity: 1
visible: false
width: ((bgRect.width/rootItemWidth)*sourceSize.width)
height: ((bg.height/rootItemHeight)*sourceSize.height) }
The above is a image button that I have created. Now I have my PDF file inside my images folder and what to open it in read mode. I tried the following approach. When the above button is clicked, I get a pop up "You'll need a new app to open this qrc link". What is the Alternative approach to this, to open the pdf file in default pdf reader in any system.
MouseArea {
anchors.fill: user_guide
onClicked: {
Qt.openUrlExternally("qrc:images/ug.pdf");
}
Looks like you're missing the / in openUrlExternally link.
It's worth using js function or C++ to verify the file actually exists so this works as you intend

Sharing data across QML files (properties)

I am writing an App and I already managed to resolve some issues, with the latest one being the Screen.Width/Height for adjusting the window size dynamically on different monitors (I use laptop, phone, PC, it's simply convenient).
To write the code efficiently and nicely, I want to obtain that specific information and put it into a single set of 2 "variables", that would then hold this information.
I tried assigning the ApplicationWindow object an id: mainWindow, in order to call upon it from a different QML file, to obtain the property value as:
mainWindow.height, mainWindow.width
I then was told to use another approach, custom QML properties, that are declared like:
property (type) (name): (value)
I then followed the advice and declared those properties in Main.qml (with AppWindow) and it does work. The properties of AppWindow (ApplicationWindow) contain the width and height of the Screen multiplied by a specific coefficient.
Then those variables are accessed by the object itself, drawing the App Window as I want it to be.
The problem is that this approach was meant to solve the issue of sharing code across .QML files, and it doesn't
[go down]
ApplicationWindow {
id: mainWindow
//Wide screen support
//Screen.desktopAvailableWidth / 4
//Screen.desktopAvailableHeight / 6
//The below is monitor cross-compatible (phone, PC, laptop)
property int globalWidth: Screen.width / 2
property int globalHeight: Screen.height / 3
width: globalWidth
height: globalHeight
visible: true
title: qsTr("Redacted")
//setWindowIcon(QIcon(":/path/to/icon.png"));
The piece of code below resides in main.qml. It is called upon from that file. Just ignoring the IDs (IDs supposedly [as stated by users/docs] can't be accessed outside of local scope...), the properties (especially custom properties) should be accessible inside Page1, Page2, Page3 etc.
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Page1Form {
}
Page2Form {
}
Page3Form {
}
}
The below is the Page2Form.qml file that is called upon (as class definition) in main.qml.
The properties declared in parent objects in main.qml (imo) should be inherited by child objects (imo).
Page {
id: localPage2
width: globalWidth
height: globalHeight
Rectangle {
id: rectangle
x: (localPage2.width / 2) - (width / 2)
y: (localPage2.height / 4) - (height / 2)
width: localPage2.width / 3
height: localPage2.height / 6
color: "#ffffff"
border.color: "#a45c5c"
border.width: 2
TextInput {
id: textInput
x: 0
y: 0
width: localPage2.width / 3
height: localPage2.height / 6
text: qsTr("Redacted")
font.pixelSize: 12
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.weight: Font.Normal
focus: true
}
}
Ok, so what is the problem?
I can try calling those properties as:
mainWindow.globalHeight
globalHeight
mainWindow.height
etc.
They won't be accessed. The form editor will provide me preview of Page object that has 0 size.
The page does render eventually (when compiled and ran), but there is an issue in passing (accessing) the value of that property.
As you can notice, both IDs and custom properties seem to work just fine locally.
Update:
I haven't fixed that issue, I also tried using aliases (references) and the "foreign" QML file will still fail to be assigned proper size (Page width and height).
I then put another custom property of string type with some text in it, I then managed to access that property in Page2.qml and the property is originally in main.qml.
It's bugged, or I have no idea what it is.
I tried 3 approaches:
ID (it's not global as it turns out)
Custom property (kind of works, just not with Screen size...)
Aliases on object's default properties
(property alias globalWidth: mainWindow.width
property alias globalHeight: mainWindow.height)

What are these glitches in my listview when scrolling?

I'm writing a file conversion software in QT for Python where you will be able to drag files into the software, click a convert button, and drag out the output files. When a user drags files into the software, all the names of the files are added into a ListView.
When a user drags files into the ListView, it calls the backend.addToPaths(url) function with each of the file paths that were dragged into it. This function then appends all of the file paths into an internal list of file paths, then updates the listview, calling the updateList (paths) function in the main.qml file with all of the file names, which clears the listview and then appends back all of the file names, the old ones, and the new ones dragged in.
All of the file names are added to the list view correctly, but then when I scroll around inside of the list view, it produces these very strange rendering bugs, as shown in this video, or in these images:
Image 1:
Image 2:
Image 3:
At first I thought it could be due to clipping, so I removed that, and nothing changed. I then tried increasing the listview's display margin, and then its cacheBuffer, but it still didn't help. I also tried setting pixelAligned to true, but that still didn't work. I'm guessing it's probably because QT isn't very good at handling listmodels being updated or changed, but I don't really know.
Here's a simplified version of my main.qml file if needed:
ListView {
id: inputFileView
// #disable-check M16
objectName: "inputFileView"
clip: true
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
displayMarginBeginning: 100
displayMarginEnd: 100
function updateList(paths) {
console.log("updating list");
inputFileModel.clear();
paths.forEach( function (item) {
inputFileModel.append({
'name': item
});
});
}
model: ListModel {
id: inputFileModel
}
delegate: Item {
Row {
id: row1
Text {
text: name
}
}
}
DropArea {
anchors.fill: parent
onDropped: {
drop.urls.forEach( function (url) {
backend.addToPaths(url)
});
}
}
}
I guess it was a bug with PySide2? I noticed someone replaced the Pyside tag with the PySide2 tag, and I didn't even show the python code that would've clarified that I was using that version, so I wondered if it meant that the issue was only in PySide2, so I switched from that to PySide6, and it worked. I have no idea what was causing it, but I guess it's fine now.

QML StackView push component with properties

In QML StackView docs it is mentioned that you can push item with properties like this:
stackView.push({item: someItem, properties: {fgcolor: "red", bgcolor: "blue"}})
Is there a way with which we can push component with properties? My components are basically wrappers of other .qml files for different views of my app, for example:
Component{
id: loginComponent
Login{}//The Login.qml file of my project
}
This is what I'm trying:
Main.qml
ApplicationWindow {
id: appWindow
visible: true
width: Screen.desktopAvailableWidth
height: Screen.desktopAvailableHeight
property alias stackv: stackv
property alias loginComponent: loginCom
StackView {
id: stackv
anchors.top: topHeader.bottom
anchors.topMargin: 10
anchors.bottom: parent.bottom
width: parent.width
focus: true
Component {
id: loginCom
Login {
anchors.fill: parent
}
}
}
}
In another QML file, which got pushed as a component to the stackview, I'm trying this on one of the button's onClick method:
onClicked: {
appWindow.stackv.push({item: appWindow.loginComponent})
}
I get popped with this error:
QML StackView: push: nothing to push
If I try this without the item property, it works. However, either way, I can't push properties.
In the documentation you linked to, the first sentence says:
An item pushed onto the StackView can be either an Item, a URL, a string containing a URL, or a Component.
So just pass a component:
stackView.push({item: loginComponent, properties: {/*...*/}})
EDIT: It turns out, after you have edited the question and added a warning output, that you are actually using StackView from Qt Quick Controls 2, not from Qt Quick Controls 1 where your documentation link points to.
QML StackView::push() (Qt Quick Controls 2)
stackView.push(loginComponent, {/*...*/})

Recursevly go trough delegated maps in FolderListModel (QML)

I'm creating a music player for Ubuntu Touch in QML and I have some things I would appreciate some help with since I'm new to QML.
The app are able to play tracks listed in the selected directory, but the directory also shows folders, and I want all the files from all the subdirs to be listed, instead of only the tracks in the root dir.
But I don't really know how to do this. FolderListModel har a isFolder method that perhaps could be used, but I don't know how. Or use some kind of function to go trough the selected dirctory.
I came by this thread qml FolderListModel but it didn't give me anything.
This is the code that currently lists my tracks:
Column {
anchors.centerIn: parent
anchors.fill: parent
ListView {
id: musicFolder
FolderListModel {
id: folderModel
folder: musicDir
nameFilters: ["*.ogg","*.mp3","*.oga","*.wav"]
}
width: parent.width
height: parent.height
model: folderModel
delegate: ListItem.Subtitled {
text: fileName
subText: "Artist: "
onClicked: {
console.debug('Debug: User pressed '+musicDir+fileName)
playMusic.source = musicDir+fileName
playMusic.play()
}
}
}
}
You'll need a proxy model which flattens the nested items recursively. One example of such a proxy model is the KDescendantsProxyModel (I'm also using it).
Alternatively, you could build a list of files matching a particular pattern via recursively walking the filesystem (or letting some existing class do this for you) and feeding the result to some other, simpler model. That would have a disadvantage of not being able to display updates easily.

Resources