2

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"
        }
    }
}
BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
ningen
  • 31
  • 1
  • 4

3 Answers3

4

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:

  1. no horizontal scrollbar is shown if the window is resized horizontally
  2. 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

Community
  • 1
  • 1
BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
  • How make it center ? I check your code and get result: top left angle. – ningen Dec 11 '14 at 11:22
  • Why you edited the code? It perfectly works on my machine, with `width: appWindow.width`. You are *forwarding* the width to the layout since it should be as large as the parent item of the `ScrollView`, that is in this case the `ApplicationWindow`. Stick with the example and then adapt to your needs. – BaCaRoZzo Dec 11 '14 at 11:26
  • try my tests for your code: 1. set: id: appWindow width: 700 height: 500 try ONLY horizontal resize to minimizing window (I get: no scrolling for window -this is the error) 2. set: id: appWindow width: 700 height: 500 and try ONLY vertical resize to minimizing window (I get: scrolling for horizont side -this is the error) – ningen Dec 11 '14 at 12:29
  • that's why. one side resizing in your case doesn't correctly work. – ningen Dec 11 '14 at 12:37
  • The second is not an error: since the content area is given by all the available space (as I defined my example), you get the horizontal scrollbar: the vertical one is covering part of the visible area from `ScrollBar` pov. I see the problem of the first case. The thing is, `ScrollView` scrollbars stick to the content (see the picture of the documentation); since we faked the width the items were centered but we lost ability to horizontally scroll on resize. I think it could rethought. Maybe following a different approach, e.g. using `Flickable` + custom scrollbars, would be a better approach. – BaCaRoZzo Dec 11 '14 at 14:20
  • @ningen I've revisited the example to solve the issues you've pointed out. They are pretty reasonable. I think it correctly addresses your requirements. Can you check it out? – BaCaRoZzo Feb 27 '16 at 15:05
0

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"
        }
    }
}
BlueMagma
  • 2,392
  • 1
  • 22
  • 46
0

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.

UniversE
  • 555
  • 2
  • 7
  • 25