QML ListView with sections representing first letter of model's name role - sections are not visible - qt

I have QML ListView, which shows customers from database via UeCustomerModel. Customers are sorted in model via MySQL statement. All works fine, but now I want to add sections into ListView, so the customers are sorted in sections by first letter criteria. Here is my ListView:
ListView
{
id: ueCustomersListView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignBottom
Layout.margins: 8
clip: true
spacing: 8
delegate: UeCustomerSelectorDelegate
{
ueParamWidth: ueCustomersListView.width
ueParamHeight: 128
ueParamImage: "image://ueCustomerModel/"+model.ueRoleImage
ueParamName: model.ueRoleCustomerName
ueParamTaxId: model.ueRoleCustomerTaxId
ueParamCurrentDebt: model.ueRoleCustomerCurrDebt
ueParamMaxDebt: model.ueRoleCustomerMaxDebt
} // delegate
section.property: model.ueRoleCustomerName // HERE RUNTIME ERROR OCCURS
section.criteria: ViewSection.FirstCharacter
section.delegate: UeCustomerSelectorSectionDelegate
{
ueParamWidth: ueCustomersListView.width
ueParamHeight: 128
ueParamName: section
} // section.delegate
Component.onCompleted:
{
model=ueCustomerModel;
} // Component.onCompleted
} // ListView
and here is section delegate:
import QtQuick 2.5
import QtQuick.Layouts 1.1
Rectangle
{
property int ueParamWidth
property int ueParamHeight
property string ueParamName
width: ueParamWidth
height: ueParamHeight
color: "#4682b4"
antialiasing: true
smooth: true
RowLayout
{
anchors.fill: parent
anchors.margins: 8
spacing: 8
Text
{
color: "#ffffff"
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter
antialiasing: true
text: ueParamName
font.family: "Courier"
font.bold: true
font.pointSize: 12
clip: true
textFormat: Text.RichText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
} // Text
} // RowLayout
} // Rectangle
Now, when ListView is shown, there are no sections visible. What did I miss, i.e., how do I correct section.property: model.ueRoleCustomerName statement to get alphabetical letters from customers (A, B, C, ...). I want ListView to section delegates according to Customer Name (delivered from database via model) first letter. Also, in mentioned line of code, I get QML runtime error Unable to assign [undefined] to QString. Why?
P.S.: model works perfectly (is fast, can search accross customers using TextField), I've tested it 5 times.
According to user sk2212's hint, I've upgraded the code with:
section.property: "ueParamName"
section.criteria: ViewSection.FirstCharacter
section.delegate: UeCustomerSelectorSectionDelegate
{
ueParamWidth: ueCustomersListView.width/2
ueParamHeight: ueCustomersListView.height/4
ueParamName: model.ueRoleCustomerName.subString(0,1)
} // section.delegate
and here is Section delegate:
import QtQuick 2.5
import QtQuick.Layouts 1.1
Rectangle
{
property int ueParamWidth
property int ueParamHeight
property string ueParamName
width: ueParamWidth
height: ueParamHeight
color: "#4682b4"
antialiasing: true
smooth: true
RowLayout
{
anchors.fill: parent
anchors.margins: 8
spacing: 8
Text
{
color: "#ffffff"
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter
antialiasing: true
text: ueParamName
font.family: "Courier"
font.bold: true
font.pointSize: 12
clip: true
textFormat: Text.RichText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
} // Text
} // RowLayout
} // Rectangle
Still does not work.

You have to use the section.property as a model data element:
delegate: UeCustomerSelectorDelegate
{
ueParamWidth: ueCustomersListView.width
ueParamHeight: 128
ueParamImage: "image://ueCustomerModel/"+model.ueRoleImage
ueParamName: model.ueRoleCustomerName
ueParamTaxId: model.ueRoleCustomerTaxId
ueParamCurrentDebt: model.ueRoleCustomerCurrDebt
ueParamMaxDebt: model.ueRoleCustomerMaxDebt
alphabet: model.ueRoleCustomerName.substring(0,1)
} // delegate
section.property: "alphabet"

Related

How can I read listmodel role property in main.qml?

In main.qml, I am updating listModel dynamically on every function addItem() call. Herein, I am setting two role; buttonTypeRole and source. OneText.qml file has a Text field. Actually, after inserting buttonTypeRole and source into listModel, I want to know whether source is being truncated or not.
IS ANY WAY TO READ OneText.qml TEXT TRUNCATED PROPERTY IN main.qml FILE?
main.qml
function additem()
{
listModel.insert(tlist.listModel.count , {"buttonTypeRole":"OneText.qml", "source":editText})
console.log("model-- "+tlist.listModel.get(sourceIndex).t)
}
listModel and ListView snapshot:
Item
{
property alias listModel: listModel
ListModel
{
id:listModel
}
Rectangle
{
id:listHolder
border.color: "transparent"
border.width: 3
color:"transparent"
height:560
width:600
focus:true
ListView
{
//id:listview
x:5
y:5
spacing:10
width:700
height:listHolder.height - 20
id:list
boundsBehavior: ListView.StopAtBounds
model:listModel
delegate:listComponent
clip: true
snapMode:ListView.SnapToItem
}
}
Component
{
id:listComponent
Rectangle
{
//color:"grey"
width:obj.width
height:obj.height
border.color: "red"
Loader
{
id:itemDisplay
source:buttonTypeRole
}
}
}
}
buttonTypeRole :OneText.qml snapshot
import QtQuick 2.0
import QtQuick.Controls 2.0
Item
{
id:one
height:obj.height
width:obj.width
Text
{
id:textOne
height:obj.height
width:obj.width
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: "AlignVCenter"
anchors.leftMargin: 10
font.family: obj.fontFamily
font.bold: obj.fontBoldStyle == "true" ? true : false
font.pixelSize: obj.fontSize
text:source
elide: Text.ElideRight
}
}

How to get column number at mouse click for QtQuick2 TableView

I'm trying to handle mouse clicks on table cells. I need to respond to the right button only if I clicked in a certain cell. but I can't find how to catch the column number. A TableView from QtQuick 2.12 is used. Or maybe you can do without a column number? Tableview from QtQuickControls I, for various reasons, can not use.
TableView {
id: table
boundsBehavior: Flickable.StopAtBounds
anchors.fill: parent
columnSpacing: 0
rowSpacing: 0
anchors.rightMargin: 2
anchors.leftMargin: 5
anchors.bottomMargin: 5
anchors.topMargin: 70
clip: true
model: TableModel {
id: model
Component.onCompleted: {
model.init()
}
}
delegate: Rectangle {
id: tableDelegate
implicitWidth: textDelegate.implicitWidth + textDelegate.padding * 2
implicitHeight: 30
border.width: 0
TextField {
id: textDelegate
text: tabledata
anchors.fill: parent
anchors.verticalCenter: parent.verticalCenter
clip: true
horizontalAlignment: TextField.AlignHCenter
verticalAlignment: TextField.AlignVCenter
enabled: true
background: Rectangle {
border.color: "#e61d6887"
color: "#e6ffffff"
border.width: 1
}
selectByMouse: true
MouseArea {
id: mad
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
switch(mouse.button){
case Qt.RightButton:
console.log("right button")
dialog.open()
break
case Qt.LeftButton:
console.log("left button")
break
default:
break
}
}
}
}
}
}
You have to use model.row and model.column (or row and column) to get the row or column in the delegate, respectively.
// ...
MouseArea {
id: mad
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
console.log(model.row, model.column)
// or
// console.log(row, column)
// ...
}
// ...
I have reported the bug in the documentation: QTBUG-76529.

Qt5.8 QML Why does a read-only Controls2.TextArea have the ibeam cursor?

Qt5.7 this example gives the "pointer" cursor, but Qt5.8, i get the "ibeam" cursor (like i am to insert).
import QtQuick 2.7
import QtQuick.Controls 2
ApplicationWindow
{
width: 1024
height: 800
visible: true
Flickable
{
anchors.fill: parent
flickableDirection: Flickable.VerticalFlick
TextArea.flickable: TextArea
{
font.pixelSize: 25
text: "hello world"
readOnly: true
}
}
}
Is this a deliberate change, if so, how can i show the pointer cursor for a read-only TextArea?
thanks.
update #1:
adding a dummy MouseArea appears to fix it. I don't know why/
like this:
Flickable
{
anchors.fill: parent
flickableDirection: Flickable.VerticalFlick
TextArea.flickable: TextArea
{
font.pixelSize: 25
text: "hello world"
readOnly: true
MouseArea
{
anchors.fill: parent
enabled: false
}
}
}
Following comments of Mitch and Jpnurmi, apparently this was a bug that is now fixed. Great!
In the meantime, my workaround is a dummy MouseArea
TextArea.flickable: TextArea
{
font.pixelSize: 25
text: "hello world"
readOnly: true
MouseArea
{
anchors.fill: parent
enabled: false
}
}

Qt QML How to change size of a component and get the whole page change

I am working on an android application and I am facing a problem. In a page of the application I have some input fields, one of them is for date and I wanted to add a Calendar that open on demand for selecting the date or just enter the date manually, for this, I created a custom component which is composed of a TextInput and a button which when clicked will create the calendar item with a loader and set the size of the loader to 80 (it was 0 initially) all this components are included in a columnlayout. When the button get clicked the calendar is drawn below the other input fields.
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
FocusScope {
id: root
Layout.preferredHeight: 20
property alias text: input.text
property alias border: background.border
property alias backgroundColor: background.color
property alias textColor: input.color
ColumnLayout{
anchors.fill: parent
spacing: 1
RowLayout{
Layout.fillHeight: true
Layout.fillWidth: true
Rectangle {
id: background
Layout.fillHeight: true
Layout.fillWidth: true
color: "darkgrey"
TextInput {
id: input
anchors.fill: parent
anchors.margins: 3
verticalAlignment: TextInput.AlignVCenter
focus: true
text: dateInput.selectedDate
}
}
CustomButton {
id: calandar
Layout.fillHeight: true
Layout.preferredWidth: 40
image: "icons/CalandarButton.svg"
onClicked: {
console.log("clicked calandar")
if(calendarLoader.status === Loader.Null){
calendarLoader.height = 80
calendarLoader.sourceComponent = Qt.createQmlObject("import QtQuick 2.5; import QtQuick.Controls 1.4; Calendar {}",
calendarLoader,
"calandarpp")
}
else{
calendarLoader.height = 0
calendarLoader.sourceComponent = undefined
}
}
}
}
Loader {
id: calendarLoader
Layout.fillWidth: true
height: 0
}
}
}
If something is below, then try changing its z coordinate.
There is no need to do Qt.createQmlObject() ever. It's enough to toggle Loader.active or Item.visible.
Example is not reproducible, make sure that it runs by itself with qmlscene.
This works for me:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
FocusScope {
id: root
Layout.preferredHeight: 20
property alias text: input.text
property alias border: background.border
property alias backgroundColor: background.color
property alias textColor: input.color
z: 1
Loader {
id: calendarLoader
active: false
sourceComponent: Calendar {}
z: 1
}
ColumnLayout {
anchors.fill: parent
spacing: 1
RowLayout{
Layout.fillHeight: true
Layout.fillWidth: true
Rectangle {
id: background
Layout.fillHeight: true
Layout.fillWidth: true
color: "darkgrey"
TextInput {
id: input
anchors.fill: parent
anchors.margins: 3
verticalAlignment: TextInput.AlignVCenter
focus: true
}
}
Button {
id: calandar
Layout.fillHeight: true
Layout.preferredWidth: 40
onClicked: {
console.log("clicked calandar")
calendarLoader.active = !calendarLoader.active
}
}
}
}
}

How to put attached properties to child item

Let's assume I have a component like this
RowLayout {
MyItem {
Layout.fillWidth: true
Layout.fillHeight: true
... // other properties
}
MyItem {
Layout.fillWidth: true
Layout.fillHeight: true
... // other properties
}
}
in which MyItem.qml is defined like this
Rectangle {
... // other properties
// Layout.fillWidth: true
// Layout.fillHeight: true
}
Can I put Layout.fillWidth to MyItem, so that I don't need to repeat it in RowLayout ?
Can I put Layout.fillWidth to MyItem, so I don't need to repeat it in RowLayout ?
I think the question has the answer in it: if you don't want to repeat, just use the Repeater type. The documentation states that
Items instantiated by the Repeater are inserted, in order, as children of the Repeater's parent. The insertion starts immediately after the repeater's position in its parent stacking list. This allows a Repeater to be used inside a layout.
The example which follows in the documentation uses Row but the very same approach can be applied to other layouts, e.g. RowLayout. Actually, it works for any type with attached properties as per the Repeater nature ("insert items inside parent").
Here is an example. Assume we have defined an Example type.
import QtQuick 2.5
Rectangle {
property alias text: inner.text
color: "steelblue"
Text {
id: inner
anchors.centerIn: parent
font.pixelSize: 30
}
}
We can add the layout properties to our Example type inside the Repeater, for instance like this:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
Window {
id: window
width: 600
height: 400
visible: true
RowLayout {
id: row
anchors.fill: parent
Repeater {
model: 6
delegate : Example {
text: index
Layout.fillWidth: true // layout options added in the delegate
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
Layout.maximumWidth: parent.width / model.length
}
}
}
}
The model property of the Repeater can be either an array of strings or another model, as usual.
This approach is flexible enough to combine several Repeaters to create more complex structures. See for instance the following example in which Text is used to fill the screen inside a GridLayout:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
Window {
id: window
width: 600
height: 400
visible: true
GridLayout {
id: grid
anchors.fill: parent
rows: 2
columns: 6
Repeater {
model: grid.columns
Text {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.row: 0
Layout.column: index
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: index + 1 // index of the repeater as text
}
}
Repeater {
model: grid.columns
Text {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.row: 1
Layout.column: index
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: index + 7
}
}
}
}
Yes, you can do that, but it will end in an error whenever you decide to use that component in a context where it has no attached property named Layout.fillWidth or, more in general, whenever you decide not to use it as a top element within a layout.

Resources