I'm trying to make a list of buttons, where the user can select one of the options. I can't seem to display the text from the listmodel, but I can't figure out why. It seems like even the button is not correctly placed. Does anyone have ideas as to how to fix this? Thanks!
import QtQuick 2.15
import QtQuick.Window 2.2
import QtQuick.Controls 2.15
Window {
id: window
visible: true
height: 400
width: 400
Rectangle {
id: rect
width: 400; height: 400
ListView {
id: listview
anchors.fill: parent
model: timeList
delegate: Item {
anchors.top: parent.top
height: 30
Button {
anchors.top: parent.top
anchors.left: parent.left
id: textButton
text: text
width: parent.width
height: 30
flat: true
onClicked: {
console.log(value)
}
}
Rectangle {
height: (index === timeList.count - 1 ? 0 : 1)
color: '#E1E6E9'
width: 400
anchors {
left: textButton.left
top: textButton.bottom
}
}
}
ListModel {
id: timeList
ListElement { text: "15 minutes"; value: 15 }
ListElement { text: "1 hour"; value: 60 }
ListElement { text: "3 hours"; value: 180 }
ListElement { text: "6 hours"; value: 360 }
ListElement { text: "12 hours"; value: 720 }
}
}
}
}
There are several issues here:
don't name ListElement properties using keywords, text: text looks confusing.
don't wrap everything with Rectangle/Item with no need, use Layout instead if needed
never use anchors for delegates
pay attention that all containers have a size, the delegate's Item has no with for example (or probably 0)
actually, that should work:
import QtQuick
import QtQuick.Window
import QtQuick.Controls
Window {
id: window
visible: true
height: 400
width: 400
ListView {
anchors.fill: parent
model: timeList
delegate: Button {
id: textButton
text: name
width: parent.width
height: 30
flat: true
onClicked: {
console.log(value)
}
}
ListModel {
id: timeList
ListElement { name: "15 minutes"; value: 15 }
ListElement { name: "1 hour"; value: 60 }
ListElement { name: "3 hours"; value: 180 }
ListElement { name: "6 hours"; value: 360 }
ListElement { name: "12 hours"; value: 720 }
}
}
}
Related
I want to use comboBox which it's model is taken from a nested model.
The simplified Code:
main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
id: applicationWindow
width: 300
height: 200
visible: true
title: qsTr("01_Change_Model_Data")
ListModel {
id: listModel1
ListElement {
labelText: "ComboBox 1:"
//subItems: ["First", "Second", "Third"]
subItems: [
ListElement {text: "First"},
ListElement {text: "Second"},
ListElement {text: "Third"}
]
}
ListElement {
labelText: "ComboBox 2:"
//subItems: ["First", "Second", "Third"]
subItems: [
ListElement {text: "First"},
ListElement {text: "Second"},
ListElement {text: "Third"}
]
}
}
Button {
id: loadUnloadBtn
height: 24
width: 50
text: "Load"
anchors {
right: parent.right
rightMargin: 20
top: parent.top
topMargin: 10
}
onClicked: {
if(comboBoxAreaLoader.source == "") {
comboBoxAreaLoader.source = "ComboBoxArea.qml"
}else {
comboBoxAreaLoader.source = ""
}
}
}
Loader {
id: comboBoxAreaLoader
anchors {
top: parent.top
topMargin: 10
bottom: parent.bottom
bottomMargin: 10
left: parent.left
leftMargin: 10
right: parent.right
rightMargin: 80
}
source: ""
property variant comboBoxModel: subItems
onStatusChanged: if(status == Loader.Ready) comboBoxModelAlias = comboBoxModel
}
}
ComboBoxArea.qml:
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
id: listViewDelegate
ListView {
id: listView1
anchors.fill: parent
model: listModel1
delegate: listElementDelegate
spacing: 6
}
Component {
id: listElementDelegate
Rectangle {
id: delegateRectangleRoot
property alias comboBoxModelAlias: comboBox.model
height: 30
width: 200
Label {
id: comboBoxNameLabel
color: "red"
width: 80
height: 30
anchors {
left: parent.left
leftMargin: 10
}
text: labelText
verticalAlignment: Text.AlignVCenter
}
ComboBox {
id: comboBox
height: 30
width: 100
//model: ["First", "Second", "Third"]
anchors {
left: comboBoxNameLabel.right
leftMargin: 10
verticalCenter: comboBoxNameLabel.verticalCenter
}
}
}
}
}
I think main problem is defining subItems in nested list. First, I tried to declare it as js list like:
subItems: ["First", "Second", "Third"]
But I got an error:
ListElement: cannot use script for property value
Then I tried to change it with listElements:
subitems: [
ListElement {text: "First"},
ListElement {text: "Second"},
ListElement {text: "Third"}
]
This time I got two errors:
ReferenceError: subItems is not defined
Error: Invalid write to global property "comboBoxModelAlias"
Actually I'm confused. Do you have any idea what I am doing wrong?
Application window screenshot
I think you were just making it a little more complex than it needed to be. By declaring subItems like below, they automatically become ListModels. And you can just refer to them in the delegate like you do labelText.
main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
id: applicationWindow
width: 300
height: 200
visible: true
title: qsTr("01_Change_Model_Data")
ListModel {
id: listModel1
ListElement {
labelText: "ComboBox 1:"
subItems: [
ListElement {text: "First"},
ListElement {text: "Second"},
ListElement {text: "Third"}
]
}
ListElement {
labelText: "ComboBox 2:"
subItems: [
ListElement {text: "First"},
ListElement {text: "Second"},
ListElement {text: "Third"}
]
}
}
Button {
id: loadUnloadBtn
height: 24
width: 50
text: "Load"
anchors {
right: parent.right
rightMargin: 20
top: parent.top
topMargin: 10
}
onClicked: {
if(comboBoxAreaLoader.source == "") {
comboBoxAreaLoader.source = "ComboBoxArea.qml"
}else {
comboBoxAreaLoader.source = ""
}
}
}
Loader {
id: comboBoxAreaLoader
anchors {
top: parent.top
topMargin: 10
bottom: parent.bottom
bottomMargin: 10
left: parent.left
leftMargin: 10
right: parent.right
rightMargin: 80
}
}
}
ComboBoxArea.qml:
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
id: listViewDelegate
ListView {
id: listView1
anchors.fill: parent
model: listModel1
delegate: listElementDelegate
spacing: 6
}
Component {
id: listElementDelegate
Rectangle {
id: delegateRectangleRoot
height: 30
width: 200
Label {
id: comboBoxNameLabel
color: "red"
width: 80
height: 30
anchors {
left: parent.left
leftMargin: 10
}
text: labelText
verticalAlignment: Text.AlignVCenter
}
ComboBox {
id: comboBox
height: 30
width: 100
model: subItems
anchors {
left: comboBoxNameLabel.right
leftMargin: 10
verticalCenter: comboBoxNameLabel.verticalCenter
}
}
}
}
}
I have a simple ListView program and therein trying to attach scrollbar. There is no movement on list while scrolling up/ down, here, list should be moving accordingly. Seems, I am not able to set contentItem correctly. Looking for some hints.
Please find my sample core below, thereupon I added a vertical scrollbar to listView.rolesListModel is my model.
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
width: 400
height: 300
visible: true
ListModel
{
id:rolesListModel
ListElement
{
t:"One"
}
ListElement
{
t:"Two"
}
ListElement
{
t:"Three"
}
ListElement
{
t:"Five"
}
ListElement
{
t:"Six"
}
ListElement
{
t:"Seven"
}
ListElement
{
t:"Eight"
}
ListElement
{
t:"Nine"
}
ListElement
{
t:"Ten"
}
}
ListView {
id: listView
width: 150
height: 100
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
model: rolesListModel
clip: true
delegate: listRect
ScrollBar {
id: vbar
active: true
orientation: Qt.Vertical
size: listView.height / listView.contentHeight
position: listView.currentItem
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
Component
{
id:listRect
Rectangle
{
id:listElementRect
height:20
width: 100
Text
{
id:elementText
width:parent.width
height:parent.height
text:t
horizontalAlignment: "AlignHCenter"
}
}
}
}
Newer way
You're using an older version of QML, QtQuick is now at 2.14. If you were okay moving from ScrollBar to a ScrollView, then the code for an arbitrary ListView would look like this:
import QtQuick 2.14
import QtQuick.Controls 2.14
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Scroll")
ScrollView {
anchors.fill: parent
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ListView {
width: parent.width
model: 20
delegate: ItemDelegate {
text: "Item " + (index + 1)
width: parent.width
}
}
}
}
Please note the essential scrollbar configuration line ScrollBar.vertical.policy: ScrollBar.AlwaysOn
https://doc.qt.io/qt-5/qml-qtquick-controls2-scrollview.html#scroll-bars
Older way
If, however, you would like to continue with your code, then the fix is to specifically declare that the vertical scrollbar property is bound to your scrollbar
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
width: 400
height: 300
visible: true
ListModel
{
id:rolesListModel
ListElement
{
t:"One"
}
ListElement
{
t:"Two"
}
ListElement
{
t:"Three"
}
ListElement
{
t:"Five"
}
ListElement
{
t:"Six"
}
ListElement
{
t:"Seven"
}
ListElement
{
t:"Eight"
}
ListElement
{
t:"Nine"
}
ListElement
{
t:"Ten"
}
}
ListView {
id: listView
width: 150
height: 100
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
model: rolesListModel
clip: true
delegate: listRect
ScrollBar.vertical: vbar
ScrollBar {
id: vbar
active: true
orientation: Qt.Vertical
size: listView.height / listView.contentHeight
position: listView.currentItem
policy: ScrollBar.AlwaysOn
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
Component
{
id:listRect
Rectangle
{
id:listElementRect
height:20
width: 100
Text
{
id:elementText
width:parent.width
height:parent.height
text:t
horizontalAlignment: "AlignHCenter"
}
}
}
}
Please note the crucial ScrollBar.vertical: vbar line, which assigns your ScrollBar component vbar to the ListView.
https://doc.qt.io/qt-5/qml-qtquick-controls2-scrollbar.html#details
What I want to do is create a new object inside a component, which can be done with the Component component of qml, but as an argument I want to pass another component which will be in a different .qmlfile.
I'm going to illustrate what I'm trying to do.
I have a tab bar accordion component I've done:
When I click on the button I want a new tab to be created which will have its own contents!
I provide the code I've used below:
import QtQuick 2.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Window 2.3
ApplicationWindow {
visible: true
width: 640
height: 500
title: qsTr("Tabbars")
Button{
id: button
text: "add new tab dynamically"
onClicked: item.createPanelItem()
anchors.top:parent.top
anchors.left:parent.left
height: 20
width: parent.width
}
Item{
id:item
//anchors.fill:parent
anchors.top: button.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
ScrollView{
anchors.fill:parent
Column {
id: column
width:item.width
property int currentItem: 0
PanelItem {
id:panel1
index:0
title: "Panel 1"
width:parent.width
content: Item {
property string title: "teste"
height: configContent.implicitHeight
width: configContent.implicitWidth
ColumnLayout{
id:configContent
anchors.topMargin: 10
anchors.bottomMargin: 10
anchors.fill:parent
TextField {
id: companyNameText1
placeholderText: qsTr("Company name")
Layout.fillWidth: true
selectByMouse: true
}
ComboBox {
id: languagesComboBox1
textRole: "text"
objectName: "language"
Layout.fillWidth: true
model: ListModel {
ListElement {text: QT_TR_NOOP("English"); oid: 0}
ListElement {text: QT_TR_NOOP("Portuguese"); oid: 1}
ListElement {text: QT_TR_NOOP("Spanish"); oid: 2}
ListElement {text: QT_TR_NOOP("Italian"); oid: 3}
ListElement {text: QT_TR_NOOP("French"); oid: 4}
ListElement {text: QT_TR_NOOP("Portuguese(Brasil)"); oid: 5}
}
}
ComboBox {
id: devSndrModeComboBox1
textRole: "text"
objectName: "test_dev_sndr_mode"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("None"), oid: 0 })
append({ text: QT_TR_NOOP("Subpanel"), oid: 1 })
append({ text: QT_TR_NOOP("All"), oid: 2 })
}
}
}
}
}
// onResetOtherPanels: function(indexClicked){
// if()
// }
}
PanelItem {
id:panel2
index:1
title: "Panel 2"
width:parent.width
content: Item {
property string title: "teste"
height: configContent2.implicitHeight
width: configContent2.implicitWidth
ColumnLayout{
id:configContent2
anchors.fill:parent
ComboBox {
id: sndrModeComboBox1
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("Preset"), oid: 0 })
append({ text: QT_TR_NOOP("Programmed"), oid: 1 })
}
}
}
}
}
Component.onCompleted: {
//resetOtherAccordions.connect(panel1.resetHeight)
console.log("panel 2 height "+panel2.height)
}
}
PanelItem {
id:panel3
index:2
title: "Panel 3"
width:parent.width
content: Item {
property string title: "teste"
height: configContent3.implicitHeight
width: configContent3.implicitWidth
ColumnLayout{
id:configContent3
anchors.fill:parent
ComboBox {
id: sndrModeComboBox2
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("Preset"), oid: 0 })
append({ text: QT_TR_NOOP("Programmed"), oid: 1 })
}
}
}
}
}
Component.onCompleted: {
console.log("panel 3 height "+panel2.height)
}
}
}
}
function createPanelItem(){
panelItem.createObject(column,{title:qsTr("newTest"),index:4 /*,content: Item{}*/ })
}
Component {
id: panelItem
PanelItem {
title: qsTr("Teste")
width: parent.width
}
}
}
}
PanelItem.qml:
import QtQuick 2.7
import QtQuick.Layouts 1.2
Item {
id: root
property Component content
property string title: "panel"
property bool isSelected: false
property int index: 0
function toggleSelected() {
root.isSelected = !root.isSelected
if(root.isSelected){
parent.currentItem = index
for(var i = 0;i<parent.children.length;i++)
{
if(parent.children[i].index !== parent.currentItem && parent.children[i].isSelected)
{
parent.children[i].toggleSelected()
}
}
}
}
clip: true
height: container.height + bar.height
Rectangle{
id: bar
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: 30
color: root.isSelected ? "#81BEF7" : "#CEECF5"
Text {
anchors.fill: parent
anchors.margins: 10
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: root.title
}
Text {
anchors{
right: parent.right
top: parent.top
bottom: parent.bottom
margins: 10
}
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
text: "^"
rotation: root.isSelected ? "180" : 0
}
MouseArea {
id:panelAreaClick
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: function(){
toggleSelected()
}
}
}
Rectangle{
id: container
anchors.top: bar.bottom
anchors.left: parent.left
anchors.right: parent.right
height: loader.item && isSelected ? loader.item.height : 0
Loader {
id: loader
visible: isSelected
sourceComponent: content
anchors.top: container.top
}
Behavior on height {
PropertyAnimation { duration: 1000 }
}
}
}
My big problem here, is I can't find a way to provide something to content in the createObject function.
I know that I can pass dynamically content to content doing something like:
"content": "import QtQuick 2.0; Rectangle{}"
but this is not I want to do, because I will have a component created on a file something like panellog.qml that is what I want to pass to the contentargument of the new tab that will be created.
It would be easiest to simply specify that in your inline component:
Component {
id: panelItem
PanelItem {
title: qsTr("Teste")
width: parent.width
content: Item {}
}
}
Or you can set the type of content to be Component so you can pass some other inline component to it, which ... is pretty much the same thing really. This might seem a bit too laborious, but is actually quite handy to customize stuff in a way that also gives you access to the current component scope.
The problem here is that Qt has a two way limitation that is kinda impeding:
you cannot use declarative component syntax in imperative (JS) code
you cannot declaratively instantiate inline components
Which means that:
if you want to reference a declarative object, you have to do so using its id or a property - it will only work with an identifier, not with an object literal/instance
if you want to decalratively create an object, it has to be in a dedicated qml file
I am working on qml, found found an error during moving mouse wheel scrolling i.e.
"TypeError: Cannot read property 'name' of undefined".
It only appear when either mouse wheel scrolling or close the application while during execution and beginning of the application didn't show this error.
One more thing, I am getting accurate data/result whatever I want but due to this error the performance of application get affected.
Please let me know how can I get rid of this issue?
also find below example to see error.
My code is..
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
TableView {
anchors.fill: parent
visible: true
backgroundVisible: false
alternatingRowColors: false
sortIndicatorVisible: true
clip: true
highlightOnFocus: false
width: parent.width
height: parent.height
TableViewColumn{ role: "code" ; title: "cde" ; width: 200;
delegate: Component {
id: codeDelegate
Item{
Text {
color: "lightgray"
elide: styleData.elideMode
text: styleData.value //modelSettingData.get(styleData.row).name
font.family: "Arial"
font.pixelSize: 18
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Text {
id: metaData
color: "red"
width: parent.width
// height: 20
anchors.bottom: parent.bottom
anchors.bottomMargin: -parent.height/1.5
font.weight: Font.ExtraLight
//elide: Text.ElideMiddle
text: "Time: " + modelSettingData.get(styleData.row).name //Error comes when this part added but I need to use it with the same form
}
}
}
}
}
TableViewColumn{ role: "name" ; title: "nme" ; width: 200
delegate: Component {
id: nameDelegate
Text {
color: "yellow"
elide: styleData.elideMode
text: styleData.value
font.family: "Arial"
font.pixelSize: 18
}
}
}
model: ListModel {
id: modelSettingData
ListElement {
name: "aaaaaaaaaa"
code: "3042666666666"
}
ListElement {
name: "bbbbbb"
code: "32235"
}
ListElement {
name: "ccccccc"
code: "32638"
}
ListElement {
name: "ddddddddddd"
code: "00000000000"
}
ListElement {
name: "eeeeeeeeeeee"
code: "111111111111"
}
ListElement {
name: "ffffffffffff"
code: "222222222222"
}
ListElement {
name: "ggggggggggggg"
code: "3333333333333"
}
ListElement {
name: "hhhhhhhhhhhhh"
code: "4444444444444"
}
ListElement {
name: "iiiiiiiiiiiii"
code: "5555555555555"
}
}
rowDelegate: Rectangle {
property bool selected : styleData.selected
width: parent.width-2
height: 100
color: styleData.selected? "black" : "black"
Rectangle {
width: parent.width
height: 1
anchors.bottom: parent.bottom
visible: parent.selected
color: "yellow"
}
}
}
}
I have a Listmodel where the delegates get selected/highlighted when they are clicked on. However when I click on a Combobox, which is part of the delegate, the delegate does not get selected.
Is there something like propagateComposedEvents which could propagate the click to the MouseArea of the delegate?
What would be the best way to also select the delegate when I click on it's containing Combobox?
Here is a screenshot
Here is the example code
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
ListModel {
id: contactsModel
ListElement {
name: "Bill Smith"
}
ListElement {
name: "John Brown"
}
ListElement {
name: "Sam Wise"
}
}
ListModel {
id: roleModel
ListElement {
text: "Employee"
}
ListElement {
text: "Manager"
}
ListElement {
text: "Big Boss"
}
}
ListView{
id: contactsView
anchors.left: parent.left
anchors.top: parent.top
width: parent.width
height: parent.height
orientation: Qt.Vertical
spacing: 10
model: contactsModel
delegate: contactsDelegate
}
Component{
id: contactsDelegate
Rectangle{
width: 200
height: 50
color: ListView.isCurrentItem ? "#003366" : "#585858"
border.color: "gray"
border.width: 1
MouseArea{
anchors.fill: parent
onClicked: {
contactsView.currentIndex = index;
}
}
Column{
Text {
color: "white"
text: name
}
ComboBox{
currentIndex: 0
model: roleModel
}
}
}
}
}
ComboBox{
currentIndex: 0
model: roleModel
onPressedChanged: if (pressed) contactsView.currentIndex = index
}
It is not exactly propagating, but it does the trick.