How to setup ListView that hightlight fits always into it - qt

I have a vertical ListView with a lot elements. When an element gets clicked a Rectangle pops up under it as highlight.
This doesnt work for the last elements in the ListView, as can be seen in the image.
How do I setup ListView, that a highlight pushes all elements up.
What I have:
What I want:

I could solve my issue by expanding the selected delegates height for the while it is selected. Furthermore you have to set the hightlight's y explicitly.
ListView{ id:listView
property var someHeight: 100
delegate:Item{
id: delegate
Connections{
target: listView
function onCurrentIndexChanged(){
if(index==listView.currentIndex)
delegate.height=someHeight+listView.highlightItem.childrenRect.height
else
delegate.height=someHeight
}
}
}
}
highlight:Item{
z:10
Rectangle{
id:highlightRect
anchors.left:parent.left
anchors.leftMargin: smallMargin
anchors.right: parent.right
anchors.rightMargin: smallMargin
y: someHeight;
height:someHighlightHeight
}
}
}

Related

Qml Combobox not closing when delegate of the listview goes out of scope

I have made a delegate for listview that contains Combobox. If I open the Combobox and scroll the listview, the Combobox popup is moving with the delegate position, that's ok. But when the delegate goes out of the listview area(Ref the sample image attached), Combobox popup continues to moves even out of the listview area.
How to close the Combobox when the corresponding delegate goes out of the listview area.
Thanks in advance...
Code goes here
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Column {
spacing: 0
anchors.fill: parent
Item {
width: parent.width
height: parent.height * 0.4
Image {
anchors.fill: parent
anchors.margins: 10
source: "https://lh4.googleusercontent.com/proxy/cITVCAj9KJ5Hfwd5iuNDhzdB2pSrMQv2rzTl-vvg23Ifhe2qdCisZBG-MzV35y_r2zijC9X4QOpda9eHzr_hA"
}
}
ListView {
width: parent.width
height: parent.height * 0.7
model: 10
spacing: 5
clip: true
delegate: Rectangle {
width: parent.width
height: 50
color: index % 2 == 0 ? "lightsteelblue" : "steelblue"
Row {
spacing: 25
anchors.centerIn: parent
Label {
text: qsTr("%1").arg(index)
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
anchors.verticalCenter: parent.verticalCenter
model: ["a", "b", "c"]
}
}
}
}
}
}
If there is no particular goal to keep ComboBox popup opened when scrolling, then add the following property to your ListView:
highlightRangeMode: ListView.StrictlyEnforceRange
This will close ComboBox popup when ListView is being scrolled.
P.S.
Also, resolves your issue with the ComboBox list getting out of view area.
UPDATE on issue with header element hiding below other list items:
Accordingly to the description ListView.StrictlyEnforceRange - the highlight never moves outside of the range. The current item changes if a keyboard or mouse action would cause the highlight to move outside of the range. when an item goes out of range the list changes next item and that makes ComboBox closing its popup, but since header item is below the other ListView items itself (see this paragraph https://doc.qt.io/qt-5/qml-qtquick-listview.html#stacking-order-in-listview , delegate is always above a header) it makes impossible displaying default header here at the top of the other items. I'd suggest you implement your own header beyond the list. Sorry, I might not have known Qt so good to find the other solution.

Multiline text item is not clipped inside QML ListView

I have a QML page that with a GridLayout that contains the page title, ListView and close button:
GridLayout {
columns: 1
rows: 5
anchors.fill: parent
<page title item>....
ListView
{
spacing: 15
model: logModel
delegate: Item {
implicitWidth: parent.width
implicitHeight: grid.height
RowLayout
{
id: grid
spacing: 0
width: parent.width
height: commentLabel.implicitHeight
<icon>....
Label {
id: commentLabel
Layout.fillWidth: true
text: comment
wrapMode: Label.Wrap
}
}
}
ScrollIndicator.vertical: ScrollIndicator { }
}
<close button>...
}
When I scroll the list, the first and the last visible item in the list may go beyond the list bounder and intersect the page title or close button:
How to prevent this and make the items clipped?
EDIT1:
I tried to add
clip: true
to ListView, delegate Item, RowLayout and Label, but with no success. According to docs, ListView with clip property set to true should clip its content, should not it?
I found a similar question where clip property is the answer, but it is not clear why it does not work with my ListView.
My QT version is 5.13.2.
Set clip:true in the ListView component.
ListView
{
clip:true
}

QML flickable print height/width while dragging view

I want to be able to print the height/width of the Flickable view while dragging it. I believe it can be done using onDraggingChanged or onMovingChanged, since a similar event listener onTextChanged does the job of listening text changes in text controls.
I tried this:
Flickable{
id: flick
height: parent.height - 40
width: parent.width - 40
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 20
flickableDirection: Flickable.HorizontalAndVerticalFlick
Rectangle{
anchors.fill: parent
color: "steelblue"
}
onMovingChanged: {
console.log("onMovingChanged")
console.log("height:", height)
}
onDraggingChanged: {
console.log("onDraggingChanged")
console.log("height:", height)
}
}
But those event listeners will only print the height on the start and end of dragging/moving the flickable. So how do I achieve this?
I believe Flickable.contentXChanged and Flickable.contentYChanged signals are what you need.
Flickable.draggingChanged is emitted only when drag is starting and ending.
Flickable.movingChanged is emitted only when Flickable starts and ends moving.
Flickable.contentXChanged is emitted every time content is being moved horizontally.
Flickable.contentYChanged is emitted every time content is being moved vertically.
Also Text.textChanged is emitted every time text changes.

QML: button with image and text underneath

I am trying to create a button like control in QML which displays an image and also some text under it. My current attempt stands as follows:
Item {
id: button
width: 30
height: 100
property alias text: buttontext
signal clicked
Image {
id: visualImage
anchors.fill: parent
source: "qrc:/images/test.png"
}
Text {
id: buttontext
font.bold: true
text: "Test"
}
}
This has a lot of problems unfortunately. So, at the moment, I am specifying the width and height of the item but this should be calculated based on the width and height of the image and the text. Also, the text is shown at the top and inside the image where I would like to position the text under the image, centered with image horizontally with some margins.
You must use anchors in the Image and in the Text. Example:
Item {
id: button
width: 30
height: 100
property alias text: buttontext
signal clicked
Image {
id: visualImage
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: buttontext.top
source: "qrc:/images/test.png"
}
Text {
id: buttontext
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
font.bold: true
text: "Test"
}
}
Since QtQuick.Controls 2.3 (Qt 5.10), display property was introduced:
This property determines how the icon and text are displayed within the button.
For your case it's AbstractButton.TextUnderIcon
Something I have done in the past as a workaround for this,
create a Rectangle{……} which holds all the 'Button' items, (Text/Image Ect),
It may not be the prettiest way but there is a few variations
Create the 'Image' and 'text' externally (photoshop whatever you choose) then fill your Rectangle with the content, then also set a MouseArea { onClicked {……}} event to that,
Make a Column/Grid/Row within the Rectangle and position your items using that method

How to stop ListView for "jumping" when model is changed

What I need to do: I need to create a chat window using a ListView in QML that stores the chat-messages. I set listView.positionViewAtEnd() in order to follow the last messages. I disable positionViewAtEnd when I scroll upwards such that I can read the past messages without jumping at the end every time I receive a new message.
The problem: After scrolling up, every time I receive a new message it jumps at the beginning of list. To solve that I manage to store the contentY of the list and reset it every time onCountChanged handler is called (see the code below):
ListView {
id: messagesList
model: contact? contact.messages: []
delegate: delegate
anchors.fill: parent
anchors.bottomMargin: 20
height: parent.height
anchors.margins: 10
property int currentContentY
onMovementEnded: {
currentContentY = contentY
}
onCountChanged: {
contentY = currentContentY
}
onContentYChanged: {
console.log(".....contentY: " + contentY)
}
}
The problem is that even though I set the last contentY I had, before the model was changed, the list still jumps a bit (several pixels, not at the end or beginning) and it doesn't jump always. And when I go to the top of the list and print the contentY I get negative values. Theoretically, contentY at the beginning of the list should be 0.
Can somebody tell me what is going wrong? Or maybe suggest another solution to create my message list?
Than you in advance! :)
One possible solution schould be insert ListView into Flickable and disable interactive flag for ListView
Flickable {
id: fparent
anchors.fill: parent
anchors.bottomMargin: 20
anchors.margins: 10
interactive: true
clip: true
flickableDirection: Flickable.VerticalFlick
contentHeight: messagesList.height
ListView {
id: messagesList
width: parent.width
height: childrenRect.height
clip: true
model: contact? contact.messages: []
delegate: delegate
interactive: false
onCountChanged: {
fparents.returnToBounds();
}
}
}
Why not use onCountChanged slot in order to set the ListView at the end ?
onCountChanged: {
messagesList.positionViewAtEnd()
}

Resources