List elements are not showing up in a vertical line - qt

On Qt 5.9.4, I have a ListView with model and delegate like below:
Rectangle {
Column {
Image {
id: img0
source: "images/img0.png"
}
ListView {
model: ListModel {
ListElement {
dimName: "D top"
}
ListElement {
dimName: "D mid"
}
ListElement {
dimName: "D bot"
}
ListElement {
dimName: "H top"
}
ListElement {
dimName: "H bot"
}
}
delegate: RowLayout {
StyledLabel {
text: dimName
enabled: true
}
Rectangle {
}
SpinBox {
editable: true
enabled: true
from: 0
to: 1000
stepSize: 1
}
}
}
}
}
The ListView doesn't show the ListElements correctly. I mean all the elements are shown on top of each other, and on top of the Image item in the code, like this:
Can anybody give me a hint on how to show ListElements in a vertical line, one below the other.
UPDATE
as suggested by #Amfasis in a comment, I explicitly determined the height of ListView item:
height: parent.height + 100
anchors.top: img0.bottom
After above modification, now the list looks better:

You have to set the height of the RowLayout, but to set it explicitly is of course not nice. So you can use the height of the first child, or a different one if you wish (actually in your case this would be the SpinBox probably)
delegate: RowLayout {
anchors.left: parent.left
anchors.right: parent.right
//height: children[0].height
height: spinbox.height //actually better in your case
StyledLabel {
text: dimName
enabled: true
}
Rectangle { }
SpinBox {
id: spinbox
editable: true
enabled: true
from: 0
to: 1000
stepSize: 1
}
}
Even better would be to take the max of all children, but I'm not sure how that would be done best

Related

Is there a way to make unselectable a "list item" in ListView?

I am new to Qt. Wondering if there a possibility to make an item "unselectable" in ListView.
I see there are a lot of other things, e.g: collapsing , expanding, etc.
**
I have not find any simple example for this problem. **
Can you provide some minimalistic examples to make a specific item in the list unselectable?
I have the following minimalistic example. How can I set list item index 2 to be unselectable?
Window {
id: mainWindow
width: 130
height: 240
visible: truetitle: qsTr("Hello")
Rectangle {
id: bg
color: "#ffffff"
anchors.fill: parent
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
Component {
id: nameDelegate
Text {
text: model.name
font.pixelSize: 24
}
}
ListView {
anchors.fill: parent
model: nameModel
delegate: nameDelegate
clip: true
highlight: Rectangle {
anchors { left: parent.left; right: parent.right }
//height: parent.height
color: "lightgrey"
}
}
}
}
I found numerous issues with your code snippet, so I attempted to address them all:
I made use of Page and set Page.background instead of declaring an outer Rectangle. This removes a level of indentation
I refactored NameComponent.qml to reduce the complexity of your main program
I change the delegate from Text to ItemDelegate so that it is clickable, and, it being clickable, I can (1) make the ListView have active focus so that it can receive keyboard events, (2) change the current item in the ListView => I think this achieves your criteria of being able to select a different item
I removed unnecessary anchoring from your highlight - your highlight will default anchor to your selected item
I set the width of your delegate to listView.width - I also made use of the ListView.view attached property so that your delegate and access properties from the ListView
Finally, I added a 20 pixel width vertical ScrollBar
import QtQuick
import QtQuick.Controls
Page {
background: Rectangle { color: "#ffffff" }
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
ListView {
anchors.fill: parent
model: nameModel
delegate: NameDelegate { }
clip: true
highlight: Rectangle {
color: "lightgrey"
}
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
}
}
// NameDelegate.qml
import QtQuick
import QtQuick.Controls
ItemDelegate {
property ListView listView: ListView.view
width: listView.width - 20
text: model.name
font.pixelSize: 24
onClicked: {
listView.forceActiveFocus();
if (listView.currentIndex === index) {
listView.currentIndex = -1;
} else {
listView.currentIndex = index;
}
}
}
You can Try it Online!

auto KeyNavigation.tab for custom components "rectangle or item" in QML

in Qml there is auto key navigation for already known components like checkbox,textfield,button and etc , i have my custom component which is a item or rectangle and i want same functionality for it,without writing
KeyNavigation.tab: componentid
here is one of my custom controls :
Rectangle {
signal clicked
property alias font : icoText.font.family
property alias icon : icoText.text
property alias size : icoText.font.pixelSize
property alias toolTip : tooltipText.text
property string colorEnter :"#0481ff"
property string colorExit :"#00171f"
id: root
implicitWidth: 50
implicitHeight: 50
//width: childrenRect.width
radius: 0
//height: childrenRect.height
color: colorExit
state: "default"
Text {
id: icoText
text: ""
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 25
font.family: "fontawesome"
visible: text!= ""
color: "white"
}
ToolTip {
id:tooltipText
text: ""
delay: 500
timeout: 2000
visible: mouseArea.containsMouse && text!=""
font.family: "B Nazanin"
contentItem: Text {
text: tooltipText.text
font: tooltipText.font
color: "white"
}
background: Rectangle {
color: "#cc000000"
border.color: "black"
}
}
InnerShadow {
id:shadow
anchors.fill: icoText
radius: 1.0
samples: 17
horizontalOffset: 1
color: colorExit
source: icoText
visible: false
}
MouseArea{
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: root.color = colorEnter
onExited: root.color = root.state == "transparent"? "transparent" : root.colorExit
onPressed: {
shadow.visible = true
}
onReleased: {
shadow.visible = false
}
onClicked: {
root.clicked()
}
}
states: [
State {
name: "transparent"
PropertyChanges {
target: root
color:"transparent"
}
PropertyChanges {
target: icoText
color:colorExit
}
},
State{
name: "default"
PropertyChanges {
target: root
color:colorExit
}
PropertyChanges {
target: icoText
color:"white"
}
}
]
}
which will be inside a page like this :
Item{
myControl{
}
myControl{
}
}
this component by default does not loop through pressing tab what should i do?
i already tried this without success, i think this should be inside FocusScope but cause of poor documentation i did not get a simple example for this
set activeFocusOnTab on parent and focus:true in child you want to get focus
Rectangle{
activeFocusOnTab: true
Control{
focus: true
}
}
Focusable Qml Components (Focus My Control On Tab)
For my experience key navigation only works with native components like checkbox, textfield, button, etc.
To work arround this problem I used a fake native component hided with the same size of my custom component like the next example:
Rectangle {
id: myCustomComponent1
width: 100
height: 100
color: red
Button {
id: buttonFake1
text: "My Accessible text Component 1"
width: parent.width
height: parent.height
opacity: 0 // hide the fake component
Accessible.role: Accessible.defaultButton
Accessible.name: text
KeyNavigation.tab: buttonFake2
onClicked: {
console.log(index)
}
onFocusChanged: {
if(focus === true){
// Here do what you want with your custom component
// For example, change color, size, ...
Do_what_you_Want()
// And then set back the focus at the fake native component
// to key navigation keeps working from the same component
buttonFake1.focus = true
}
}
}
}
Rectangle {
id: myCustomComponent2
width: 100
height: 100
color: green
Button {
id: buttonFake2
text: "My Accessible text Component 2"
width: parent.width
height: parent.height
opacity: 0 // hide the fake component
Accessible.role: Accessible.defaultButton
Accessible.name: text
KeyNavigation.tab: buttonFake1
onClicked: {
console.log(index)
}
onFocusChanged: {
if(focus === true){
// Here do what you want with your custom component
// For example, change color, size, ...
Do_what_you_Want()
// And then set back the focus at the fake native component
// to key navigation keeps working from the same component
buttonFake2.focus = true
}
}
}
}

Getting header title from model in QtQuick ListView

It's not clear to me how to access the model from the header component in ListView. I have provided headerData in the (C++) model, but it doesn't seem to be called. I can grab the data from the model in theRowDelegate, so my roles are defined correctly (I have implemented the roleNames function).
I'm sure this must be explained in the documentation somewhere, but I can't find it.
ListView{
anchors.fill: parent
model: logfile_model
orientation: Qt.Vertical
header: Row{
Text{
text: increment // Doesn't work
width: 100
}
Text{
text: iteration // Doesn't work
width: 100
}
}
delegate: Row{
Text {
text: increment
width: 100
}
Text {
text: iteration
width: 100
}
}
}
This is the demo you want, but not recommend because the header text shall not put into model data.
You can drag the list to see the header fixed always keep visible.
ListModel{
id: testData
ListElement{
increment: "I am a Header"
iteration: "I am also aHeader"
}
ListElement{
increment: "testData"
iteration: "testData"
}
ListElement{
increment: "testData"
iteration: "testData"
}
ListElement{
increment: "testData"
iteration: "testData"
}
}
ListView{
anchors.fill: parent
model: testData
Rectangle{ // always visible
width: header.width
height: header.height
color: "white"
Row{
id: header
Text{
text: testData.get(0).increment
width: 100
}
Text{
text: testData.get(0).iteration
width: 100
}
}
}
delegate: Row{
Text {
text: increment
width: 100
}
Text {
text: iteration
width: 100
}
Component.onCompleted: if(index == 0) {
visible = false
}
}
}

Two-dimensional table with nested scrolling areas in QML

I want to create, in QML, a TV-schedule where the vertical axis is a list of Channels and the horizontal axis is time-based. For example something like
(source: zappware.com)
Initially, I created
a vertical ListView with
model = the list of Channels
delegate = a horizontal ListView
every horizontal ListView has
model = the list of Events
delegate = an Item where the width is proportional to the duration of the Event
So far so good. Only drawback is that the horizontal ListViews scroll one by one while they should scroll together.
So somehow, the contentX property of every horizontal ListView should be bound to the contentX property of the moving/flicking horizontal ListView. Note that this binding is dynamic: when flicking in the first row, all other rows should bind to the contentX of the first row. But this should be changed when flicking in the second row.
Any advice on how this can be done?
I tried a somewhat different approach by
creating a Flickable Item on top of the vertical ListView (with contentWidth the complete time-window).
binding every horizontal ListView to the contentX of this Flickable (this is a static binding)
This resulted in nice synchronous scrolling but I still have some issues
I had to do some tricks to ensure that flicking is only horizontal or vertical but not both
I'm not able anymore to click on individual Events; I guess events are intercepted by the Flickable
I'm also not sure about the memory impact of such a Flickable with a huge contentWidth?
Feedback appreciated!
I'd say have only one vertical list view for the channels. But the channel names only, not the actual programs. Instead of a horizontal view for the programs, you can cram them all together in a single flickable, using the begin time and duration to layout the programs in the flickable by binding their x and width properties to the former.
Then you can bind the channel list view together with the vertical scrolling of the program items, so that you have the programs corresponding to their appropriate channels. This way you can scroll vertically from both, and only scroll horizontally the programs.
Here is a quick example:
ApplicationWindow {
id: main
width: 500
height: 100
visible: true
color: "white"
ListModel {
id: modC
ListElement { name: "Ch1" }
ListElement { name: "Ch2" }
ListElement { name: "Ch3" }
}
ListModel {
id: modP1
ListElement { name: "p1"; start: 0; duration: 6 }
ListElement { name: "p2"; start: 6; duration: 6 }
ListElement { name: "p3"; start: 12; duration: 6 }
ListElement { name: "p4"; start: 18; duration: 6 }
}
ListModel {
id: modP2
ListElement { name: "p1"; start: 0; duration: 12 }
ListElement { name: "p2"; start: 12; duration: 12 }
}
ListModel {
id: modP3
ListElement { name: "p1"; start: 0; duration: 8 }
ListElement { name: "p2"; start: 8; duration: 8 }
ListElement { name: "p3"; start: 16; duration: 8 }
}
property var subMod : [ modP1, modP2, modP3 ]
Component {
id: progDelegate
Rectangle {
property var source
x: source.start * 50
width: source.duration * 50
height: 50
color: "lightblue"
border.color: "black"
Text {
text: source.name
}
}
}
Row {
anchors.fill: parent
ListView {
id: list
height: parent.height
width: 100
model: modC
delegate: Item {
width: 100
height: 50
Rectangle {
anchors.fill: parent
color: "red"
border.color: "black"
Text {
anchors.centerIn: parent
text: name
}
}
Component.onCompleted: {
var mod = subMod[index]
for (var i = 0; i < mod.count; ++i) progDelegate.createObject(flick.contentItem, {"source": mod.get(i), "y": index * 50})
}
}
}
Flickable {
id: flick
height: parent.height
width: parent.width - list.width
contentWidth: 1200
contentHeight: contentItem.childrenRect.height
clip: true
flickableDirection: Flickable.HorizontalFlick
contentY: list.contentY
}
}
}

Qt, QML ListView and Desktop App

My question is kind of a two part conditional question. I have a desktop application I'm writing in C++/Qt. In the app I have a couple lists that I want to decorate and add list items with icons and rich text.
I first attempted to do this with the QWidget world but the more I looked into it, the more I thought QML might be a better option. But now I'm wondering about that as well since it seems that QML Is more geared toward touch screen devices. Not to mention that my progress with QML has been frusating. Give them QML below, I cannot figure out how to: (1) get an item to highlight when I click it and (2) add a scroll bar:
import QtQuick 1.0
Item
{
width: 300
height: 200
ListModel
{
id: myModel2
ListElement { text: "List Item 1" }
ListElement { text: "List Item 2" }
ListElement { text: "List Item 3" }
ListElement { text: "List Item 4" }
ListElement { text: "List Item 5" }
ListElement { text: "List Item 6" }
}
Component
{
id: beerDelegate
Rectangle
{
id: beerDelegateRectangle
height: beerDelegateText.height * 1.5
width: parent.width
Text
{
id: beerDelegateText
text: "<b>" + modelData + "</b> <i>(" + modelData + ")</i>"
}
MouseArea
{
anchors.fill: parent
onClicked:
{
console.log("clicked: " + modelData + " at index: " + index);
beerList.currentIndex = index;
}
}
}
}
ListView
{
id: beerList
anchors.fill: parent
model: myModel2
delegate: beerDelegate
highlightFollowsCurrentItem: true
highlight: Rectangle
{
width: parent.width
color: "red"
}
focus: true
}
}
How can I accomplish what I'm looking for given this QML? Or is using QML in a QWidget desktop app just a bad idea all around?
For the first question (highlight):
Your list actually draws the highlight, however, your item delegate overpaints this with a white rectangle! Just replace the rectangle with an item and it works:
Component
{
id: beerDelegate
Item
{
...
}
}
For the second question (scroll bars):
As far as I know, QML doesn't provide scroll bars out of the box. There is however the Qt Desktop Components project (git repository) which gives you access to most of the widgets in the QML world. Among them, there is a ScrollArea.
It is no longer necessary to implement the Scrollbars yourself. There is the ScrollView-Item since Qt 5.1. Simply surround a Flickable-Item (e.g. the ListView-Item you use, is also "Flickable") with the ScrollView-Item and you'll be fine:
ScrollView {
ListView {
id: beerList
anchors.fill: parent
model: myModel2
delegate: beerDelegate
highlightFollowsCurrentItem: true
highlight: Rectangle
{
width: parent.width
color: "red"
}
focus: true
}
}
For the second question. i.e Scroll-bar on ListView:
I have created code for scroll bar on ListView. It also can work on the GridView
ScrollBar.qml
import Qt 4.7
Item {
property variant target
width: 8
anchors.top: target.top
anchors.bottom: target.bottom
anchors.margins: 1
anchors.rightMargin: 2
anchors.bottomMargin: 2
anchors.right: target.right
visible: (track.height == slider.height) ? false : true
Image {
id: scrollPath
width: 2
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
source: "qrc:/resources/buttons/slider2.png"
}
Item {
anchors.fill: parent
Timer {
property int scrollAmount
id: timer
repeat: true
interval: 20
onTriggered: {
target.contentY = Math.max(0, Math.min(target.contentY + scrollAmount,
target.contentHeight - target.height));
}
}
Item {
id: track
anchors.top: parent.top
anchors.topMargin: 1
anchors.bottom: parent.bottom
width: parent.width
MouseArea {
anchors.fill: parent
onPressed: {
timer.scrollAmount = target.height * (mouseY < slider.y ? -1 : 1)
timer.running = true;
}
onReleased: {
timer.running = false;
}
}
Image {
id:slider
anchors.horizontalCenter: parent.horizontalCenter
source: "qrc:/resources/buttons/slider.png"
width: parent.width
height: Math.min(target.height / target.contentHeight * track.height, track.height) < 20 ? 20 : Math.min(target.height / target.contentHeight * track.height, track.height)
y: target.visibleArea.yPosition * track.height
MouseArea {
anchors.fill: parent
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: 0
drag.maximumY: track.height - height
onPositionChanged: {
if (pressedButtons == Qt.LeftButton) {
target.contentY = slider.y * target.contentHeight / track.height;
}
}
}
}
}
}
}
And I used scroll bar item with ListView in MyListView.qml as:
MyListView.qml
ListView {
id: list
clip: true
anchors.margins: 5
anchors.fill: parent
model: 10
delegate: trackRowDelegate
interactive: contentHeight > height
}
ScrollBar {
id: verticalScrollBar
target: list
clip: true
}
This ScrollBar item can be used with GridView as
GridView {
id: grid
clip: true
anchors.margins: 5
anchors.fill: parent
cellWidth:100
cellHeight: 100
model: items
interactive: contentHeight > height
snapMode: GridView.SnapToRow
delegate: myDelegate
}
ScrollBar {
id: verticalScrollBar
target: grid
clip: true
visible: grid.interactive
}

Resources