I have a few questions about GridLayout in QtQuickLayouts 1.3:
How should I make it , so the GridLayout places into CORRECT row/column every element of my grid even if the size of the element is not clearly specified by with or height parameter?
Let me remove the width and height and I will show you the broken layout. I will just comment it out:
Item {
id: test_item
//Layout.fillWidth: true
//height: 20
}
Full source code of the .qml file is here, and can be tested with bin/qmlscene:
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
ApplicationWindow {
width: 400
height: 500;
ColumnLayout {
anchors.fill: parent
GridLayout {
anchors.fill: parent
columns: 2
Label {
text:"Email:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
Label {
text: "Full Name:"
Layout.fillWidth: true
}
Item {
id: test_item // the commented out portion, to show the flaw
//Layout.fillWidth: true
//height: 20
}
Label {
text: "Gender:"
}
RowLayout {
Layout.minimumHeight: 20
Layout.fillWidth: true
RadioButton {
text: "Male"
width: parent.width/2
height: 20
}
RadioButton {
text: "Female"
width: parent.width/2
height: 20
}
}
Label {
text: "Mobile phone:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
}
Row {
Button {
text: "Cancel"
}
Button {
text: " Ok "
}
}
}
}
The 'broken` output looks like this:
While the correct output , with Item's size specified looks like this:
2) The second question. How do I load a component into a GridLayout cell via Loader using Component type? For example, this is my full source with the Component item and the component is missing when rendering:
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
ApplicationWindow {
width: 400
height: 500;
ColumnLayout {
anchors.fill: parent
GridLayout {
anchors.fill: parent
columns: 2
Label {
text:"Email:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
Label {
text: "Full Name:"
Layout.fillWidth: true
}
Loader {
id: test_item
sourceComponent: field_template
}
Label {
text: "Gender:"
}
RowLayout {
Layout.minimumHeight: 20
Layout.fillWidth: true
RadioButton {
text: "Male"
width: parent.width/2
height: 20
}
RadioButton {
text: "Female"
width: parent.width/2
height: 20
}
}
Label {
text: "Mobile phone:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
}
Row {
Button {
text: "Cancel"
}
Button {
text: " Ok "
}
}
}
Component {
id: field_template
Item {
Layout.fillWidth: true
height: 33
Rectangle {
border.color: "blue"
color: "transparent"
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.rightMargin: 10
TextEdit {
anchors.fill: parent
anchors.leftMargin: 5
anchors.topMargin: 3
anchors.rightMargin: 2
clip: true
text: "type here"
}
}
}
}
}
The picture of the output rendered by qmlscene is this:
I have correctly speecified witdht and height, why isn't the component being loaded with Loader ?
For the second question folibis is right in the comment. You just have to check the size. Here, is a working code.
...
Item {
Layout.fillWidth: true
//width: 80
height:20
Loader {
id: test_item
anchors.fill: parent
sourceComponent: field_template
}
}
...
Component {
id: field_template
Item {
Rectangle {
border.color: "blue"
color: "transparent"
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.rightMargin: 10
TextEdit {
anchors.fill: parent
anchors.leftMargin: 5
anchors.topMargin: 3
anchors.rightMargin: 2
clip: true
text: "type here"
}
}
}
Related
Basically I want to display a text telling the user if a switch is turned on or off. The words "on" and "off" have a small background associated with them so I thought maybe making two labels would work. Now I have an issue where I'm hard coding the position of the second label, and it doesn't look clean because both of them are not centered. Here is the code:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.0
Window {
visible: true
width: 400
height: 400
property bool switchOn: false
Rectangle {
color: '#D3D3D3'
anchors.fill: parent
Label {
id: sentence
text: qsTr("The switch is currently turned ")
color: 'black'
width: parent.width
wrapMode: Text.Wrap
font.pixelSize: 40
anchors.top: parent.top
Label {
id: endText
text: switchOn ? qsTr(" off ") : qsTr(" on ")
font.pixelSize: 40
color: "white"
anchors {
top: parent.top
left: parent.left
topMargin: 50
leftMargin: 310
}
// #disable-check M16
background: Rectangle {
color: switchOn ? "grey" : "red"
radius: 8
}
}
}
Switch {
id: switch1
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 150
text: qsTr("Switch")
onToggled: switchOn = !switchOn
}
}
}
How can I have that sentence appear as one sentence and center it within a parent object?
EDIT:
Here I can get them in a row, but if my sentence ends on the second row and my first row is longer than the first, the ending text is placed way further than it needs to be:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.0
Window {
visible: true
width: 400
height: 400
property bool switchOn: false
Rectangle {
color: '#D3D3D3'
anchors.fill: parent
Row {
anchors.horizontalCenter: parent.horizontalCenter
Label {
id: sentence
text: qsTr("The switch is currently ")
color: 'black'
width: 300
wrapMode: Text.Wrap
font.pixelSize: 40
anchors.top: parent.top
}
Label {
id: endText
text: switchOn ? qsTr(" off ") : qsTr(" on ")
font.pixelSize: 40
color: "white"
anchors.top: sentence.top
anchors.topMargin: 45
// #disable-check M16
background: Rectangle {
color: switchOn ? "grey" : "red"
radius: 8
}
}
}
Switch {
id: switch1
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 150
text: qsTr("Switch")
onToggled: switchOn = !switchOn
}
}
}
You can do that by using the lineLaidOut signal of the Label. It gives you information about each line's geometry (you can also modify them if needed):
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.0
Window {
id: root
visible: true
width: 400
height: 400
property bool switchOn: false
Rectangle {
color: '#D3D3D3'
anchors.fill: parent
Label {
id: sentence
text: qsTr("The switch is currently ")
color: 'black'
anchors.horizontalCenter: parent.horizontalCenter
width: 300
wrapMode: Text.Wrap
font.pixelSize: 40
anchors.top: parent.top
property real lastLineY
property real lastLineWidth
onLineLaidOut: line => {
if (line.isLast) {
lastLineY = line.y;
lastLineWidth = line.implicitWidth
}
}
Label {
id: endText
text: root.switchOn ? qsTr(" off ") : qsTr(" on ")
font.pixelSize: 40
color: "white"
x: sentence.lastLineWidth
y: sentence.lastLineY
background: Rectangle {
color: root.switchOn ? "grey" : "red"
radius: 8
}
}
}
Switch {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 150
text: qsTr("Switch")
onToggled: root.switchOn = !root.switchOn
}
}
}
You can put the Labels within a Row, and horizontally center the Row.
Rectangle {
color: '#D3D3D3'
anchors.fill: parent
Row {
anchors.horizontalCenter: parent.horizontalCenter
Label {
id: sentence
...
}
Label {
id: endText
anchors.top: sentence.top
...
}
}
}
I have ListView with items like this:
And I want use swipe. But when I add SwipeDelegate I get this:
How I can make swipe elements over the text? I try use z properties, but with z my swipe not animated when opened and I can't close it.
Here my code:
//SomePage.qml:
import QtQuick 2.12
import QtQuick.Controls 2.12
ScrollView {
ListView {
id: someListView
model: SomeItems {}
delegate: SwipeDelegate {
width: someListView.width
Row {
leftPadding: 5
width: parent.width
Image {
id: someImg
height: 38
source: myImage
width: height
}
Column {
leftPadding: 5
width: parent.width - someImg.width - 10
// Name
Text {
id: someName
text: myCount.toString() + " × " + myName
}
// Number
Text {
id: someNumber
text: myNumber.toLocaleString(Qt.locale("ru-RU"), "f", 0)
anchors.right: parent.right
font.pixelSize: 12
rightPadding: 5
}
}
}
swipe.right: Row {
anchors.right: parent.right
height: parent.height
// Delete button
Label {
text: "\ue800"
color: "black"
font.family: fontFontello.name
height: parent.height
padding: 12
verticalAlignment: Label.AlignVCenter
width: this.height
background: Rectangle {
color: "lightblue"
height: parent.height
width: parent.width
MouseArea {
anchors.fill: parent
onClicked: someListView.model.remove(index)
}
}
}
// Hide button
Label {
text: "\ue80a"
color: "black"
font.family: fontFontello.name
height: parent.height
padding: 12
verticalAlignment: Label.AlignVCenter
width: this.height
background: Rectangle {
color: "lightgray"
MouseArea {
anchors.fill: parent
onClicked: {
...
swipe.close()
}
}
}
}
}
}
}
}
The problem is you're adding your text/image on top of the default contentItem instead of inside it. It will look correct if you add your Row to contentItem, like this:
delegate: SwipeDelegate {
contentItem: Row {
...
}
}
Why does not the MouseArea cover the whole item_row component in my example? If it did , then the Pane would become red when putting the mouse over it. I want the MouseArea to cover the whole Row, so when I put the mouse over the blue square or the labels, the whole pane becomes red, but right now it works only on the empty space. How should I do it?
This is the code, runs with qmlscene
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 680
title: qsTr("Hello World")
StackView {
anchors.fill: parent
Pane {
id: item_pane
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
contentHeight: parent.height
Row {
id: item_row
Rectangle {
color: "blue"
antialiasing: true
width: 150
height: 150
}
Pane {
background: Rectangle {
color: "transparent"
}
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
ColumnLayout {
Label {
text: "Some data"
Layout.alignment: Qt.AlignHCenter
font.bold: true
}
Grid {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
columns: 2
rows: 3
Label {
text: "Field1:"
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
}
Label {
text: "1 sec"
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
}
Label {
text: "Field 2"
}
Label {
text: "30 kg"
}
Label {
text: "Field 3"
}
Label {
text: "30 years"
}
}
}
}
MouseArea {
id: mouse_area
hoverEnabled: true
//anchors.fill: parent
onEntered: {
item_pane.background.color="red"
}
onExited: {
item_pane.background.color="#ffffff"
}
}
Component.onCompleted: {
mouse_area.x=item_row.x
mouse_area.y=item_row.y
mouse_area.width=item_row.width
mouse_area.height=item_row.height
console.log("x="+item_row.x+",y="+item_row.y+"width=" + item_row.width +",height="+item_row.height)
}
}
}
}
}
The Row will automatically position all children (that are all Items declared inside its { }) next to each other.
To have a MouseArea cover the whole Row, make the Row and the MouseArea siblings.
Row {
id: myRow
Rectangle {
[...]
}
[...]
}
MouseArea {
anchors.fill: myRow
[...]
}
just make a some wrapper. put Row to Item with same size AND fill this Item by MouseArea
I want to create an animated accordion-like element that expands on click. Here's how it should work.
When the user clicks one of the red rectangles, the green rectangle which is the actual content, should expand. I want this expansion to be animated. The height of the contents of the green rectangles could be different for each red header.
I have been able to implement the click-to-expand behavior, but there's no animation. Here is the code I currently have.
AccordionElement.qml
import QtQuick 2.5
import QtQuick.Layouts 1.1
ColumnLayout {
id: rootElement
property string title: ""
property bool isOpen: false
default property alias accordionContent: contentPlaceholder.data
anchors.left: parent.left; anchors.right: parent.right
// Header element
Rectangle {
id: accordionHeader
color: "red"
anchors.left: parent.left; anchors.right: parent.right
height: 50
MouseArea {
anchors.fill: parent
Text {
text: rootElement.title
anchors.centerIn: parent
}
cursorShape: Qt.PointingHandCursor
onClicked: {
rootElement.isOpen = !rootElement.isOpen
}
}
}
// This will get filled with the content
ColumnLayout {
id: contentPlaceholder
visible: rootElement.isOpen
anchors.left: parent.left; anchors.right: parent.right
}
}
And this is how it is used from the parent element:
Accordion.qml
ColumnLayout {
Layout.margins: 5
visible: true
AccordionElement {
title: "Title1"
accordionContent: Rectangle {
anchors.left: parent.left; anchors.right: parent.right
height: 20
color: "green"
}
}
AccordionElement {
title: "Title2"
accordionContent: Rectangle {
anchors.left: parent.left; anchors.right: parent.right
height: 50
color: "green"
}
}
AccordionElement {
title: "Title3"
accordionContent: Rectangle {
anchors.left: parent.left; anchors.right: parent.right
height: 30
color: "green"
}
}
// Vertical spacer to keep the rectangles in upper part of column
Item {
Layout.fillHeight: true
}
}
This produces the following result (when all rectangles are expanded):
Ideally I would like the green rectangles to roll out of the red rectangles (like paper out of a printer). But I am stuck on how to do this. I have tried several approaches using the height property, and I got the green rectangle to disappear but the white space remains under the red rectangle.
Any help would be appreciated. Is there an approach I'm missing?
Here is a quick and simple example:
// AccItem.qml
Column {
default property alias item: ld.sourceComponent
Rectangle {
width: 200
height: 50
color: "red"
MouseArea {
anchors.fill: parent
onClicked: info.show = !info.show
}
}
Rectangle {
id: info
width: 200
height: show ? ld.height : 0
property bool show : false
color: "green"
clip: true
Loader {
id: ld
y: info.height - height
anchors.horizontalCenter: info.horizontalCenter
}
Behavior on height {
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
}
}
}
// Acc.qml
Column {
spacing: 5
AccItem {
Rectangle {
width: 50
height: 50
radius: 50
color: "blue"
anchors.centerIn: parent
}
}
AccItem {
Rectangle {
width: 100
height: 100
radius: 50
color: "yellow"
anchors.centerIn: parent
}
}
AccItem {
Rectangle {
width: 75
height: 75
radius: 50
color: "cyan"
anchors.centerIn: parent
}
}
}
You are needlessly over-complicating it with the anchors and the layouts. It doesn't seem the problem calls for any of those.
Update: I slightly refined the implementation, compared to the initial one the content would actually slide out of the header as paper out of printer rather than simply being unveiled, and also removed the source of a false positive binding loop warning.
I created an example. I do not know why I get a crash when I try to resize the window horizontally. Crash happens only when iconVisible is true
here is the qml code from the main, paste this in a hello world qt quick controls 2 project to test:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import QtQuick.XmlListModel 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Page {
anchors.fill: parent
XmlListModel{
id : modelId
namespaceDeclarations: "declare namespace media = 'http://search.yahoo.com/mrss/';"
source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2&tags="
query: "//item[title and media:thumbnail and media:content]"
}
ListView {
anchors.fill: parent
model: modelId
Layout.fillWidth: true
delegate: itemDelegateId
ScrollBar.vertical: ScrollBar {}
}
Component {
id: itemDelegateId
Rectangle {
property bool iconVisible: true
property string contentText: "contentaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
property double itemHeight: 100
property int titleTextSize: 32
property int columnLayoutLeftMargin: (iconVisible)? 20 : 0
property string borderColor: "black"
property int iconSize: (iconVisible)? 40 : 0
height : itemHeight
anchors {
left: parent.left
right: parent.right
}
border.color: borderColor
border.width: 1
RowLayout {
anchors {
fill: parent
}
Rectangle {
id: notificationIconId
visible: iconVisible
anchors {
top: parent.top
}
height: iconSize
width: iconSize
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectFit
}
}
ColumnLayout {
id: columnLayoutId
anchors {
top: parent.top
bottom: parent.bottom
left: notificationIconId.right
right: parent.right
}
Text {
id: contentId
anchors {
top: parent.top
bottom: parent.bottom
}
Layout.fillWidth: true
font.pixelSize: 20
elide: Text.ElideRight
maximumLineCount: 3
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: "black"
text: contentText
}
}
}
}
}
}
}
There are a few issues here. The first is that Layout.fillWidth: true has no effect, as Page is not a layout:
ListView {
anchors.fill: parent
model: modelId
Layout.fillWidth: true // remove
delegate: itemDelegateId
ScrollBar.vertical: ScrollBar {}
}
The second is that you shouldn't specify width and height for items in a layout:
Rectangle {
id: notificationIconId
visible: iconVisible
anchors {
top: parent.top
}
height: iconSize // Should be Layout.preferredHeight: iconSize
width: iconSize // Should be Layout.preferredWidth: iconSize
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectFit
}
}
You can't use horizontal anchors on an item managed by a horizontal layout:
ColumnLayout {
id: columnLayoutId
anchors {
top: parent.top
bottom: parent.bottom
// This ColumnLayout is managed by a RowLayout, so these two lines have to go
left: notificationIconId.right
right: parent.right
}
}
Same thing for the Text item:
Text {
id: contentId
// Can't use vertical anchors on an item that is managed by a ColumnLayout
anchors {
top: parent.top
bottom: parent.bottom
}
Layout.fillWidth: true
font.pixelSize: 20
elide: Text.ElideRight
maximumLineCount: 3
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: "black"
text: contentText
}
With all of those issues fixed, it seems to work as expected:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import QtQuick.XmlListModel 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Page {
anchors.fill: parent
XmlListModel{
id : modelId
namespaceDeclarations: "declare namespace media = 'http://search.yahoo.com/mrss/';"
source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2&tags="
query: "//item[title and media:thumbnail and media:content]"
}
ListView {
anchors.fill: parent
model: modelId
delegate: itemDelegateId
ScrollBar.vertical: ScrollBar {}
}
Component {
id: itemDelegateId
Rectangle {
property bool iconVisible: true
property string contentText: "contentaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
property double itemHeight: 100
property int titleTextSize: 32
property int columnLayoutLeftMargin: (iconVisible)? 20 : 0
property string borderColor: "black"
property int iconSize: (iconVisible)? 40 : 0
height : itemHeight
anchors {
left: parent.left
right: parent.right
}
border.color: borderColor
border.width: 1
RowLayout {
anchors {
fill: parent
}
Rectangle {
id: notificationIconId
visible: iconVisible
anchors {
top: parent.top
}
Layout.preferredHeight: iconSize
Layout.preferredWidth: iconSize
Image {
anchors.fill: parent
fillMode: Image.PreserveAspectFit
}
}
ColumnLayout {
id: columnLayoutId
anchors {
top: parent.top
bottom: parent.bottom
}
Text {
id: contentId
Layout.fillWidth: true
font.pixelSize: 20
elide: Text.ElideRight
maximumLineCount: 3
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: "black"
text: contentText
}
}
}
}
}
}
}