Best way to add space around a ColumnLayout? - qt

I like that there is a spacing property to add space between items in a layout. But is it also possible to add space around a layout?
See my code below. I try to use anchors.margins on the ColumnLayout but that does not work.
Rectangle {
id: leftSelectionRect
anchors.top: parent.top
anchors.right: leftLine.left
implicitWidth: leftSelectionLayout.implicitWidth
implicitHeight: leftSelectionLayout.implicitHeight
color: CustomProperties.Colors.transparentSelectionBackground
ColumnLayout {
id: leftSelectionLayout
spacing: CustomProperties.Margins.small
anchors.margins: CustomProperties.Margins.small // This is what I would like to do, but it does not work.
CustomComponents.HeaderText {
id: leftText
text: Converter.formatDuration(ui.selectionModel.startUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
CustomComponents.HeaderText {
id: leftdeltaText
text: "Δ " + Converter.formatDuration(ui.selectionModel.deltaUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
}
}
EDIT
The following is the first attempt I have made that works, but it is messy. There must be a better way:
Rectangle {
id: leftSelectionRect
anchors.top: parent.top
anchors.right: leftLine.left
implicitWidth: leftSelectionLayout.implicitWidth + CustomProperties.Margins.medium * 2
implicitHeight: leftSelectionLayout.implicitHeight + CustomProperties.Margins.small * 2
color: CustomProperties.Colors.transparentSelectionBackground
ColumnLayout {
id: leftSelectionLayout
spacing: CustomProperties.Margins.small
anchors.topMargin: CustomProperties.Margins.small
anchors.bottomMargin: CustomProperties.Margins.small
anchors.leftMargin: CustomProperties.Margins.medium
anchors.rightMargin: CustomProperties.Margins.medium
anchors.fill: parent
CustomComponents.HeaderText {
id: leftText
text: Converter.formatDuration(ui.selectionModel.startUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
CustomComponents.HeaderText {
id: leftdeltaText
text: "Δ " + Converter.formatDuration(ui.selectionModel.deltaUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
}
}

Do not add anchors.fill:parent to your inner ColumnLayout but to your outer wrapper component:
Item {
anchors.fill: parent
anchors.margins: 10
ColumnLayout {
id: layout
width: parent.width
spacing: 10
Rectangle {
color: "red"
Layout.preferredHeight: 100
Layout.preferredWidth: parent.width
}
Rectangle {
color: "blue"
Layout.preferredHeight: 100
Layout.preferredWidth: parent.width
}
Rectangle {
color: "green"
Layout.preferredHeight: 100
Layout.preferredWidth: parent.width
}
}
}
At all you should avoid setting height property or anchors.top AND anchors.bottom properties to your ColumnLayout because it calculates its height at its own.

Related

QML - SpinBox - Data validation

I have the following SpinBox model which I am trying to recreate using the new QtQuick.Control 2, because this one it's using version 1. And I've encountered some problems which I am not sure how to solve.
On the validation side, I should not be able to write anything on the suffix side, just on the number part. Also I should not be allowed to remote the suffix from there while editing
My width should be fixed and I should not be allowed to write more than that.
My Code:
import QtQuick 2.6
import QtQuick.Controls 2
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
SpinBox {
id: root
property color borderColor: "red"
property string multipleValuesTooltip: ""
property color backgroundColor: "yellow"
property bool showTooltip: true
font.pointSize: 10
property int maximumValue: 50
property int minimumValue: 0
property string suffix: ""
property int decimals: 0
to: maximumValue
from: minimumValue
editable: true
rightPadding: {
console.log(root.contentItem.height)
return Math.max(40, Math.round(root.contentItem.height))
}
textFromValue: function(value, locale) {
return qsTr("%1"+suffix).arg(value);
}
contentItem: TextInput {
z: 5
text: root.textFromValue(root.value, root.locale)
font: root.font
color: "white"
selectionColor: "#21be2b"
selectedTextColor: "#ffffff"
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
validator: root.validator
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
up.indicator: Rectangle {
height: parent.height / 2
anchors.right: parent.right
anchors.top: parent.top
implicitWidth: 20 // Adjust width here
implicitHeight: {
console.log(root.contentItem.height)
return root.contentItem.height - 10
}
color: root.up.pressed ? "red" : "pink"
Image {
source: "qrc:/resources/arrow-down.png"
height: Math.min(15, sourceSize.height)
width: Math.min(30, sourceSize.width)
anchors.centerIn: parent
rotation: 180
}
}
down.indicator: Rectangle {
height: parent.height / 2
anchors.right: parent.right
anchors.bottom: parent.bottom
implicitHeight: root.contentItem.height - 10
implicitWidth: {
console.log("W: ",root.width)
return 20
}
color: root.down.pressed ? "red" : "pink"
Image {
source: "qrc:/resources/arrow-down.png"
height: Math.min(15, sourceSize.height)
width: Math.min(30, sourceSize.width)
anchors.centerIn: parent
}
}
background: Item {
implicitHeight: root.height === 0 ? Math.max(30, Math.round(root.contentItem.height * 1.2)) : root.height
implicitWidth: root.contentItem.width + leftPadding +rightPadding
baselineOffset: root.anchors.baselineOffset
Rectangle {
id: baserect
anchors.fill: parent
color: "purple"
radius: 3
}
Rectangle { // Border only
anchors.fill: parent
border.color: "black"
color: "transparent"
radius: 3
}
Rectangle {
anchors.right: parent.right
anchors.rightMargin: root.rightPadding - 10
anchors.verticalCenter: parent.verticalCenter
color: "black"
height: parent.height - parent.height/5
width: 1
}
}
}
I couldn't find any documentation or any kind of information regarding this wherever I've searched for. If any of you could help me I would be really grateful.

QML ScrollBar combined with ListView

I'm new to QML and QT so don't blame me if this question is going to sound stupid for most of you but I've search all over the internet without any luck in founding an answer.
What I'm trying to do:
I'm having a ScrollView which has inside of it a ScrollBar and a ListView.
I want that at the moment when I'm scrolling the ListView elements to also move the bar from ScrollBar. In other words, I want to use the ScrollBar as an overall view of your current position, you are not supposed to touch that, its only purpose is for viewing.
My Code:
ScrollView{
implicitHeight: 100
implicitWidth: 50
anchors.fill: parent
ScrollBar.horizontal: ScrollBar{
id: hbar
active: true
policy: ScrollBar.AlwaysOn
anchors {
left: parent.left
top: parent.top
right: parent.right
}
background: Rectangle {
implicitWidth: 100
implicitHeight: 50
opacity: enabled ? 1 : 0.3
color: hbar.down ? "#red" : "black"
}
contentItem: Rectangle {
implicitWidth: 6
implicitHeight: 100
radius: width / 2
color: hbar.pressed ? "#81e889" : "#c2f4c6"
}
}
ListView {
id: listViewParent
height: listViewID.height/10*6
contentHeight: height*2
contentWidth: width*2
clip: false
interactive: false
keyNavigationWraps: true
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
enabled: true
scale: 1
transformOrigin: Item.Center
anchors.verticalCenter: parent.verticalCenter
boundsBehavior: Flickable.DragAndOvershootBounds
flickableDirection: Flickable.HorizontalFlick
highlightMoveDuration: 0
cacheBuffer: 300
snapMode: ListView.SnapToItem
layoutDirection: Qt.LeftToRight
orientation: ListView.Vertical
model: 1
delegate:
ListView {
width: parent.width;
height: parent.height;
spacing: listViewID.width/8/9
model: MovieListModel {}
orientation: ListView.Horizontal
id: listid
delegate:
Rectangle {
property int recDynamicHeight: listViewID.height/10*6
property int recOriginalHeight: listViewID.height/10*6
property int recDynamiclWidth: listViewID.width/7
property int recOriginalWidth: listViewID.width/7
id: rectPer
width: recDynamiclWidth
height: recDynamicHeight
Image {
id: image1
anchors.fill: parent;
source: model.imgUrl
}
Text {
property bool isVisible: false
color: "#ffffff"
anchors.fill: parent
visible: textid.isVisible
id: textid
text: model.title
font.bold: true
horizontalAlignment: Text.AlignLeft
font.pixelSize: listViewID.width/8/9
topPadding: listViewID.width/8/9
leftPadding: listViewID.width/8/9
}
Text {
anchors.topMargin: listViewID.width/8/9
color: "#ffffff"
anchors.fill: parent
visible: textid.isVisible
id: yearId
text: model.year
horizontalAlignment: Text.AlignLeft
font.pixelSize: listViewID.width/8/9
topPadding: listViewID.width/8/9*2
leftPadding: listViewID.width/8/9
}
MouseArea {
anchors.fill: parent
onPressed: {
rectPer.recDynamicHeight = rectPer.recOriginalHeight;
rectPer.recDynamicHeight += rectPer.recOriginalHeight/10;
rectPer.recDynamiclWidth += rectPer.recOriginalWidth/10;
console.log(textid.isVisible);
textid.isVisible = true;
textid.visible = textid.isVisible;
console.log(sideButtonID.x);
console.log(sideButtonID.y);
console.log(model.year + " clicked");
}
onClicked: {
console.log("INDEX: " + model.id)
load_page(PageType.movie_detailed_view, model.title, model.description, model.imgUrl, model.type, model.year)
}
onReleased: {
rectPer.recDynamicHeight = rectPer.recOriginalHeight;
rectPer.recDynamiclWidth = rectPer.recOriginalWidth;
textid.isVisible = false;
textid.visible = textid.isVisible;
}
}
}
}
}
}
Layout:
You could try use a Flickable instead of a ScrollView and spawn a ListView there(delegates: Rectangles). Then, spawn the Scrollbar inside the ListView

How can I change the anchors of an item to attach it to the right or left of another item based on a condition?

The layout below works. I am showing it as reference. startSelectionRect is always anchored to the left of a line as I have intended.
Rectangle {
id: startLine
x: ui.selectionModel.startPixel
width: 1
height: parent.height
color: QQProperties.Colors.text
}
Rectangle {
id: startSelectionRect
color: QQProperties.Colors.transparentSelectionBackground
anchors.top: parent.top
anchors.right: startLine.left
implicitHeight: startSelectionLayout.implicitHeight + QQProperties.Margins.small * 2
implicitWidth: startSelectionLayout.implicitWidth + QQProperties.Margins.medium * 2
ColumnLayout {
id: startSelectionLayout
spacing: QQProperties.Margins.small
anchors.topMargin: QQProperties.Margins.small
anchors.bottomMargin: QQProperties.Margins.small
anchors.leftMargin: QQProperties.Margins.medium
anchors.rightMargin: QQProperties.Margins.medium
anchors.fill: parent
QQComponents.HeaderText {
id: startText
text: Converter.formatDuration(ui.selectionModel.startUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
}
}
Here I try to anchor startSelectionRect to the right or left of a line based on a condition.
function selectionFromLowestBound() {
console.log("selectionStartingOnLowestBound: ", ui.selectionModel.startPixel === ui.selectionModel.lowerBoundaryPixel);
return ui.selectionModel.startPixel === ui.selectionModel.lowerBoundaryPixel;
}
Rectangle {
id: startLine
x: ui.selectionModel.startPixel
width: 1
height: parent.height
color: QQProperties.Colors.text
}
Rectangle {
id: startSelectionRect
color: QQProperties.Colors.transparentSelectionBackground
anchors.top: parent.top
anchors.right: selectionFromLowestBound() ? startLine.left : undefined
anchors.left: !selectionFromLowestBound() ? startLine.right : undefined
implicitHeight: startSelectionLayout.implicitHeight + QQProperties.Margins.small * 2
implicitWidth: startSelectionLayout.implicitWidth + QQProperties.Margins.medium * 2
ColumnLayout {
id: startSelectionLayout
spacing: QQProperties.Margins.small
anchors.topMargin: QQProperties.Margins.small
anchors.bottomMargin: QQProperties.Margins.small
anchors.leftMargin: QQProperties.Margins.medium
anchors.rightMargin: QQProperties.Margins.medium
anchors.fill: parent
QQComponents.HeaderText {
id: startText
text: Converter.formatDuration(ui.selectionModel.startUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
}
}
I can see with console.log that the condition is evaluated and that it is sometimes true and sometimes false. But startSelectionRect is always anchored to the right of the line. And startSelectionRect has lost its background color.
What am I doing wrong?
EDIT:
Here I am trying to follow the answer by Amfasis, but am failing thus far.
function selectionFromLowestBound() {
return ui.selectionModel.startPixel === ui.selectionModel.lowerBoundaryPixel;
}
Rectangle {
id: startLine
x: ui.selectionModel.startPixel
width: 1
height: parent.height
color: QQProperties.Colors.text
}
Rectangle {
id: startSelectionRect
color: QQProperties.Colors.transparentSelectionBackground
anchors.top: parent.top
implicitHeight: startSelectionLayout.implicitHeight + QQProperties.Margins.small * 2
implicitWidth: startSelectionLayout.implicitWidth + QQProperties.Margins.medium * 2
states: [
State {
name: "lowerBound"
when: selectionFromLowestBound()
PropertyChanges {
target: startSelectionRect
anchors.right: startLine.left
}
},
State {
name: "upperBound"
when: !selectionFromLowestBound()
PropertyChanges {
target: startSelectionRect
anchors.left: startLine.right
}
}
]
ColumnLayout {
id: startSelectionLayout
spacing: QQProperties.Margins.small
anchors.topMargin: QQProperties.Margins.small
anchors.bottomMargin: QQProperties.Margins.small
anchors.leftMargin: QQProperties.Margins.medium
anchors.rightMargin: QQProperties.Margins.medium
anchors.fill: parent
QQComponents.HeaderText {
id: startText
text: Converter.formatDuration(ui.selectionModel.startUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
}
}
You can add states to a QML item in which it is also possible to set different anchors. See the following example:
Rectangle {
id: rect
property bool left : true
states: [
State {
name: "left"
when: rect.left
PropertyChanges {
target: rect
anchors.left: parent.right
}
},
State {
name: "right"
when: !rect.left
PropertyChanges {
target: rect
anchors.right: parent.left //note switched with above ;-)
}
}
]
}

How to stop item from affecting size of parent when hidden?

When the rightDeltaText item is hidden it still seems to be affecting the height of its parent.
How can I make it not affect the height of its parent?
Rectangle {
id: rightSelectionRect
anchors.top: parent.top
anchors.left: rightLine.right
implicitWidth: leftSelectionLayout.implicitWidth + CustomProperties.Margins.medium * 2
implicitHeight: leftSelectionLayout.implicitHeight + CustomProperties.Margins.small * 2
color: CustomProperties.Colors.transparentSelectionBackground
ColumnLayout {
id: rightSelectionLayout
spacing: CustomProperties.Margins.small
anchors.topMargin: CustomProperties.Margins.small
anchors.bottomMargin: CustomProperties.Margins.small
anchors.leftMargin: CustomProperties.Margins.medium
anchors.rightMargin: CustomProperties.Margins.medium
anchors.fill: parent
CustomComponents.HeaderText {
id: rightText
text: Converter.formatDuration(ui.selectionModel.endUs, Converter.MicroSeconds, Converter.MicroSeconds)
}
CustomComponents.HeaderText {
id: rightdeltaText
text: "Δ " + Converter.formatDuration(ui.selectionModel.deltaUs, Converter.MicroSeconds, Converter.MicroSeconds)
visible: ui.selectionModel.startingOnSmallestValueUs
}
}
}

Qml Text Size based on Container

I am using Qt Quick to develop an app (Qt 5.8). I have text that appears in multiple places so I created a component to use to display the text. The areas the text can vary in placement and size. How can I adjust my text so that the data displays in 1 line horizontally and all text is the same size if I simply want to display the following?
FLAPS 1
GEAR DOWN
TRIM -1.0
I used Text and was able to get close, however since GEAR DOWN has more characters the text was smaller, than flaps and trim. So I moved on to using Label. Can someone provide better insight on how to have text size based on its container's width or height?
main.qml
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
id: windowRoot
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
height: windowRoot.height * .80
width: windowRoot.width * .80
color: "green"
anchors.centerIn: parent
Rectangle {
id: rect1
opacity: .5
anchors.top: parent.top
anchors.left: parent.left
color: "lime"
border.color: "orange"
height: parent.height * 1/2
width: parent.width * 1/2
TextHolder {
anchors.top: parent.top
anchors.left: parent.left
width: parent.width * 1/4
height: parent.height
}
}
Rectangle {
id: rect2
anchors.top: parent.top
anchors.left: rect1.right
color: "yellow"
border.color: "blue"
height: parent.height * 1/2
width: parent.width * 1/2
}
Rectangle {
id: rect3
anchors.top: rect1.bottom
anchors.left: parent.left
color: "pink"
border.color: "red"
height: parent.height * 1/2
width: parent.width * 1/2
TextHolder {
anchors.top: parent.top
anchors.left: parent.left
width: parent.width * 1/4
height: parent.height * 1/2
}
}
Rectangle {
id: rect4
anchors.top: rect2.bottom
anchors.left: rect3.right
color: "orange"
border.color: "lime"
height: parent.height * 1/2
width: parent.width * 1/2
TextHolder {
anchors.bottom: parent.bottom
height: parent.height * 1/4
width: parent.width * 1/4
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
TextHolder.qml
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.1
Rectangle {
color: "purple"
border.color: "steelblue"
border.width: 3
property color colorOfText: "white"
property real textSize: 48
Item {
id: inputs
property int flapHndl: 1
property int gearHndl: 1
property real trim: -1.0
}
clip: true
ColumnLayout {
anchors.top: parent.top
width: parent.width
height: parent.height
spacing: 5
Label {
id: flapLabel
text: "FLAPS " + inputs.flapHndl
color: colorOfText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: textSize
fontSizeMode: Text.HorizontalFit
Layout.fillWidth: true
}
Label {
id: gearLabel
text: {
if (inputs.gearHndl === 1)
return "GEAR DOWN"
else
return "GEAR UP"
}
color: colorOfText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: textSize
fontSizeMode: Text.HorizontalFit
Layout.fillWidth: true
}
Label {
id: trimLabel
text: "TRIM " + inputs.trim.toFixed(1)
color: colorOfText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: textSize
fontSizeMode: Text.HorizontalFit
Layout.fillWidth: true
}
}
}
Can someone provide better insight on how to have text size based on
its container's width or height?
For evaluating the text width and height we can definitely use QML type TextMetrics and having the metrics we can then attempt to fit the text in. If the text still won't fit we can then try to adjust the font size. For that, some logic might need to be implemented with JavaScript. So, the below code is an example of the "feedback" type of solution.
Rectangle {
property string textToShow
property int widthLimit: 400
onTextToShowChanged: {
while (txtMeter.width > widthLimit) {
txtMeter.font.pixelSize --;
}
}
TextMetrics {
id: txtMeter
font.family: "Courier"
font.pixelSize: 25
text: textToShow
}
Text {
font: txtMeter.font
text: textToShow
}
}
P.S. This is just a sketchy idea and your actual implementation may differ
There is fontSizeMode property of Text
Text {
id: goToParentFolderText
anchors.fill: parent
font.family: fontAwesomeSolid.name
text: "\uf060"
fontSizeMode: Text.Fit
font.pointSize: 100
color: Material.accent
}
I was able to get #Alexander V's answer to work, with a minor change. The outer textToShow property was processing its update before the TextMetrics block was updated (which caused the width calculation to be incorrect). You can fix this issue by triggering onTextChanged inside the TextMetrics blocks instead.
Rectangle {
property string textToShow
property int widthLimit: 400
TextMetrics {
id: txtMeter
font.family: "Courier"
font.pixelSize: 25
text: textToShow
onTextChanged: {
while (txtMeter.width > widthLimit) {
txtMeter.font.pixelSize --;
}
}
}
Text {
font: txtMeter.font
text: textToShow
}
}

Resources