Delegate FolderListModel in TableView - qt

I'm learning Qt Quick to make a file manager, but I have no experience in QML or GUI in general. The first step is to list the content of a folder, using FolderListModel. I got the example code working using ListView, but naturally I want to display multiple fields in addition to the name, e.g. size, time, and so on. Thus, I'm thinking of using TableView.
However, it's not clear to me how to delegate each entry as a row in TableView. Currently I'm simply using itemDelegate to display fileName, and the resultant is that in each row, all the columns repeat the name of the entry. So I think rowDelegate is the correct way, but how do I make a proper delegate Component for that purpose? Conceptually I'd like to specify an array of fields, e.g. [model.fileName, model.fileSize] corresponding to the table columns. Is this achievable?
For clarify I'm posting the code below:
import QtQuick 2.4
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import Qt.labs.folderlistmodel 2.1
ApplicationWindow {
visible: true
width: 900
height: 600
title: qsTr("Hello World")
Item {
anchors.fill: parent
width: 900
height: 600
SplitView {
id: splitView1
anchors.fill: parent
TabView {
id: tabView1
width: splitView1.width / 2
Tab {
title: qsTr("Home")
TableView {
id: tableView1
width: splitView1.width / 2
TableViewColumn {
role: "name"
title: qsTr("Name")
width: tableView1.width * 0.75
}
TableViewColumn {
role: "size"
title: qsTr("Size")
width: tableView1.width * 0.25
}
FolderListModel {
id: folderModel2
folder: "file:/home/username"
nameFilters: ["*"]
showHidden: true
}
Component {
id: fileDelegate2
Text {
text: model.fileName
}
}
model: folderModel2
itemDelegate: fileDelegate2
}
}
}
}
}
}

The documentation mentions that the following roles are available:
List item
fileName
filePath
fileURL (since Qt 5.2)
fileBaseName
fileSuffix
fileSize
fileModified
fileAccessed
fileIsDir
So you don't need to have custom delegates to display that information, just set the role property of TableViewColumn appropriately:
import QtQuick 2.4
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import Qt.labs.folderlistmodel 2.1
ApplicationWindow {
visible: true
width: 900
height: 600
title: qsTr("Hello World")
Item {
anchors.fill: parent
width: 900
height: 600
SplitView {
id: splitView1
anchors.fill: parent
TabView {
id: tabView1
width: splitView1.width / 2
Tab {
title: qsTr("Home")
TableView {
id: tableView1
width: splitView1.width / 2
TableViewColumn {
role: "fileName"
title: qsTr("Name")
width: tableView1.width * 0.75
}
TableViewColumn {
role: "fileSize"
title: qsTr("Size")
width: tableView1.width * 0.25
}
FolderListModel {
id: folderModel2
folder: "file:/home/username"
nameFilters: ["*"]
showHidden: true
}
model: folderModel2
}
}
}
}
}
}

Related

QML scope: Invalid alias reference

I get the following error: qrc:/main.qml:17 Invalid alias reference. Unable to find id "button2". The error can be reproduced by the following qml file:
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Window 2.0
import QtQuick.Layouts 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
id: root
property alias myprop: button2
SplitView {
id: splitView
orientation: Qt.Vertical
SplitView {
id: splitView1
orientation: Qt.Horizontal
TabView {
Tab{
title: "Tab1"
}
Tab{
title: "Tab2"
ColumnLayout {
GridLayout {
Button {
id: button2
text: qsTr("test button")
}
}
}
}
}
}
}
}
}
It seems I have a misunderstanding about qml scope. I thought the parent can access the ids of all of its children?

How to set an item property of one qml from main.qml

I waste my time to find how set the visible property to false, the delegate being in an another qml file.
For instance here is a simple example based on Places Map.
Marker.qml
import QtQuick 2.0
import QtLocation 5.6
MapQuickItem {
id: idPointsMarker
sourceItem: Loader{sourceComponent: idRect}
visible: true //if set manually to false, everything works correctly
Component{
id: idRect
Rectangle{
width: 20
height: 20
color: "blue"
}
}
}
and the main.qml
import QtQuick 2.0
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6
Window {
width: 512
height: 512
visible: true
PositionSource {
...
}
property variant locationOslo: QtPositioning.coordinate( 59.93, 10.76)
PlaceSearchModel {
...
}
Map {
id: map
anchors.fill: parent
plugin: Plugin {name: "osm"}
center: locationOslo
zoomLevel: 13
MouseArea {
id : mouseMap
anchors.fill: parent
onDoubleClicked: {
console.log("DoubleClicked")
Marker.idPointsMarker.visible = false // pb is here
}
}
MapItemView {
model: searchModel
delegate: Marker{
coordinate: place.location.coordinate
}
}
}
}
I wish to toggle the visibility to false on doubleclick. I am not able to access the property anyhow the way i write it. What is the correct syntax?
Sorry for a so simple question. Thanks for help.
You do not have to set the property in main.qml, you must do it in Marker.qml, since the elements of Marker.qml can access all the elements of main.qml. One solution is to establish a property of type bool that manages the visibility and that changes in the double click:
main.qml
Map {
[...]
property bool isVisibleItems: true
MouseArea {
id : mouseMap
anchors.fill: parent
onDoubleClicked: map.isVisibleItems = !map.isVisibleItems
}
[...]
Marker.qml
import QtQuick 2.0
import QtLocation 5.6
MapQuickItem {
id: idPointsMarker
sourceItem: Loader{sourceComponent: idRect}
visible: map.isVisibleItems
Component{
id: idRect
Rectangle{
width: 20
height: 20
color: "blue"
}
}
}
In the following link there is an example

Adding TabButton dynamically to TabBar in QML

I am trying to add a tabButton to TabBar dynamically on pressing a button but i have spent a lot of time searching but i am not getting how to add, below is the code which i am working on :
MyTabButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
Item
{
property int BtnWidth:0
property int BtnHeight:0
property string BtnText: ""
property bool isChecked : false
TabButton
{
id:tabBtn
text:BtnText
width:BtnWidth
height:BtnHeight
}
}
MainForm.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
Rectangle
{
Button
{
id:button
width:100
height:100
anchors.top:parent.top
text:qStr("Add")
onClicked{
//How to add logic here to add tab in below tabBar.
}
}
TabBar
{
id:tabBar
anchors.top:button.bottom
width:500
height:500
}
}
Example:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
width: 360
height: 630
visible: true
header: TabBar {
id: tabBar
}
Component {
id: tabButton
TabButton { }
}
Button {
text: "Add"
anchors.centerIn: parent
onClicked: {
var tab = tabButton.createObject(tabBar, {text: "Tab " + tabBar.count})
tabBar.addItem(tab)
}
}
}
You need to have something like a Component that is a TabButton. Your file MyTabButton.qml won't result in a TabButton, but instead an Item containing a TabButton, but with this, your TabBar does not know what to do.
So your file will need to have TabButton as root element
//MyTabButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.2
TabButton
{
id: tabBtn
// customize as you like
}
Then you create a Component of this in your file where you want to use it. (e.g. main.qml)
import QtQuick 2.4
import QtQuick.Controls 2.0
ApplicationWindow {
width: 800
height: 600
visible: true
TabBar {
id: tabBar
width: 800
height: 50
}
// The component is like a factory for MyTabButtons now.
// Use myTabButton.createObject(parent, jsobject-with-property-assignments) to create instances.
Component {
id: myTabButton
MyTabButton {
/// EDIT ACCORDING TO YOUR COMMENTS ***
Connections {
target: tabBar
onCurrentIndexChanged: doSomething()
}
/// EDIT OVER
}
}
Button {
anchors.centerIn: parent
// Create a object out of the component, and add it to the container
onClicked: tabBar.addItem(myTabButton.createObject(tabBar /*, { object to set properties }*/))
}
}
TabBar inherits Container, which has addItem().
Try it in Window
Row {
anchors.fill: parent
TabBar {
id: tabBar
currentIndex: 0
width: parent.width - addButton.width
TabButton { text: "TabButton" }
}
Component {
id: tabButton
TabButton { text: "TabButton" }
}
Button {
id: addButton
text: "+"
flat: true
onClicked: {
tabBar.addItem(tabButton.createObject(tabBar))
console.log("added:", tabBar.itemAt(tabBar.count - 1))
}
}
}

ComboBox disable an item at a particular index

I have a combobox in qml in a as a TableViewColummn and I define it as follows:
import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
ListModel {
id: comboModel
ListElement {
text: ""
Index: -1
Dims: -1
}
}
TableViewColumn {
id: imageTypeList
role: "ImageType"
title: "Image Type"
width: 100
delegate: Rectangle {
ComboBox {
anchors.verticalCenter: parent.verticalCenter
anchors.margins: 2
model: comboModel
onActivated : {
console.log(comboModel.get(index).Index)
}
}
}
}
My question is that if it is possible to disable a combobox menu item given a index to the item in the ComboBox. So, I would not like to change the underlying model but actually simply disable the item and not allow the user to select it.
Is it possible to disable a ComboBox menu item ... and not allow the user to select it?
Sure, it is possible.
To do it using Quick Controls 2 you need to create ComboBox delegate this way:
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
visible: true
width: 640
height: 200
title: qsTr("Let's disable some items in ComboBox")
ComboBox {
id: control
currentIndex: 0
anchors.centerIn: parent
model: [
{ text: "Enabled item.", enabled: true },
{ text: "Supposed to be disabled. Can't click on it.", enabled: false},
{ text: "Last, but enabled item.", enabled: true}
]
width: 500
textRole: "text"
delegate: ItemDelegate {
width: control.width
text: modelData.text
font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
highlighted: ListView.isCurrentItem
enabled: modelData.enabled
}
}
}
If you are using Quick Controls 1, you should provide your own implementation of ComboBox component.

How to get parent button from ButtonStyle without using id?

I created a component (SidebarMenuButton) that is used in the main qml file multiple times. The button has styles that should be inherited by all it's 'instances'. Here is the SidebarMenuButton.qml:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Button {
width: buttonNewMessage.width
height: buttonNewMessage.height
anchors {
horizontalCenter: parent.horizontalCenter
topMargin: 5
}
style: ButtonStyle {
background: Rectangle {
color: 'transparent'
}
label: Text {
text: parent.text // undefined here
color: 'white'
font.family: 'Helvetica'
font.pixelSize: 12
font.bold: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
}
And a part of my main qml file:
import QtQuick 2.3
import QtQuick.Window 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Window {
id: main
title: 'Messenger'
width: 1024
height: 768
minimumWidth: 800
minimumHeight: 600
RowLayout {
id: layout
anchors.fill: parent
spacing: 0
Rectangle {
id: sidebar
color: '#3C3E55'
Layout.fillHeight: true
Layout.preferredWidth: 200
ButtonCompanyName {
id: buttonCompanyName
}
ButtonNewMessage {
id: buttonNewMessage
}
SidebarMenuButton {
id: buttonInbox
text: 'Inbox (1)'
anchors.top: buttonNewMessage.bottom
}
SidebarMenuButton {
id: buttonSentMessages
text: 'Sent messages'
anchors.top: buttonInbox.bottom
}
SidebarMenuButton {
id: buttonStarred
text: 'Starred'
anchors.top: buttonSentMessages.bottom
}
}
I commented the line with error. parent there doesn't refer to button so the text in all buttons is empty. I need to access parent button from there and get it's text property. The component has no id cause it's used multiple times and ids are assigned in the main qml file. So the question is: how can I get that button text without id?
There are two ways to set text in your case.
1)The Button for which you are applying the style is available as control property in ButtonStyle class. You can set the the text as text:control.text
Reference:control property(ButtonStyle)
2)You can give an id to the Button in SidebarMenuButton type and access its textproperty.
Button
{
id:button
.
.
.
text: button.text
}
You can assign an id inside your component file that would not conflict with the id you use when you instantiate the component somewhere else. I use the same value for the id of most of my QML components: container so that I can easily reference properties from the root of the item.
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Button {
id: container
style: ButtonStyle {
background: Rectangle {
color: 'transparent'
}
label: Text {
text: container.text
}
}
}
Then when you instantiate this component in another file you set whichever id you want and it would still work

Resources