フォトサーフェス
タッチデバイス用のQMLアプリで、リピータとFolderListModel を使ってフォルダ内のコンテンツにアクセスし、PinchHandler を使って取得したコンテンツのピンチジェスチャーを処理します。
フォトサーフェスでは、FolderListModel とFolderDialog を備えたRepeater を使用して、ユーザーが選択したフォルダから画像にアクセスする方法と、Qt Quick 入力ハンドラを使用して、同じアイテム内でのドラッグ、回転、ピンチ操作によるズームを処理する方法を紹介します。
すべてのアプリコードは、1つのQMLファイル(photosurface.qml
)に含まれています。インラインJavaScriptコードは、写真表面上の画像を配置、回転、拡大縮小するために使用されます。
例の実行
からサンプルを実行するには Qt Creatorからサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳しくは、Building and Running an Exampleをご覧ください。
メインウィンドウの作成
Photo Surfaceアプリのメインウィンドウを作成するために、Window QMLタイプをルートアイテムとして使用します。QMLタイプは自動的に Qt Quickグラフィカルタイプで使用するためのウィンドウを自動的に設定します:
Window { id: root visible: true width: 1024; height: 600 color: "black" title: Application.displayName + " : " + folderModel.folder property real defaultSize: 200 property real surfaceViewportRatio: 1.5 property var imageNameFilters: ["*.png", "*.jpg", "*.gif"] // overridden in main.cpp
フォルダコンテンツへのアクセス
Repeater QML型とFolderListModel QML型を併用することで、少なくともフォルダ内のGIF、JPG、PNG画像を表示することができます(ただし、main.cppではサポートする画像タイプのリストが拡張される可能性があります):
Repeater { model: FolderListModel { id: folderModel objectName: "folderModel" showDirs: false nameFilters: root.imageNameFilters }
FolderListModel 型を使用するには、インポートする必要があります:
import Qt.labs.folderlistmodel
FolderDialog 、ユーザーが画像を含むフォルダを選択できるようにします:
FolderDialog { id: folderDialog title: qsTr("Choose a folder with some images") onAccepted: folderModel.folder = selectedFolder }
FolderDialog タイプを使用するには、次の import ステートメントを追加します:
import QtQuick.Dialogs
フォルダパスがコマンドライン引数として与えられていない限り、最初のスライドショーが終了したときにファイルダイアログを開くためにfolderDialog.open()
関数を使用します:
Component.onDestruction: { folderIcon.visible = true const lastArg = Application.arguments.slice(-1)[0] const standardPicturesLocations = StandardPaths.standardLocations(StandardPaths.PicturesLocation) const hasValidPicturesLocation = standardPicturesLocations.length > 0 if (hasValidPicturesLocation) folderDialog.currentFolder = standardPicturesLocations[0] if (/.*hotosurface.*|--+/.test(lastArg)) { if (hasValidPicturesLocation) folderModel.folder = standardPicturesLocations[0] else folderDialog.open() }
ユーザーはフォルダダイアログのアイコンをクリックして開くこともできます。アイコンの表示にはImageQMLタイプを使用します。Imageタイプの内部では、onTapped
シグナルハンドラを持つTapHandler を使い、folderDialog.open()
関数を呼び出しています:
Image { id: folderIcon visible: false anchors.top: parent.top anchors.left: parent.left anchors.margins: 10 source: "resources/folder.png" TapHandler { onTapped: folderDialog.open() } HoverHandler { id: folderMouse } ToolTip.visible: folderMouse.hovered ToolTip.text: qsTr(`Open an image directory (${openShortcut.nativeText})`) ToolTip.delay: 1000 Shortcut { id: openShortcut sequence: StandardKey.Open onActivated: folderDialog.open() } }
フォトサーフェスに画像を表示する
Repeater のデリゲートとしてRectangle を使用し、FolderListModel が選択されたフォルダ内で見つけた各画像のフレームを提供します。JavaScriptのMath()
メソッドを使用して、写真サーフェス上にフレームをランダムに配置し、ランダムな角度で回転させ、画像を拡大縮小します。枠の色はインタラクションの状態を示している:
delegate: Rectangle { required property date fileModified required property string fileName required property url fileUrl id: photoFrame objectName: "frame-" + fileName width: image.width * (1 + 0.10 * image.height / image.width) height: image.height * 1.10 scale: root.defaultSize / Math.max(image.sourceSize.width, image.sourceSize.height) border.color: pinchHandler.active || dragHandler.active ? "darkturquoise" : mouse.hovered ? "darkseagreen" : "saddlebrown" border.width: 3 / scale antialiasing: true Component.onCompleted: { x = Math.random() * root.width - width / 2 y = Math.random() * root.height - height / 2 rotation = Math.random() * 13 - 6 } Image { id: image anchors.centerIn: parent fillMode: Image.PreserveAspectFit source: photoFrame.fileUrl antialiasing: true }
ドラッグとピンチのジェスチャーとマウスを扱う
ドラッグ、ピンチ・ズーム、回転を処理するために、各フォトフレームでDragHandler とPinchHandler を使用しています:
PinchHandler { id: pinchHandler minimumRotation: -360 maximumRotation: 360 minimumScale: 0.1 maximumScale: 10 grabPermissions: PointerHandler.CanTakeOverFromAnything // and never gonna give it up onActiveChanged: if (active) photoFrame.z = ++flick.highestZ } DragHandler { id: dragHandler onActiveChanged: { if (active) photoFrame.z = ++flick.highestZ else anim.restart(centroid.velocity) } }
PinchHandler は Rectangle の内部で宣言されているため、PinchHandler.target
プロパティが暗黙的に設定され、ピンチジェスチャーが Rectangle を操作できるようになっています。回転プロパティは、フレームがあらゆる角度に回転できることを指定し、スケールプロパティは、フレームが0.1
と10
の間で拡大縮小できることを指定します。ピンチ・ジェスチャーは、タッチスクリーンやマルチタッチ・タッチパッドでも同様に機能します。フレームを変形すると、そのコンテンツ(イメージ)が変形します。
DragHandler.target
プロパティも暗黙のうちに設定されているため、タッチスクリーンやタッチパッド上で、またはマウスを使って、指一本で写真をドラッグすることができます。DragHandler'のonActiveChanged
シグナルハンドラでは、z
プロパティの値を増加させることで、選択されたフォトフレームを一番上に上げます(一方、共有されたhighestZ
プロパティには、これまでに使用された最大のz
値が保持されます)。ドラッグが終わると、しばらく同じ方向に動き続けるアニメーションを開始し、速度を落として停止します。サーフェスの端を越えて写真を「フライング」すると、サーフェスは新しい位置に合わせて拡大します。リピーターと、リピーターが入力するすべてのフォトフレームを含むScrollView 、サーフェスのさまざまな部分を見るために移動することができます。
DragHandlers を介して2本の指で2枚の写真をドラッグすることができ、2本の指で1つのPinchHandler をピンチすることもできます。写真のコレクションは互いに重なり合う傾向があるため、PinchHandler が優先されるようにgrabPermissions
を調整する必要があります。ピンチのジェスチャーが始まると、DragHandlers が再びタッチポイントのグラブを引き継ぐことを許可しません。
タッチデバイスを持たないコンピューターでもインタラクティブに操作できるように、上記のborder.colorが依存するHoverHandler 、2つのWheelHandlers 。もうひとつは、Shiftキーを押しながらマウス・ホイールを使って、カーソルのある位置を拡大・縮小するものだ。どちらも、上のDragHandler と同じように、写真を上昇させることができます:
HoverHandler { id: mouse } WheelHandler { acceptedModifiers: Qt.ControlModifier property: "rotation" onActiveChanged: if (active) photoFrame.z = ++flick.highestZ } WheelHandler { acceptedModifiers: Qt.ShiftModifier property: "scale" onActiveChanged: if (active) photoFrame.z = ++flick.highestZ }
QMLアプリケーションも参照してください 。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.