Reputation: 4982
I'm trying to make a widget that has an image at the bottom, and text that populates from bottom-to-top. Here are three ASCII-art examples of the widget in action:
Text Line 3 ^
Text Line 4 |
Text Line 1 Text Line 5 |
Text Line 1 Text Line 2 Text Line 6 V
| ----------- | | ----------- | | ----------- |
| ----------- | | ----------- | | ----------- |
+-----------------+ +-----------------+ +-----------------+
| printer.svg | | printer.svg | | printer.svg |
+-----------------+ +-----------------+ +-----------------+
I'm having problems with the vertical spacing. It should be:
The objects needed are pretty clear:
ColumnLayout
+-- ScrollView
| +-- TextArea
+-- Image
But what combinations Layout alignments/heights/implicitHeights/contentHeights/anchors/position/policy can make this happen?
The closest I have gotten is below, and the commented-out stuff is what I've been brute-forcing.
import QtQuick 2.0
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.5
ColumnLayout {
width: parent.width
height: parent.height
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
ScrollView {
Layout.alignment: Qt.AlignBottom
Layout.maximumHeight: parent.height - rect.height
TextArea {
text:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eleifend non leo
a iaculis. Nam at tortor mollis, iaculis justo vel, dictum sapien. Vivamus sed
feugiat tortor, nec tempor nisi. Orci varius natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. Quisque vestibulum, eros id vehicula
eleifend, eros tellus iaculis lectus, sit amet molestie justo ex in nulla.
Maecenas at ultrices velit. Vestibulum eu libero tortor. Morbi ipsum lorem,
interdum sed aliquam quis, semper pretium ante. Duis et nibh ac tortor tincidunt
commodo. Vestibulum commodo nibh nisi, in lacinia lectus imperdiet vel. Class
aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
himenaeos.
Aliquam erat volutpat. Praesent eget erat a nisi vulputate euismod. Donec in
vulputate tellus, eget dapibus eros. Quisque nec lacus iaculis, venenatis ante
quis, tincidunt ligula. Donec aliquet diam sit amet nisl sollicitudin, et varius
arcu lobortis. Aliquam erat volutpat. Duis enim justo, fringilla egestas
volutpat et, efficitur id erat. Duis et ullamcorper leo. Maecenas ornare orci
purus, ac commodo sapien malesuada eget. In dapibus ex nec risus laoreet
fringilla. Donec maximus elit in elit aliquam, eget imperdiet mauris congue.
Nunc libero quam, fringilla et mauris sit amet, consectetur convallis augue. Sed
vitae hendrerit ex, ac sollicitudin nibh. Donec diam mi, placerat vitae
venenatis vitae, lacinia at urna."
}
}
Rectangle { // Image placeholder
id: rect
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
width: 300
height: 100
color: "red"
}
}
In this case, I am using anchors to force the ColumnLayout to fill its container. Then, things like Layout.alignment: Qt.AlignBottom
behave well. I found that if I don't specify ScrollView{ Layout.maximumHeight: }
, then the scroll bar doesn't appear.
It works well in the online sandbox I'm playing in, but in practice it fails miserably That's because this widget is contained in a StackLayout
. When I try to include my widget in the project, I get:
QML ColumnLayout: Detected anchors on an item that is managed by a layout. This is undefined behaviour; use Layout.alignment instead.
So I've tried combinations of these lines:
ColumnLayout {
Layout.alignment: Qt.AlignBottom
height: parent.height
But neither line had any effect. I think that's because the parent deduces its size from its children.
I'd prefer not to change the rest of the application, but if I reduce the rest of the application to parent components and properties, I get something that looks like this. Is it even possible for me to write a bottom-to-top widget in an application like this?
ApplicationWindow {
readonly property int base_width: 1920
readonly property int base_height: 1080
id: mainApplication
width: base_width*4/5
height: base_height*4/5
Rectangle {
id: iosMain
anchors.fill: parent
StackLayout
{
id: stackLayout
anchors.left: menuButtonsLayout.right
anchors.right: iosMain.right
anchors.top: iosMain.top
anchors.bottom: iosMain.bottom
Item {
id: pageRoot
Layout.fillWidth: false
Layout.fillHeight: false
transformOrigin: Item.TopLeft
width: childrenRect.width
height: childrenRect.height
RowLayout {
x: Style.pageLeftMargin
y: Style.pageTopMargin
StackLayout {
id: stackLayout
width: parent.width
currentIndex: 0
Layout.fillHeight: true
MyWidget{} // <-- This is where my widget lives
}
}
}
}
}
}
Upvotes: 0
Views: 309
Reputation: 3914
This is the solution I came up with, I hope it fits your needs. I basically wrapped the ScrollView
in an Item
in order to fill the hole upper ColumnLayout
cell via the attached property Layout.fillHeight
. Then I use the height
of the Item
to place the ScrollView
inside of it. First it is placed at the bottom until it grows bigger than the Item
.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Window {
id: root
width: 480
height: 320
visible: true
color: "white"
Timer {
interval: 500
running: true
repeat: true
onTriggered: {
textArea.text += "\nTip Tip Tip " + Date().toString()
// scroll to bottom when text was added
scrollView.ScrollBar.vertical.position = 1.0 - scrollView.ScrollBar.vertical.size
}
}
StackLayout {
anchors.fill: parent
currentIndex: 0
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Item {
id: frame
Layout.minimumWidth: 100
Layout.maximumWidth: 800
Layout.preferredWidth: image.paintedWidth
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
ScrollView {
id: scrollView
anchors.bottom: parent.bottom
width: parent.width
height: frame.height < scrollView.contentHeight ? frame.height : scrollView.contentHeight
TextArea {
id: textArea
color: "black"
text: "Typewriter Tip Tip Tip"
background: Rectangle {
border.color: "black"
}
}
}
}
Image {
id: image
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
Layout.fillWidth: true
Layout.minimumHeight: 100
Layout.maximumHeight: 400
source: "https://picsum.photos/300/100"
fillMode: Image.PreserveAspectFit
}
}
}
}
Upvotes: 2