QMLプログラミングでFlickableを極める:flick()メソッドと応用

2025-05-27

Flickableは、タッチデバイスなどでコンテンツをドラッグしたりフリックしたりしてスクロールさせるためのQMLアイテムです。通常、ユーザーが指で画面を素早く払う(フリックする)と、その勢いに応じてコンテンツが滑らかにスクロールし、徐々に減速して停止します。

Flickable.flick(xVelocity, yVelocity) メソッドは、このユーザーによるフリック操作をコードからシミュレートするものです。

  • flick(qreal xVelocity, qreal yVelocity):
    • xVelocity: 水平方向の初速度(ピクセル/秒)を指定します。正の値は右方向へのフリック、負の値は左方向へのフリックを表します。
    • yVelocity: 垂直方向の初速度(ピクセル/秒)を指定します。正の値は下方向へのフリック、負の値は上方向へのフリックを表します。

このメソッドを呼び出すと、指定された速度でFlickableのコンテンツが動き出し、自然な減速アニメーションが適用されて停止します。

使用例

例えば、ボタンを押したときにFlickableを特定の方向にフリックさせたい場合などに利用できます。

import QtQuick 2.0
import QtQuick.Controls 2.0

Rectangle {
    width: 300
    height: 200
    color: "lightgray"

    Flickable {
        id: myFlickable
        anchors.fill: parent
        contentWidth: 600 // コンテンツの幅をFlickableの幅より大きくする
        contentHeight: 400 // コンテンツの高さをFlickableの高さより大きくする
        clip: true // はみ出たコンテンツをクリップする

        Rectangle {
            width: 500
            height: 300
            color: "lightblue"
            Text {
                anchors.centerIn: parent
                text: "長いコンテンツ"
                font.pointSize: 24
            }
        }

        Button {
            text: "右にフリック"
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: {
                myFlickable.flick(200, 0); // 水平方向に200ピクセル/秒でフリック
            }
        }
    }
}

この例では、myFlickableというFlickableアイテムの中に大きなRectangleがあり、"右にフリック"ボタンを押すと、myFlickable.flick(200, 0)が呼び出され、コンテンツが右方向にフリックされます。

Flickable.flick()メソッドは、以下のようなシナリオで役立ちます。

  • デモンストレーション: アプリケーションのデモンストレーションやチュートリアルで、フリックの動作を視覚的に示したい場合。
  • ナビゲーション: ユーザーの操作によらず、特定のセクションにフリックで移動させたい場合。
  • 自動スクロール: 特定のイベント発生時にコンテンツを自動的にスクロールさせたい場合(例: 新しいアイテムが追加されたときに一番下までスクロールする)。


フリックしても何も起こらない、または動きが小さい

考えられる原因と解決策

  • flickableDirection の制限
    flickableDirection プロパティは、フリックが許可される方向を制限します。例えば、Flickable.HorizontalFlick に設定されているのに yVelocity に値を与えても垂直方向には動きません。 解決策: 意図するフリック方向が flickableDirection で許可されているか確認してください。デフォルトは Flickable.AutoFlickDirection で、コンテンツサイズに基づいて自動的に方向が決定されます。

  • interactive プロパティが false に設定されている
    Flickable.interactivefalse の場合、ユーザーインタラクションが無効になり、flick() も機能しません。 解決策: Flickable.interactive: true であることを確認してください。

  • flickDeceleration の影響
    Flickable には flickDeceleration というプロパティがあり、フリックの減速度合いを制御します。この値が大きいと、フリックが早く停止します。 解決策: 必要であれば、flickDeceleration の値を小さくして、フリックがより長く続くように調整してみてください。一時的に flick() を呼び出す前に flickDeceleration を0に設定し、フリック後に元の値に戻すというアプローチもあります(ただし、ユーザーによるフリック操作に影響を与える可能性があるため注意が必要です)。

  • xVelocity / yVelocity の値が小さすぎる
    flick() メソッドに渡す速度は、ピクセル/秒単位です。非常に小さい値を指定すると、フリックがほとんど視認できないか、すぐに停止してしまいます。 解決策: 適切なフリック感を出すために、xVelocityyVelocity には十分に大きな値(例: 200〜1000 ピクセル/秒など)を設定してみてください。

  • contentWidth / contentHeight の設定不足
    Flickableは、その width/height に対して contentWidth/contentHeight が大きい場合にのみスクロール可能です。flick() を呼び出してもコンテンツが動かない場合、コンテンツのサイズが Flickable の表示領域と同じか、それより小さい可能性があります。 解決策: Flickable 内のコンテンツがその表示領域よりも大きいことを確認し、contentWidthcontentHeight を適切に設定してください。

    Flickable {
        width: 300
        height: 200
        contentWidth: 600 // Flickableの幅より大きくする
        contentHeight: 400 // Flickableの高さより大きくする
        // ...
    }
    

フリックが途中で止まる、またはバウンドする

考えられる原因と解決策

  • コンテンツのサイズ変更と contentWidth/contentHeight の更新不足
    動的にコンテンツのサイズが変わる場合(例: 画像のロード後、テキスト量の変更など)、FlickablecontentWidthcontentHeight が適切に更新されていないと、フリック可能な範囲が正しく認識されません。 解決策: コンテンツのサイズが変更されたときに、FlickablecontentWidth および contentHeight を更新するロジックを実装してください。特に ImageText など、ロードやレイアウトによってサイズが確定する要素の場合、onLoadedonContentWidthChanged / onContentHeightChanged などのシグナルを利用して更新すると良いでしょう。

    Image {
        id: myImage
        source: "largeImage.png"
        onStatusChanged: {
            if (status === Image.Ready) {
                myFlickable.contentWidth = myImage.width;
                myFlickable.contentHeight = myImage.height;
            }
        }
    }
    
  • boundsBehavior の設定
    FlickableboundsBehavior プロパティは、コンテンツが境界に到達したときの挙動を制御します。

    • Flickable.StopAtBounds (デフォルト): 境界でフリックが停止します。
    • Flickable.DragOverBounds: 境界を越えてドラッグできますが、フリックは境界で停止します。
    • Flickable.DragAndOvershootBounds: 境界を越えてドラッグでき、フリックも境界をオーバーシュート(飛び出し)します。 解決策: 想定する挙動に合わせて boundsBehavior を調整してください。オーバーシュートさせたい場合は Flickable.DragAndOvershootBounds を使用します。

flick() を呼び出しても見た目の変化がない

考えられる原因と解決策

  • 他の要素が Flickable の上に重なっている
    Flickable の上に他の ItemRectangle などが重なっていて、それがフリック対象のコンテンツを覆い隠している可能性があります。 解決策: Zオーダー(z プロパティ)を確認し、Flickable が適切に表示されるように調整してください。

  • clip プロパティが false
    Flickable はデフォルトではコンテンツをクリップしません。つまり、Flickable の表示領域からはみ出したコンテンツも表示され続けます。この場合、フリックしても見た目に変化がないように見えることがあります。 解決策: Flickableclip プロパティを true に設定して、表示領域外のコンテンツを非表示にしてください。

    Flickable {
        clip: true // これを設定しないと、コンテンツがFlickableの枠外にはみ出して表示される
        // ...
    }
    

flick() とユーザー操作の競合

考えられる原因と解決策

  • flick() の呼び出しタイミング
    ユーザーがコンテンツをドラッグしている最中や、別のフリックアニメーションが実行されている最中に flick() を呼び出すと、予期せぬ挙動になることがあります。 解決策: flick() を呼び出す前に、flickingdragging プロパティを確認し、Flickable がアイドル状態であることを確認すると良いでしょう。flickEnded シグナルを利用して、前回のフリックが終了したことを検知してから次の flick() を呼び出すようにすることもできます。

Flickable の子要素に関する問題

考えられる原因と解決策

  • MouseArea との競合
    Flickable 内に MouseArea がある場合、MouseArea がマウスイベントを消費してしまい、Flickable のフリック動作が阻害されることがあります。 解決策: MouseAreapropagateComposedEvents プロパティを true に設定することで、イベントを親要素に伝播させることができます。または、MouseAreahoverEnabledacceptedButtons を適切に設定して、必要なイベントのみを処理するように制限します。

  • Flickable の子要素は contentItem の子になる
    QMLのFlickableに直接配置された子要素は、実際にはFlickablecontentItemの子として追加されます。このため、子要素のプロパティ(x, y など)を直接操作しても、フリックによるスクロール量には影響されない場合があります。 解決策: flick()Flickable自体のcontentX, contentYプロパティを操作することでスクロールを実現します。子要素を相対的に移動させたい場合は、contentX, contentYの値に基づいて子要素の位置を調整するか、Flickableの外部からflick()を呼び出すことで全体をスクロールさせます。

  • 最小限の再現コードを作成する
    複雑なアプリケーションで問題が発生した場合、Flickable.flick() のみに焦点を当てた最小限のQMLファイルを作成し、そこで問題が再現するかどうかを確認します。これにより、問題の原因がFlickable自体にあるのか、それともアプリケーションの他の部分との相互作用にあるのかを切り分けやすくなります。

  • Qt Creator の QML Debugger を使用する
    Qt Creator には強力な QML Debugger が搭載されており、QMLツリーの要素のプロパティ値をリアルタイムで確認したり、デバッグメッセージをチェックしたりできます。これは問題の特定に非常に役立ちます。

  • console.log() を活用する
    FlickablecontentX, contentY, contentWidth, contentHeight, width, height, flicking, dragging などのプロパティを console.log() で出力し、期待通りの値になっているか確認してください。 特に onFlickStartedonFlickEnded シグナル内でログを出力すると、フリックのライフサイクルを追跡できます。



基本的なフリック操作

最も基本的な例として、ボタンをクリックしたときにFlickableを特定の方向にフリックさせるコードです。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300
    title: "Flickable.flick() の基本"

    Flickable {
        id: myFlickable
        anchors.fill: parent
        clip: true // コンテンツをFlickableの境界内でクリップする

        // Flickable のコンテンツは、そのcontentWidth/contentHeightがFlickable自身のwidth/heightより大きい場合にのみスクロール可能
        contentWidth: myContent.width
        contentHeight: myContent.height

        Rectangle {
            id: myContent
            width: 800 // Flickableの幅より広いコンテンツ
            height: 600 // Flickableの高さより高いコンテンツ
            color: "lightblue"

            Text {
                anchors.centerIn: parent
                text: "このコンテンツをフリックします"
                font.pointSize: 20
            }
        }

        // コントロール
        Column {
            anchors.right: parent.right
            anchors.verticalCenter: parent.verticalCenter
            spacing: 10
            width: 100 // ボタンの幅

            Button {
                text: "右へフリック"
                width: parent.width
                onClicked: {
                    // 水平方向に2000ピクセル/秒でフリック (右方向)
                    myFlickable.flick(2000, 0);
                }
            }

            Button {
                text: "左へフリック"
                width: parent.width
                onClicked: {
                    // 水平方向に-2000ピクセル/秒でフリック (左方向)
                    myFlickable.flick(-2000, 0);
                }
            }

            Button {
                text: "下へフリック"
                width: parent.width
                onClicked: {
                    // 垂直方向に2000ピクセル/秒でフリック (下方向)
                    myFlickable.flick(0, 2000);
                }
            }

            Button {
                text: "上へフリック"
                width: parent.width
                onClicked: {
                    // 垂直方向に-2000ピクセル/秒でフリック (上方向)
                    myFlickable.flick(0, -2000);
                }
            }
        }
    }
}

この例では、Flickable内に大きなRectangle(コンテンツ)を配置し、Buttonをクリックすると、それぞれの方向へ flick() メソッドが呼び出されてスクロールします。速度の値は、フリックの勢いを表します。

コンテンツの端まで自動スクロール

チャットアプリケーションなどで、新しいメッセージが追加されたときに自動的に一番下までスクロールさせたい場合などに役立ちます。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

ApplicationWindow {
    visible: true
    width: 400
    height: 500
    title: "チャット風自動スクロール"

    Flickable {
        id: chatFlickable
        anchors.fill: parent
        clip: true
        contentWidth: chatColumn.width
        contentHeight: chatColumn.height

        ColumnLayout {
            id: chatColumn
            width: chatFlickable.width - 20 // 左右に余白
            spacing: 5
            leftPadding: 10
            rightPadding: 10
            topPadding: 10
            bottomPadding: 10

            // チャットメッセージをここに追加
        }

        // 新しいメッセージ追加ボタン
        Button {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            text: "メッセージを追加"
            onClicked: {
                var newRect = Qt.createQmlObject(`
                    import QtQuick 2.15
                    Rectangle {
                        width: parent.width
                        height: 40
                        color: Qt.random() > 0.5 ? "lightgreen" : "lightblue"
                        radius: 5
                        Text {
                            anchors.centerIn: parent
                            text: "メッセージ " + chatFlickable.contentItem.children.length
                            font.pointSize: 14
                        }
                    }`, chatColumn);
                newRect.parent = chatColumn;

                // 新しいメッセージが追加されたら、一番下までフリック
                // contentYが最大値になるようにフリック速度を調整
                // -chatFlickable.contentHeight を使うことで、コンテンツの高さに基づいて計算
                // (contentHeight - height) がスクロール可能な最大値
                // 例えば、contentHeight = 600, height = 300 なら 300 が最大
                var targetY = chatFlickable.contentHeight - chatFlickable.height;
                if (targetY < 0) targetY = 0; // コンテンツがFlickableより小さい場合は0

                // 現在のcontentYから目標contentYまでの距離に比例した速度を与える
                // 例えば、目標まで100pxあるなら、それに応じた速度を計算
                // この例では、単純に負の大きな速度を与えて下方向にフリック
                chatFlickable.flick(0, 5000); // 下方向へ勢いよくフリック
            }
        }

        // contentHeightが変更されたときに自動スクロール
        // ユーザーが手動でスクロールしている場合は邪魔しないようにする
        onContentHeightChanged: {
            // flicking, dragging, moving は、Flickableが現在アニメーション中か、
            // ユーザーが操作中かを示すプロパティ
            if (!chatFlickable.flicking && !chatFlickable.dragging && !chatFlickable.moving) {
                // コンテンツの一番下が見える位置までフリック
                var targetY = chatFlickable.contentHeight - chatFlickable.height;
                if (targetY < 0) targetY = 0;
                chatFlickable.flick(0, targetY - chatFlickable.contentY > 0 ? 5000 : 0); // 下方向へ
            }
        }
    }
}

この例では、"メッセージを追加"ボタンを押すたびに新しいRectangle(メッセージ)が追加され、chatFlickable.flick(0, 5000) を呼び出すことで自動的に一番下までスクロールします。onContentHeightChanged ハンドラは、コンテンツの高さが変わる(新しいメッセージが追加される)たびに、Flickableがユーザーによって操作されていない場合に限り、自動スクロールを実行します。

特定の要素までフリックしてスクロール位置を調整

多数のアイテムがあるFlickable内で、特定のアイテムが見える位置までスクロールさせたい場合に便利です。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

ApplicationWindow {
    visible: true
    width: 400
    height: 500
    title: "特定のアイテムへフリック"

    Flickable {
        id: itemFlickable
        anchors.fill: parent
        clip: true
        contentWidth: contentColumn.width
        contentHeight: contentColumn.height

        ColumnLayout {
            id: contentColumn
            width: itemFlickable.width
            spacing: 5
            Repeater {
                model: 20 // 20個のアイテム
                delegate: Rectangle {
                    id: itemRect
                    width: parent.width
                    height: 50
                    color: index % 2 === 0 ? "#E0E0E0" : "#F0F0F0"
                    border.color: "gray"
                    border.width: 1

                    Text {
                        anchors.centerIn: parent
                        text: "アイテム " + (index + 1)
                        font.pointSize: 16
                    }

                    // このアイテムをクリックすると、そのアイテムまでフリック
                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            // クリックされたアイテムのグローバル座標を取得
                            var itemGlobalPos = itemRect.mapToItem(itemFlickable.contentItem, 0, 0);

                            // 目標のcontentXとcontentYを計算
                            // ここでは、アイテムの先頭がFlickableの先頭に来るように調整
                            var targetX = itemGlobalPos.x;
                            var targetY = itemGlobalPos.y;

                            // flick() は相対的な速度なので、ターゲットまでの距離を速度に変換する
                            // 単純に一定の速度でフリックさせる例
                            // 速度の方向と大きさは、現在の位置と目標位置の差から計算
                            var deltaX = targetX - itemFlickable.contentX;
                            var deltaY = targetY - itemFlickable.contentY;

                            var velocityMagnitude = 2000; // 速度の大きさ
                            var angle = Math.atan2(deltaY, deltaX);
                            var xVel = velocityMagnitude * Math.cos(angle);
                            var yVel = velocityMagnitude * Math.sin(angle);

                            itemFlickable.flick(xVel, yVel);

                            console.log("アイテム " + (index + 1) + " にフリック中...");
                        }
                    }
                }
            }
        }
    }

    // 特定のアイテムにジャンプするための入力
    Row {
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
        spacing: 10
        z: 100 // Flickableの上に表示されるようにする

        TextField {
            id: itemIndexInput
            placeholderText: "アイテム番号を入力"
            width: 150
            validator: IntValidator { bottom: 1; top: 20 }
        }

        Button {
            text: "ジャンプ"
            onClicked: {
                var indexToJump = parseInt(itemIndexInput.text) - 1; // 0ベースインデックスに変換
                if (indexToJump >= 0 && indexToJump < itemFlickable.contentItem.children.length) {
                    var targetItem = itemFlickable.contentItem.children[indexToJump];
                    var targetY = targetItem.y;

                    // 現在のcontentYから目標contentYまでの距離に応じてフリック速度を調整
                    var deltaY = targetY - itemFlickable.contentY;
                    var velocity = deltaY * 5; // 距離に応じて速度を調整(適当な係数)

                    itemFlickable.flick(0, velocity);
                    console.log("アイテム " + (indexToJump + 1) + " へジャンプ中...");
                }
            }
        }
    }
}

この例では、Repeaterで20個のRectangle(アイテム)を作成しています。各アイテムをクリックすると、そのアイテムがFlickableの表示領域の先頭に来るように自動的にフリックします。また、上部にテキストフィールドとボタンを設け、番号を入力してジャンプすることもできます。

  • ユーザー操作との競合
    flick() を呼び出すタイミングには注意が必要です。ユーザーがドラッグ操作をしている最中や、他のフリックアニメーションが実行されている最中に flick() を呼び出すと、意図しない挙動になることがあります。flicking, dragging, moving といったプロパティや、flickStarted, flickEnded などのシグナルを利用して、安全なタイミングで呼び出すように制御すると良いでしょう。
  • 速度の調整
    xVelocityyVelocity の値は、フリックの勢いを決定します。小さい値だとすぐに止まり、大きすぎると画面外に飛び出しすぎてしまう可能性があります。アプリケーションの要件に応じて適切な値を試行錯誤して見つける必要があります。
  • clip: true
    Flickableclip プロパティを true に設定すると、Flickable の境界からはみ出たコンテンツがクリップされ、スクロールしていることが視覚的に分かりやすくなります。
  • contentWidth/contentHeight の設定
    Flickablewidth/height よりコンテンツのサイズ (contentWidth/contentHeight) が大きい場合にのみフリックが可能です。これらを適切に設定しないと、flick() を呼び出しても何も起こりません。


contentX / contentY プロパティの直接操作

FlickablecontentX および contentY プロパティは、Flickable 内のコンテンツの現在のオフセットを表します。これらの値を直接設定することで、コンテンツを特定の位置に即座に移動させることができます。

特徴

  • アニメーションなし
    滑らかな移動が必要な場合は、別途アニメーションを追加する必要があります。
  • 直接的
    スクロール位置をピクセル単位で正確に制御できます。
  • 即時性
    値を設定すると、アニメーションなしでコンテンツがすぐに指定された位置にジャンプします。

使用例
特定のアイテムの先頭にスクロールしたい場合など、瞬間的な移動が必要な場合に利用できます。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300
    title: "contentX / contentY の直接操作"

    Flickable {
        id: myFlickable
        anchors.fill: parent
        clip: true
        contentWidth: contentRect.width
        contentHeight: contentRect.height

        Rectangle {
            id: contentRect
            width: 800
            height: 600
            color: "lightblue"
            Text { anchors.centerIn: parent; text: "広いコンテンツ"; font.pointSize: 24 }
        }

        Row {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 10

            Button {
                text: "左上へリセット"
                onClicked: {
                    myFlickable.contentX = 0;
                    myFlickable.contentY = 0;
                }
            }

            Button {
                text: "中央へ移動"
                onClicked: {
                    // コンテンツの中央をFlickableの中心に合わせる
                    myFlickable.contentX = (myFlickable.contentWidth - myFlickable.width) / 2;
                    myFlickable.contentY = (myFlickable.contentHeight - myFlickable.height) / 2;
                }
            }
        }
    }
}

PropertyAnimation を使った contentX / contentY のアニメーション

contentXcontentY を直接設定すると瞬間的な移動になりますが、PropertyAnimation を使うことで、これらのプロパティの変化を滑らかにアニメーションさせることができます。これにより、flick() と同様に視覚的に心地よいスクロールを実現できます。

特徴

  • 停止・一時停止・再開
    アニメーションをプログラム的に制御できます。
  • 柔軟性
    速度、継続時間、イージング(動きの加速/減速パターン)を細かく制御できます。
  • 滑らかな移動
    指定した時間とイージングカーブでスクロールをアニメーションできます。

使用例
「一番下までゆっくりスクロールする」や「特定のセクションまで滑らかに移動する」といった場合に適しています。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 500
    title: "PropertyAnimation によるスクロール"

    Flickable {
        id: myFlickable
        anchors.fill: parent
        clip: true
        contentWidth: contentColumn.width
        contentHeight: contentColumn.height

        Column {
            id: contentColumn
            width: myFlickable.width
            spacing: 5
            Repeater {
                model: 30
                delegate: Rectangle {
                    width: parent.width
                    height: 50
                    color: index % 2 === 0 ? "#E0E0E0" : "#F0F0F0"
                    Text { anchors.centerIn: parent; text: "アイテム " + (index + 1); font.pointSize: 16 }
                }
            }
        }

        Button {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            text: "一番下までスクロール (アニメーション)"
            onClicked: {
                // PropertyAnimation を使って contentY をアニメーションさせる
                scrollAnimation.to = myFlickable.contentHeight - myFlickable.height;
                if (scrollAnimation.to < 0) scrollAnimation.to = 0; // コンテンツがFlickableより小さい場合は0
                scrollAnimation.start();
            }
        }

        PropertyAnimation {
            id: scrollAnimation
            target: myFlickable
            property: "contentY"
            duration: 1000 // 1秒かけてスクロール
            easing.type: Easing.OutCubic // 滑らかな減速アニメーション
        }
    }
}

この例では、ボタンをクリックすると scrollAnimation が開始され、Flickable が滑らかに一番下までスクロールします。easing.type を変更することで、動きの挙動を調整できます。

ListView / GridView の positionViewAtBeginning() / positionViewAtEnd()

ListViewGridViewFlickable をベースにしていますが、リストやグリッドに特化した便利なスクロールメソッドを提供しています。

特徴

  • アニメーション制御
    通常、内部的にアニメーションを伴います。
  • シンプル
    positionViewAtBeginning()positionViewAtEnd() のように、目的が明確なメソッド。
  • コンテキスト依存
    リストやグリッドの構造に最適化されたスクロール。

使用例
チャットリストやフィードのように、コンテンツの先頭や末尾に移動したい場合に非常に便利です。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 500
    title: "ListViewによるスクロール制御"

    ListView {
        id: myListView
        anchors.fill: parent
        clip: true
        spacing: 5

        model: 30 // 30個のアイテム

        delegate: Rectangle {
            width: parent.width
            height: 50
            color: index % 2 === 0 ? "#E0E0E0" : "#F0F0F0"
            Text { anchors.centerIn: parent; text: "リストアイテム " + (index + 1); font.pointSize: 16 }
        }
    }

    Column {
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        spacing: 10

        Button {
            text: "先頭へスクロール"
            onClicked: {
                myListView.positionViewAtBeginning();
            }
        }

        Button {
            text: "末尾へスクロール"
            onClicked: {
                myListView.positionViewAtEnd();
            }
        }

        Button {
            text: "10番目のアイテムへ"
            onClicked: {
                // positionViewAtIndex(index, mode)
                // ListView.Beginning: アイテムをビューの先頭に
                // ListView.Center: アイテムをビューの中央に
                // ListView.End: アイテムをビューの末尾に
                // ListView.Visible: アイテムが見える範囲に移動(最低限のスクロール)
                myListView.positionViewAtIndex(9, ListView.Center); // 0-based indexなので9は10番目
            }
        }
    }
}

ScrollView は、Flickable の上にスクロールバーなどのUI要素を自動的に追加してくれる高レベルなコントロールです。内部的には Flickable を使用していますが、ユーザーインターフェースとしての完全なスクロールビューを提供します。スクロールバーの表示/非表示や、ユーザー操作への応答などを自動的に処理してくれます。

特徴

  • 内部はFlickable
    内部的には Flickable の機能を利用しているため、ScrollView.flickable.flick() のようにアクセスすることも可能です。
  • 簡潔な記述
    多くのケースで Flickable を直接使うよりもコード量が減ります。
  • 高レベルの抽象化
    スクロールバーの表示など、複雑なUIを自動的に処理。

使用例
通常のドキュメントビューアや設定画面など、標準的なスクロール動作とスクロールバーが必要な場合に最適です。

// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300
    title: "ScrollViewの使用"

    ScrollView {
        id: myScrollView
        anchors.fill: parent

        // ScrollView のコンテンツは、子要素として直接配置
        Rectangle {
            width: 800 // ScrollViewの幅より広いコンテンツ
            height: 600 // ScrollViewの高さより高いコンテンツ
            color: "lightcoral"
            Text { anchors.centerIn: parent; text: "ScrollView のコンテンツ"; font.pointSize: 24 }
        }

        // ScrollView内部のFlickableにアクセスしてflick()を呼び出す
        Button {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            text: "ScrollViewをフリック"
            onClicked: {
                myScrollView.flickable.flick(2000, 0); // ScrollViewの内部のFlickableをフリック
            }
        }
    }
}
  • ScrollView: スクロールバー付きの標準的なスクロールビューを簡単に実現したい場合に利用します。内部の flickable プロパティを通じて flick() などにアクセスすることも可能です。
  • ListView / GridView のメソッド: リストやグリッドの特定のアイテムにスクロールしたい場合に最も適した高レベルなメソッドです。
  • PropertyAnimation + contentX / contentY: flick() よりもきめ細かくスクロールアニメーションを制御したい場合(時間、イージング、停止/再開など)に強力です。
  • contentX / contentY 直接操作: 即座にスクロール位置を移動させたい場合に便利です。アニメーションは提供されません。
  • Flickable.flick(): ユーザーのフリック操作をプログラム的にシミュレートしたい場合に最適です。減速アニメーションが組み込まれています。