QML: SplitView hides all children except last - qt

I am new to QML and I am trying to implement a horizontal splitview with 2 children. The problem that I am having is that despite setting maximum and minimum widths for the children, the last child always takes up the entire split view and all the others are hidden and have to be manually opened. I have tried defining minimum and maximum widths using Layout.maximum/minimumwidth (which dont work at all) and have tried using fillwidth on the first child of the splitview. Nothing seems to work. I even copied and pasted the code from the qml doc page from splitview and it did the same thing. Here is my code:
import QtQuick 2.0
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.11
import "../buttons"
import "../customWidgets"
Rectangle {
id: conversationsPage
anchors.fill: parent
height: 455
width: 800
SplitView {
id: splitView
anchors.fill: parent
orientation: Qt.Horizontal
Rectangle {
id: sideBar
Layout.minimumWidth: 200
Layout.preferredWidth: 300
Layout.maximumWidth: 500
Layout.fillWidth: true
color: "#b9b9b9"
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.topMargin: 0
clip: true
Rectangle {
id: sideBarTopBar
y: 0
z: 2
height: 44
color: "#e868ff"
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
SearchBar {
id: conversationSearchBar
anchors.left: parent.left
anchors.right: newConversationBtn.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
anchors.topMargin: 10
anchors.leftMargin: 10
anchors.rightMargin: 10
}
IconBtn {
id: newConversationBtn
width: 35
height: 35
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 10
btnIconSource: "../images/icons/plus.svg"
}
}
ScrollView {
id: conversationsListScroll
anchors.left: parent.left
anchors.right: parent.right
anchors.top: sideBarTopBar.bottom
anchors.bottom: parent.bottom
z: 1
anchors.topMargin: 0
ColumnLayout {
id: conversationListLayout
x: 0
y: 0
width: conversationsListScroll.width
clip: true
ConversationTab {
Layout.fillWidth: true
}
ConversationTab {
Layout.fillWidth: true
}
ConversationTab {
Layout.fillWidth: true
}
ConversationTab {
Layout.fillWidth: true
}
ConversationTab {
Layout.fillWidth: true
}
ConversationTab {
Layout.fillWidth: true
}
ConversationTab {
Layout.fillWidth: true
}
}
}
}
Rectangle {
id: conversationView
Layout.fillWidth: false
Layout.minimumWidth: 300
Layout.maximumWidth: 500
color: "#ff0000"
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.topMargin: 0
anchors.bottomMargin: 0
}
}
Do you guys have any idea why the split view isnt working the way I want it to?

I noticed a couple of things, first, in SplitView from Quick Controls 2, you must use the SplitView attached property instead of the Layout attached property.
Secondarily, I also noticed that you have anchors specified inside the direct children of the SplitView, which have no effect and can be removed. I am not sure, but it seems like the child with SplitView.fillWidth: true should not have a maximum width set, as both children having maximum widths can prevent the SplitView from filling its parent Rectangle fully (you may still have a use case for this, but I removed it for this reason).
Here is the code with these recommendations:
SplitView {
id: splitView
anchors.fill: parent
orientation: Qt.Horizontal
Rectangle {
id: sideBar
SplitView.minimumWidth: 200
SplitView.preferredWidth: 300
SplitView.fillWidth: true
color: "#b9b9b9"
clip: true
// children here...
}
Rectangle {
id: conversationView
SplitView.fillWidth: false
SplitView.minimumWidth: 300
SplitView.maximumWidth: 500
color: "#ff0000"
}
}

Related

Scroll Bar is not working in ScrollView qml

I'm trying to use a scrollbar inside a scrollview. The scrollbar shows up and I can interact with it (hover/pressed), but it doesn't move, and I can't understand why. I wrote my code by following the official documentation and online examples.
Here's the code:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
Window {
width: 740
height: 580
visible: true
color: "#00000000"
title: qsTr("Hello World")
Rectangle {
id: rectangle
color: "#40405f"
anchors.fill: parent
Button {
id: button
text: qsTr("Menu")
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.leftMargin: 10
anchors.bottomMargin: 466
anchors.topMargin: 74
onClicked: animationMenu.running = true
}
ScrollView {
id: scrollView
width: 0
anchors.left: button.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 10
clip: true
Rectangle {
id: rectangle1
color: "#00000000"
border.color: "#00000000"
border.width: 0
anchors.fill: parent
PropertyAnimation {
id: animationMenu
target: scrollView
property: "width"
to: if(scrollView.width == 0) return 240; else return 0
duration: 800
easing.type: Easing.InOutQuint
}
Column {
id: columnMenu
width: 0
anchors.fill: parent
spacing: 10
Button {
id: button1
text: qsTr("Button")
}
Button {
id: button2
text: qsTr("Button")
}
Button {
id: button3
text: qsTr("Button")
}
Button {
id: button4
text: qsTr("Button")
}
}
}
ScrollBar {
id: vbar
hoverEnabled: true
orientation: Qt.Vertical
size: scrollView.height / rectangle1.height
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
wheelEnabled: true
pressed: true
active: true
}
}
}
}
Ok, so I edited the code to a smaller version so that it can be run.
Some advices:
Use anchors or Layouts. Do not use fixed values or some kind of treats, no matter if it works. The long term value of your code will be bad.
You should read carefully the (ScrollView documentatio). Also the Size section and the Touch and Mouse Interaction Section.
I am able to modify your example without the animation.
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.15
Window {
width: 740
height: 580
visible: true
color: "#00000000"
title: qsTr("Hello World")
Rectangle {
id: rectangle
color: "#40405f"
anchors.fill: parent
RowLayout{
anchors.fill: parent
Button {
id: button
text: qsTr("Menu")
width: 100
height: 50
}
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
RowLayout{
implicitHeight: 2000
implicitWidth: 2000
Column {
id: columnMenu
width: 0
anchors.fill: parent
spacing: 10
Repeater{
model: 50
delegate: Button {
text: qsTr("Button")
}
}
}
}
}
}
}
}

StackLayout in QML

Requirement: I am building a Settings app in QML, in which the I have divided screen into a grid. On the left hand side of the Grid, there are buttons : Home, Connectivity, Settings and Quit. and on the right hand side, corresponding display should be drawn. Currently, I have added a rectangle, and when I click on buttons like Home, Settings, connectivity etc.. . Code written inside the rectangle of StackLayout is executed successfully.
Instead of writing code in a rectangle, i want to write code in a separate file like settings.qml, connectivity.qml.
How to call the different file by clicking on buttons and setting current Index
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.3
ApplicationWindow {
id:main1
visible: true
x:0
y:20
width: Screen.width
height: Screen.height
title: qsTr("Settings")
GridLayout {
id: gridLayout
width: parent.width
height:main1.height
columns: 2
Rectangle {
id: left_rect
width: Screen.width/4
height: gridLayout.height
color:"yellow"
Button {
id: button
text: qsTr("Home")
anchors.right: parent.right
anchors.rightMargin: 5
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
onClicked: {
layout.currentIndex = 0
}
}
Button {
id: button1
x: 1
y: -4
text: qsTr("Connectivity")
anchors.topMargin: 59
anchors.leftMargin: 5
anchors.left: parent.left
anchors.top: parent.top
anchors.rightMargin: 5
anchors.right: parent.right
onClicked: {
layout.currentIndex = 1
}
}
Button {
id: button2
x: 5
y: -8
text: qsTr("Settings")
anchors.topMargin: 112
anchors.leftMargin: 5
anchors.left: parent.left
anchors.top: parent.top
anchors.rightMargin: 5
anchors.right: parent.right
onClicked: {
layout.currentIndex = 2
}
}
Button {
id: button3
x: 6
y: -16
text: qsTr("Quit")
anchors.topMargin: 172
anchors.leftMargin: 5
anchors.left: parent.left
anchors.top: parent.top
anchors.rightMargin: 5
anchors.right: parent.right
onClicked: {
Qt.quit()
}
}
}
Rectangle {
id: right_rect
width: ( Screen.width/4 )*3
height: Screen.height
color:"green"
StackLayout {
id: layout
anchors.fill: parent
currentIndex: 0
Rectangle {
color: 'teal'
implicitWidth: 200
implicitHeight: 200
}
Rectangle {
color: 'plum'
implicitWidth: 300
implicitHeight: 200
}
Rectangle {
color: 'orange'
implicitWidth: 300
implicitHeight: 200
}
}
}
}
Where you currently have
Rectangle {
color: 'teal'
implicitWidth: 200
implicitHeight: 200
}
replace with
qmlClassName {
id: someId
}

QML ListView::contentWidth is wider than actual content

Trying to implement ListView's content scroll by clicking on a button. When scrolling towards the end of the view ListView's content does not stop at the end of the last picture it overscrolls. Below I provided the minimum working example as well as the preview what goes wrong. Just change the .img path to make it work on your PC. I was looking for some help in sources of ListView and its inherited parent Flickable but nothing that could help to resolve the problem. How to make it stop at the end of the last picture?
import QtQuick 2.14
import QtQuick.Window 2.14
Window {
visible: true
width: 1024
height: 300
Item {
id: root
anchors.fill: parent
property var imagesUrlModel: ["file:///C:/Users/mikha/OneDrive/Изображения/toyota.jpg",
"file:///C:/Users/mikha/OneDrive/Изображения/toyota.jpg"
]
property int _width: 0
Component {
id: imageDelegate
Image {
id: image
sourceSize.height: 300
source: modelData
fillMode: Image.Stretch
}
}
Rectangle {
id: leftButton
anchors.top: root.top
anchors.bottom: parent.bottom
anchors.topMargin: 15
anchors.leftMargin: 10
anchors.left: parent.left
color: "green"
width: 25
MouseArea {
anchors.fill: parent
onClicked: {
listView.contentX = listView.contentX > 0
? listView.contentX - 50 > 0 ? listView.contentX - 50 : 0
: 0
}
}
}
Rectangle {
id: rightButton
anchors.top: root.top
anchors.bottom: parent.bottom
anchors.topMargin: 15
anchors.rightMargin: 10
anchors.right: parent.right
color: "green"
width: 25
MouseArea {
anchors.fill: parent
onClicked: {
listView.contentX = listView.contentX < listView.contentWidth
? listView.contentX + 50
: listView.contentWidth
//wrong content width
}
}
}
ListView{
id: listView
clip: true
boundsBehavior: Flickable.StopAtBounds
anchors.topMargin: 15
anchors.left: leftButton.right
anchors.right: rightButton.left
anchors.top: root.top
anchors.bottom: parent.bottom
spacing: 5
orientation: ListView.Horizontal
model: root.imagesUrlModel
delegate: imageDelegate
}
}
}
In your example just change listView.contentWidth to listView.contentWidth-listView.width in onClicked event for rightButton. But that's not enough. You should check whether the listView.contentX+50 is not overflowing listView.contentWidth-listView.width before you update the listView.contentX. In such case you need to update listView.contentX with difference between listView.contentWidth and listView.width.
Here it is:
listView.contentX = listView.contentX+50 <= listView.contentWidth-listView.width
? listView.contentX + 50
: listView.contentWidth - listView.width
I used another approach with repeater and scrollview and it has worked!
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Window {
visible: true
width: 1024
height: 300
Item {
id: contentItem
anchors.fill: parent
Rectangle {
id: rightButton
anchors.top: contentItem.top
anchors.bottom: contentItem.bottom
anchors.rightMargin: 10
anchors.right: contentItem.right
color: "green"
width: 25
MouseArea {
anchors.fill: parent
onClicked: {
var allowedWidth = scrollView.flickableItem.contentWidth - scrollView.viewport.width
if(row.width < scrollView.viewport.width){
return
}
var offset = scrollView.flickableItem.contentX + 50
if(offset <= allowedWidth){
scrollView.flickableItem.contentX += 50
}
else {
scrollView.flickableItem.contentX = allowedWidth
}
}
}
}
ScrollView {
id: scrollView
anchors.left: contentItem.left
anchors.right: rightButton.left
anchors.top: contentItem.top
anchors.bottom: contentItem.bottom
clip: true
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
property var imagesUrlModel: [
"file:///C:/Users/mikha/OneDrive/Изображения/toyota.jpg",
"file:///C:/Users/mikha/OneDrive/Изображения/toyota.jpg"
]
Row {
id: row
spacing: 15
Repeater {
id: repeater
anchors.left: parent.left
anchors.right: parent.right
model: scrollView.imagesUrlModel
delegate: Component {
id: imageDelegate
Image {
id: image
sourceSize.height: 300
source: modelData
fillMode: Image.Stretch
}
}
}
}
}
}
}

how to create a scrollbar for rectangle in QML

like the web pages,when content's high beyond the rectangle,there is a scrollbar.
Is there anyone else who can help me?
I have tried with listview,but I can't use it in a rectangle
There is an example in the docs, how to use ScrollBar without a Flickable:
import QtQuick 2.7
import QtQuick.Controls 2.0
Rectangle {
id: frame
clip: true
width: 160
height: 160
border.color: "black"
anchors.centerIn: parent
Text {
id: content
text: "ABC"
font.pixelSize: 160
x: -hbar.position * width
y: -vbar.position * height
}
ScrollBar {
id: vbar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Vertical
size: frame.height / content.height
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
}
ScrollBar {
id: hbar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Horizontal
size: frame.width / content.width
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
adding rectangle into flickable solved my problem
import QtQuick.Controls 2.5
import QtQuick.Controls.Material 2.5
import QtQuick 2.8
Item {
id: item1
visible: true
width: 800
height: 600
ScrollView {
id: frame
clip: true
anchors.fill: parent
//other properties
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Flickable {
contentHeight: 2000
width: parent.width
Rectangle {
id : rectangle
color: "#a7c4c6"
radius: 6
//visible: !busyIndicator.running
anchors.fill: parent
}
}
}
}

QML: Using ScrollView leads to incorrect displaying of elements

I'm using Qt 5.2.1 for windows (Qt creator 3.0.1)
I have a custom QML component, it works fine when I'm loading in into rectangle:
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: mainRectangle
anchors.fill: parent
Loader {
anchors.top: parent.top;
anchors.left: parent.left;
anchors.right: parent.right;
id: ld01;
onLoaded: {
ld01.visible = true;
anchors.top = parent.top;
}
}
Loader {
anchors.top: ld01.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
id: ld02;
onLoaded: {
anchors.top = ld01.bottom;
ld02.visible = true;
}
}
Component.onCompleted: {
ld01.setSource("View_item2.qml");
ld02.setSource("View_item2.qml");
}
}
But when I'm trying to put it all inside a ScrollView, elements of my component are moved somewhere. What kind of trick I should implement for correct use of ScrollView?
ScrollView {
id: mainTabLayout
anchors.fill: parent
anchors.margins: 4
//here I put a code from above (except imports, of course)
}
Component code is below:
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.0
Rectangle {
id: slv_layout
objectName: "itemColumnLayout"
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 1
property int minimal_height: 200
height: 400
color: "green"
MouseArea {
property bool is_pressed: false
property int initial_y: 0
property int proposed_y: 0
id: resizeStick
enabled: true
anchors.bottom: parent.bottom
height: 10
width: parent.width
hoverEnabled: true
onEntered: {
cursorShape = Qt.SizeVerCursor;
}
onPressed: {
is_pressed = true;
initial_y = mouseY;
}
onReleased: {
is_pressed = false;
}
onMouseYChanged: {
if (is_pressed) {
proposed_y = slv_layout.height + mouseY - initial_y;
if (proposed_y >= slv_layout.minimal_height) {
slv_layout.height += (mouseY - initial_y);
initial_y = mouseY;
}
}
}
}
Text {
id: slvTitle
text: "device name"
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 2
}
Rectangle {
anchors.top: slvTitle.bottom
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.topMargin: 2
color: "blue"
Button {
id: slv_butt_run;
objectName: "slv_butt_run"
width: 60
height: width
text: "Run"
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 2
}
Button {
id: slv_butt_settings;
objectName: "slv_butt_settings"
width: 60
height: width
text: "Settings"
anchors.top: parent.top
anchors.left: slv_butt_run.right
anchors.margins: 2
}
Button {
id: slv_butt_stop;
objectName: "slv_butt_stop"
width: 60
height: width
text: "Stop"
anchors.top: slv_butt_run.bottom
anchors.left: parent.left
anchors.margins: 2
}
Button {
id: slv_butt_expand;
objectName: "slv_butt_expand"
width: 60
height: width
text: "Expand"
anchors.top: slv_butt_settings.bottom
anchors.left: slv_butt_stop.right
anchors.margins: 2
}
TextArea {
id: slv_log_area
anchors.left: slv_butt_expand.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 3
}
}
}
How it looks when all is ok:
How it looks when not ok:
Actually, I still don't know, why code works as described above. But I have found acceptable method to solve task other way.
Looks like "put a needle into egg, egg into duck, duck into rabbit":
ScrollView must contain a ListView component which has a corresponding ListModel and a custom component should act as delegate. Only with ListModel I've got correct automatic scrolling and relative emplacement support.
ScrollView {
id: id_scrollView
anchors.fill: parent
objectName: "ScrollView"
frameVisible: true
highlightOnFocus: true
style: ScrollViewStyle {
transientScrollBars: true
handle: Item {
implicitWidth: 14
implicitHeight: 26
Rectangle {
color: "#424246"
anchors.fill: parent
anchors.topMargin: 6
anchors.leftMargin: 4
anchors.rightMargin: 4
anchors.bottomMargin: 6
}
}
scrollBarBackground: Item {
implicitWidth: 14
implicitHeight: 26
}
}
ListView {
id: id_listView
objectName: "ListView"
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 11
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
delegate: view_component
model: id_listModel
ListModel {
id :id_listModel
objectName: "ListModel"
}
//delegate: View_item2.Item
Component {
id: view_component
View_item2 {
objectName: name
}
}
}
According to the ScrollView documentation,
A ScrollView can be used either to replace a Flickable or decorate an existing Flickable. ... The width and height of the child item will be used to define the size of the content area.
A ScrollView needs to know two width-height pairs: the first one is the width and height used to display the region, and the second one is the width and height of the content. If the area of the content is larger than the display area, the display area will add a scroll bar on it.
In your example:
ScrollView {
id: mainTabLayout
anchors.fill: parent
//other properties
Rectangle {
id: mainRectangle
anchors.fill: parent
//...
}
}
The width and height of the content is bound to the display area, making the two areas be in the same size. The width and height of display area is the one in mainTabLayout, which is bound to it's parent; and the width and height of the content is the one in mainRectangle, which is bound to it's parent, mainTabLayout. Therefore the ScrollView cannot work correctly since ScrollView expects the two values are different, not bound together.
To solve your problem, you can explicitly assign width and height to mainRectangle. Do not bind the width and height of mainRectangle to it's parent using anchors.fill:parent.
ScrollView {
id: mainTabLayout
anchors.fill: parent
//other properties
Rectangle {
id: mainRectangle
width: 800; height: 800 //not binding to parent.width & height
//...
}
}
And this can work correctly.

Resources