Label word wrap in RowLayout with other elements - qt

I have two elements inside of a RowLayout, which I'm trying to fit within the boundaries of my window.
Page {
id: settingsView
anchors.fill: parent
ColumnLayout {
Layout.fillWidth: true
RowLayout {
Layout.fillWidth: true
Label {
text: "This is some long sample text which will definitely be wider than the page width."
padding: 6
Layout.maximumWidth: parent.width - timeComboBox.width
verticalAlignment: timeComboBox.height * 0.5
wrapMode: Label.WordWrap
}
ComboBox {
id: timeComboBox
model: ["1", "2", "3"]
}
}
}
}
This page gets pushed onto a StackView(the StackView also anchors.fill: parent), but no matter what I do, I cannot make it so that the Label text gets wrapped, and the ComboBox ends up half outside the window boundaries.

You have several problem points, I've correct them a bit:
Page {
id: settingsView
anchors.fill: parent
ColumnLayout {
width: parent.width // this item is not inside Layout so can't have Layout.* attached properties
RowLayout {
Layout.fillWidth: true
Label {
text: "This is some long sample text which will definitely be wider than the page width."
padding: 10
Layout.fillWidth: true // just fill all the space except the ComboBox
verticalAlignment: Text.AlignVCenter // that should be enum, not numerical value
wrapMode: Text.WordWrap // this is Text.* emum, not Label's one
}
ComboBox {
id: timeComboBox
model: ["1", "2", "3"]
}
}
}
}

It turns out that the answer was quite simple, all I had to do was remove Layout.maximumWidth: parent.width - timeComboBox.width and replace it with Layout.fillWidth: true

Related

QML: Current Index / Item is changin if swipeview is populated using a loader or repater inside a asyncronous parent Loader

Dynamic loading data into a QML SwipeView loaded asyncronous is autmomatically increment the current index.
Loader{
asynchronous: true
anchors.fill: parent
sourceComponent: ColumnLayout{
//Any content here that can take some time to load
TabBar{
Layout.fillWidth: true
Repeater{
model: swRepeater.model
delegate: TabButton{
text: "Tab button "+index
}
}
}
SwipeView{
// anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
currentIndex: 0
Repeater{
id: swRepeater
model: 5
delegate: Item{
Label{
anchors.centerIn: parent
text: qsTr("Test "+index)
}
}
}
onCurrentIndexChanged: {
console.debug("Index was modified to ",currentIndex)
}
}
}
}
At the end of the loading data the current item and index will be 4, and not 0 as explected.
Also is displayed the last item from stack.
The same behavior can be se on the TabBar item so the problem looks to came from ListView or Container.
Any suggestion on this behavior?

How to show Images In a row using repeater in qml?

so i have to show 9 images on my page, so I have used repeater, but the problem is that I want to show the images in a row, but in out put it shows in a column. I am working on a mobile application using qml. So can anybody suggest me how to show it in a row format using qml?
Here is my code
ColumnLayout {
spacing: 10
clip:true
Repeater{
model: 9
Row{
id:icons
spacing:30
Layout.alignment: Qt.AlignHCenter
Image {
id: img1
source:"path to images"
height: 50
width:50
}
}
}
}
Replace ColumnLayout with RowLayout and use modelData property.
RowLayout {
anchors.fill: parent
Repeater{
model: ["img1.png", "img2.png"]
Image {
Layout.preferredWidth: 50
Layout.preferredHeight: 50
source: modelData
}
}
}

Qml, update gridview inside listview item

I have a listview in which, each item has gridview inside it:
ListView{
id:list_roi
anchors.fill: parent
delegate: roi_item_view
model: roi_item_model
spacing: 5
clip: true
focus: true
ScrollBar.vertical: ScrollBar {}
onCurrentIndexChanged: {
valueUpdater.selected_roi_changed(list_roi.currentIndex)
}
highlight: Rectangle {
color: 'lightgray'
}
}
ListModel{
id:roi_item_model
ListElement {roi_rows: 2, roi_cols: 2, roi_subregion_model : [{_text:"555.3"},{_text:"555.3"},{_text:"555.3"}]}
}
Component{
id:roi_item_view
MouseArea {
anchors.fill: parent
onClicked: list_roi.currentIndex = index
}
GridLayout{
id:layout_wrapper
anchors.fill: parent
rows: 3
columns: 5
GridView {
id:grid_sub_region
Layout.row: 2
Layout.column: 0
Layout.columnSpan:5
Layout.alignment: Qt.AlignHCenter
width: roi_cols * 30; height: roi_rows * 30
cellWidth: 30; cellHeight: 30
visible : true
model: roi_subregion_model
delegate: contactsDelegate
focus: true
}
Component {
id: contactsDelegate
CellBox{
id: wrapper
width: 30
height: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
id: contactInfo
text: _text
}
}
}
}
}
as you can see, inside model i have 3 property (roi_rows, roi_cols, roi_subregion_model) which are supposed to change the view of Gridview's rows, columns and data inside each cell, when i change them.
but when i change these values, number of cells inside Gridview does not changes. when i initialize roi_rows and toi_cols to 2 i will have 2x2 gridview after listview item is created. but after initialization i cannot change it. it seems i have to do something to refresh the UI of specific item inside Listview so that the Gridview inside that item will be redrawn.
Update
based on comments: width and height of the GridView will be set based on roi_rows, roi_cols which are part of Listview Model. and because the CellWidth and CellHeight are constant then number of cells (rows and columns of the Gridview) will be changed.
OK i found the answer. in Model,View,Delegate structure when we create a Delegate and want to bind it with a key inside Model, in some cases like 'text' for 'Label' it will be automatically bound automatically. in this example:
ListModel{
id:roi_item_model
ListElement {label_text:"Hello" ,roi_rows: 2, roi_cols: 2, roi_subregion_model : [{_text:"555.3"},{_text:"555.3"},{_text:"555.3"}]}
}
Component{
id:roi_item_view
MouseArea {
anchors.fill: parent
onClicked: list_roi.currentIndex = index
}
GridLayout{
id:layout_wrapper
anchors.fill: parent
rows: 3
columns: 5
Label{ text:label_text }
GridView {
id:grid_sub_region
Layout.row: 2
Layout.column: 0
Layout.columnSpan:5
Layout.alignment: Qt.AlignHCenter
width: roi_cols * 30; height: roi_rows * 30
cellWidth: 30; cellHeight: 30
visible : true
model: roi_subregion_model
delegate: contactsDelegate
focus: true
}
Component {
id: contactsDelegate
CellBox{
id: wrapper
width: 30
height: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
id: contactInfo
text: _text
}
}
}
}
}
label_text inside Model will be bound to text property of Label automatically which means if i change label_text the content of Label will be changed automatically. but for some property we should do this binding manually. in out example add this to delegate of ListView:
Binding {
target: grid_sub_region
property: 'height'
value: roi_rows * 30
}
Binding {
target: grid_sub_region
property: 'width'
value: roi_cols * 30
}

QML: Is there Grid Layout's signal "onChildren's initial resizing ended"

In Qml GridLayout with Repeater in it firstly creates items with zero x,y coordinates, width and height. After it emits Component.onComleted signal. And then moves items to correct coordinates, then resizes them.
GridLayout {
id: inputPanel
property var tableModel
rowSpacing: 0
columnSpacing: 0
Repeater {
model: inputPanel.tableModel
delegate: KeyButton {
displayedText: model.display
Layout.minimumHeight: tableModel.elementSize.height
Layout.minimumWidth: tableModel.elementSize.width
Layout.maximumHeight: tableModel.elementSize.height
Layout.maximumWidth: tableModel.elementSize.width
Layout.alignment: Qt.AlignCenter
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
Keybutton.qml
Item {
id: keyButton
anchors.margins: 2.5
Rectangle {
anchors.fill: parent
}
}
Is there any way to catch a moment, when KeyButtons already will have correct x, y, width, height. (KeyButton.onXChanged is not best way, because it emits, when Grid Layout's size changes too)

How to implement Master Details View in Qt/QML (part 2)

I previously asked how to implement a Master Details View in Qt/QML here: How to implement a master-details view Qt/QML on an Android tablet?.
Having continued working on this, I came out with the following mockup QML layout:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 1.4
Item {
y: 50
Layout.fillHeight: true
width: appWindow.width
RowLayout {
id: mainLayout
anchors.fill: parent
ListModel {
id: navigation
ListElement {
item: "Item 1"
}
ListElement {
item: "Item 2"
}
ListElement {
item: "Item 3"
}
ListElement {
item: "Item 4"
}
ListElement {
item: "Item 5"
}
ListElement {
item: "Item 6"
}
ListElement {
item: "Item 7"
}
ListElement {
item: "Item 8"
}
ListElement {
item: "Item 9"
}
ListElement {
item: "Item 10"
}
ListElement {
item: "Item 11"
}
}
ScrollView{
Layout.fillHeight: true
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
ListView {
id: listview
Layout.fillHeight: true
Layout.preferredWidth: 300
contentWidth: 300
model: navigation
delegate: Rectangle {
id: wrapper
width: 300
height: 50
Text {
id: itemInfo
text: item
color: "red"
}
}
}
}
Rectangle {
x: 300
y: 50
Layout.preferredWidth: appWindow.width - listview.width-4
height: appWindow.height - 50
color: "green"
border.width: 1
}
}
}
The master view is essentially a ListView with a number of items (each item represents a selectable element, which will trigger an update of the details view, which is currently represented by the green rectangle (see attached screenshot below)
At the moment I am still having a couple of issues with the following points:
How should I modify the Layout so that the ListView covers the entire screen height?
When I "scroll" through the ListView, I have noticed a lot of screen flickering? How can I minimize this?
How can I prevent the entire upper status bar (where device system information such as battery charge is shown) from being displayed?
Edit: Modified the code by adding the ListView in a ScrollView. In this case, the ScrollView's height is the same as the screen height, which is also what I wanted (minus a 50 offset at the top, see Figure below). I think that the ListView is behaving as expected and not occupying more space that its items.
What needs to be achieved now is to change the Background color of the SrollView so that it matches the ListView color. In that case it will appear as if the ListView is occupying the entire space.
In order to hide the status bar, the easiest thing to do is to specify a theme and apply it in the manifest file. Other solutions require modifying the activity and such.
In yourApp/android/res/values create a theme.xml with the following content:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="#android:style/Theme.DeviceDefault.Light.NoActionBar">
</style>
</resources>
Then in the manifest, on the same line where you added the screen orientation, add the theme:
android:theme="#style/AppTheme"
And in your main window use Window.FullScreen visibility instead of maximized.
For the layouting, it appears you could do with less. There is nothing wrong with Layout, just IMO it is more suited to standard scalable "micro" GUI elements like buttons and such rather than custom macro elements. Here is a condensed but functional example:
Row {
anchors.fill: parent
ListView {
id: lv
width: 200
height: parent.height
model: 30
delegate: Rectangle {
width: 200
height: 50
color: index == lv.currentIndex ? "lightgray" : "white"
Text {
text: "item " + index
color: "red"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: lv.currentIndex = index
}
}
Rectangle {
anchors.right: parent.right
width: 5
height: parent.height * parent.visibleArea.heightRatio
color: "grey"
y: parent.height * parent.visibleArea.yPosition
}
}
Rectangle {
width: parent.width - lv.width
height: parent.height
color: "green"
Text {
anchors.centerIn: parent
text: "selected item n" + lv.currentIndex
color: "white"
font.pointSize: 15
}
}
}
The result:
Although it is not exactly clear the reason you offset things vertically, if you want to have the free space at the top, simply don't fill the entire parent with the root Rowelement but rather size it accordingly.
I am a bit clueless, how it comes, that you consider the ScrollView to be needed.
I removed it from your example, added clipping to the ListView and I was done.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow
{
id: appWindow
width: 1024
height: 800
visible: true
Item {
y: 50
Layout.fillHeight: true
width: appWindow.width
RowLayout {
id: mainLayout
anchors.fill: parent
ListModel {
id: navigation
ListElement { item: "Item 1" }
Component.onCompleted: {
for (var i = 2; i < 50; i++) append({ item: 'Item' + i })
}
}
ListView {
id: listview
Layout.fillHeight: true
Layout.preferredWidth: 300
contentWidth: 300
model: navigation
clip: true //<--- Add this, so there won't be no elements outside the ListView-area
delegate: Rectangle {
id: wrapper
width: 300
height: 50
Text {
id: itemInfo
text: item
color: "red"
}
}
}
Rectangle {
x: 300
y: 50
Layout.preferredWidth: appWindow.width - listview.width-4
height: appWindow.height - 50
color: "green"
border.width: 1
}
}
}
}
There are a few things you might misunderstand:
The ListView provides no background. If you want such, you need to draw something behind it, e.g. a Rectangle
The ListView does not provide ScrollBars by itself. You need to add them like this:
ScrollBar.vertical: ScrollBar { }
The ScrollBar has no native style. And the handle will disapear by default. You can find more than one question here, on how to style a ScrollBar.
If you don't clip the ListView you will see some elements protruding the ListView and suddenly disappear. If you have nothing that covers this anyway, you should set clip: true
For your ListView to take all the height, you can simply set it to fill the height of the layout. However make sure the Layout (and its parent in your case) have the right size too. Size defaults to (0,0) for Item in QML.
ListView {
id: listview
//...
Layout.fillHeight: true
//...
}
Regarding the "flickering", you can try increasing the ListView cacheBuffer property, which corresponds to the content height, in pixels, which is preloaded. However if this is really flickering, there's probably little you can do.
Flickering appears when display is refreshed with the wrong timings regarding screen refresh rate, and typically solved by using multiple buffers and/or synchronization. QtQuick hides all this complexity and uses OpenGL for rendering, but I didn't saw (yet) any flickering on Android with recent Qt versions.
You can remove the status bar by editing the Android manifest file as explained in this other post, or worse case, through JNI.

Resources