ScrollView that won't scroll - qml

I have a flow which fills up well beyond the bottom of the screen. So I wrapped it in a ScrollView; however, I just can't make it work.
A (minor) problem is that setting contentWidth to anything other than parent.width causes the flow to show nothing. I should NOT have to set contentWidth/contentHeight since the scrollView contains a single item. (But not setting these causes an empty scrollView).
The major problem is that the view is not scrollable (once I have content showing). I can see content cutoff on the bottom, but I can't drag it up/down with my mouse, nor does a scrollbar appear. What is wrong?
Rectangle {
anchors {
top: buttons.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
ScrollView {
clip: true
contentHeight: gatewayFlow.implicitHeight
contentWidth: parent.width // availableWidth // gatewayFlow.implicitWidth
Flow {
id: gatewayFlow
anchors.fill: parent
spacing: 10
Gateway { }
Gateway { }
Gateway { }
Gateway { }
Gateway { }
Gateway { }
Gateway { }
Gateway { }
Gateway { }
} // Flow
} // ScrollView
} // Rectange

The issue is that your ScrollView will by default grow and shrink its width and height to match the content size if you haven't otherwise constrained them. And if the width and height match the content width and height you naturally won't get any scrolling.
Add this to ScrollView to constrain it and get actual scroll behavior of the content:
anchors.fill: parent

Related

How to show origin image size in qml Image component?

I tried to show origin image size in QML Image component,code like:
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: imageRect
width: parent.width
height: parent.height
anchors.fill: parent
DragHandler {
acceptedButtons: Qt.RightButton
target: sourceImage
xAxis.enabled: true
yAxis.enabled: true
}
Image {
id: sourceImage
source: "qrc:/2.jpg"
width: sourceSize.width
height: sourceSize.height
MouseArea {
width:parent.width
height:parent.height
onClicked: {
print(mouse.x, mouse.y)
print(sourceImage.x, sourceImage.y)
}
}
}
}
}
but the image is not fit with the parent's size, how can i fit the image to its parent and keep image origin size?
By default, the Image component will automatically set width and height to source image contents. You use this if you don't want any scaling to occur.
In the following example, I render the original Image, the Hubble view of the Pillars of Creation. I put it inside a Flickable with ScrollBars so that you can pan the image.
import QtQuick
import QtQuick.Controls
Page {
property string mouseInfo
Flickable {
id: flickable
anchors.fill: parent
contentWidth: image.width + 20
contentHeight: image.height + 20
clip: true
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
ScrollBar.horizontal: ScrollBar {
height: 20
policy: ScrollBar.AlwaysOn
}
Image {
id: image
source: "https://www.arcgis.com/sharing/rest/content/items/d0ecaa3fd9ef45c8ad255989ef6ded07/data"
MouseArea {
anchors.fill: parent
onClicked: mouseInfo = `${mouseX},${mouseY}`;
}
}
}
footer: Frame {
Text {
text: "image: %1x%2 mouseInfo:%3".arg(image.width).arg(image.height).arg(mouseInfo)
}
}
}
You can Try it Online!

SplitView inside ScrollView

Putting SplitView inside ScrollView breaks its work: for some reason it stops responding to mouse events and therefore resizing its children by dragging the splitter becomes impossible.
import QtQuick 2.7
import QtQuick.Controls 2.15
ScrollView {
width: 800
SplitView {
anchors {
top: parent.top
right: parent.right
left: parent.left
}
orientation: Qt.Vertical
Repeater {
model: 3
Rectangle {
SplitView.fillWidth: true
SplitView.minimumHeight: 150
color: "lightsteelblue"
Text {
anchors.centerIn: parent
text: "Row " + index
}
}
}
}
}
Is this a bug or am I missing something?

Center elements inside Scrollview

I have a problem with centering QML objects in a ScrollView. I want to scroll the images and other QML elements and they should be centered. But they are always sticked to the top left angle.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow{
id: appWindow
width:Screen.width
height:Screen.height
visible: true
ScrollView {
anchors.fill: parent
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: 800
height: 800
color : "yellow"
}
}
}
You have two aspects to take in account. Directly from the docs:
Only one Item can be a direct child of the ScrollView and the child is implicitly anchored to fill the scroll view.
So you could not have more than one Rectangle, just a container for all the Rectangles (which actually are images, as stated in your question).
Moreover it should be noted, again from the docs, that:
The width and height of the child item will be used to define the size of the content area.
Hence, you need only one child for the ScrollView and ensure that it takes the correct size from the parent. I would use a ColumnLayout for the purpose. Final sample code here:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
ApplicationWindow{
id: appWindow
width: 200
height: 100
visible: true
ScrollView {
anchors.fill: parent
ColumnLayout { // unique child
spacing: 10
width: appWindow.width // ensure correct width
height: children.height // ensure correct height
// your children hereon...
Repeater {
model: 4
delegate: Rectangle {
Layout.alignment: Qt.AlignHCenter
width: 50
height: 50
color : "yellow"
}
}
}
}
}
EDIT
According to the OP the provided solution does not perfectly meet his needs and that's pretty reasonable. In particular:
no horizontal scrollbar is shown if the window is resized horizontally
the horizontal scrollbar is shown as soon as the vertical one is shown
Both the problems are related to the approach used. Problem 1 is caused by the binding between the parent width and the ScrollView width: since the visible width is always equal to the total width, no horizontal scroll is shown, even if the contained items are larger than the window. Problem 2 is a consequence of the 1: since the width is equal to application, as soon as a vertical scrollbar is added, the horizontal one is also added to show the horizontal space covered by the vertical scrollbar.
Both the problems can be solved by changing the width binding to be either equal to the contained items width (to solve problem 1) or equal to the width of the viewport (solve problem 2), as also discussed in this other answer. Finally, anchoring should be removed to avoid binding loops. Here is a complete example working as expected:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
ApplicationWindow{
id: appWindow
width: 200
height: 100
visible: true
ScrollView {
id: scroller
width: appWindow.width // NO ANCHORING TO AVOID binding loops!
height: appWindow.height
ColumnLayout { // <--- unique child
spacing: 10
width: Math.max(scroller.viewport.width, implicitWidth) // ensure correct width
height: children.height // ensure correct height
// your children hereon...
Repeater {
model: 3
delegate: Rectangle {
Layout.alignment: Qt.AlignHCenter
width: 150
height: 150
color : "yellow"
}
}
}
}
}
is bound to the window width horizontal scrolls are not shown, even if contained items are larger than the window
From the doc (http://qt-project.org/doc/qt-5/qml-qtquick-controls-scrollview.html) :
Only one Item can be a direct child of the ScrollView and the child is implicitly anchored to fill the scroll view.
So you can't achieve what you want by anchoring the content. You have to change the size and the anchoring of the ScrollView
For example :
ApplicationWindow{
id: appWindow;
width:Screen.width;
height:Screen.height;
visible: true;
ScrollView
{
anchors.centerIn: parent;
width: Math.min(content.width + 30, appWindow.width);
height: Math.min(content.height, appWindow.height);
Rectangle
{
id: content;
width: 800;
height: 800;
color : "yellow"
}
}
}
You can insert a Rectangle or other similar QML items you like as a middle layer between ScrollView and the QML item you need to center and set its color to "transparent". This should be a cross-platform solution.
I have modified your code for example:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
id: appWindow
width:Screen.width
height:Screen.height
visible: true
ScrollView {
anchors.fill: parent
Rectangle {
width: Math.max(appWindow.width, rect.width)
height: Math.max(appWindow.height, rect.height)
color: "transparent"
Rectangle {
id: rect
anchors.centerIn: parent
width: 800
height: 800
color : "yellow"
}
}
}
}
I use Qt 5.5.

Hide the highlight of a ListView while scrolling

I am building a Qt5 application based on Qt-Quick 2 for the UI. I have an issue while displaying a ListView with an highlight component. When I scroll the ListView the highlight rectangle is visible outside of the ListView and I can't find a way to avoid it.
Here is an example of the issue with a minimal QML file:
import QtQuick 2.0
Rectangle {
width: 360; height: 600
ListView {
width: 350; height: 200
anchors.centerIn: parent
id: myList
model: myModel
highlight: highlightBar
delegate: Item {
width: 400; height: 20
Text { text: name }
MouseArea {
id: mArea
anchors.fill: parent
onClicked: { myList.currentIndex = index; }
}
}
}
Component {
id: highlightBar
Rectangle {
width: parent.width; height: 20
color: "#FFFF88"
}
}
ListModel {
id: myModel
}
/* Fill the model with default values on startup */
Component.onCompleted: {
for(var i = 0; i < 100; i++) {
myModel.append({ name: "Big Animal : " + i});
}
}
}
Is there a way to "limit" a component to its parent borders or to hide the highlight component while scrolling?
As reported by the documentation:
Note: Views do not enable clip automatically. If the view is not clipped by another item or the screen, it will be necessary to set clip: true in order to have the out of view items clipped nicely.
Hence, what you are experiencing is a common behaviour and you should either 1) clip the view via other Items (e.g. a header Rectangle and a footer Rectangle with z:infinite or simply set the clip property to true, i.e.
ListView{
//...
clip:true
//...
}
Clipping has some perfomance disavantages which can greatly affect the application as it grows. Hence, its usage, especially outside the views scenario, should be evaluated carefully.

Cascades layout issue - can't scroll a ListView in a DockLayout

I'm trying to display an ActivityIndicator while my list data is loading. Here's my Page QML:
Page {
signal articleClicked(variant article)
id: root
titleBar: TitleBar {
title: qsTr("All feeds")
visibility: ChromeVisibility.Visible
} // titleBar
Container {
layout: DockLayout {}
ListView {
dataModel: _feedModel
listItemComponents: [
ListItemComponent {
type: "item"
FeedListComponent {
feed: ListItemData
}
}
]
visible: !_manager.working
onTriggered: {
if (indexPath.length > 1) {
root.articleClicked(dataModel.data(indexPath));
}
}
} // ListView
ActivityIndicator {
verticalAlignment: VerticalAlignment.Fill
horizontalAlignment: HorizontalAlignment.Fill
running: _manager.working
}
} // Root container
} // Page
To display the ActivityIndicator centered, I'm using a DockLayout. It's working fine. However, when I switch _manager.working to false and display the ListView, I can't scroll. I guess it's not limited to the screen size, so it thinks that it's not needed to scroll, as all items are visible. But they're not. I tried to add verticalAlignment: VerticalAlignment.Fill and horizontalAlignment: HorizontalAlignment.Fill to the ListView, without any change. Any hint on how can I force the ListView to fit on screen? Thanks.
The problem isn't that your listview won't scroll, it's that the ActivityIndicator is on top of the listview preventing the touch events from propagating down to the listview beneath it. Try adding
visible: _manager.working
to the ActivityIndicator
Now your touch events will pass through to the listview when the listview is visible.