Foto-Oberfläche
Eine QML-App für Touch-Geräte, die einen Repeater mit einem FolderListModel verwendet, um auf Inhalte in einem Ordner zuzugreifen, und einen PinchHandler, um Pinch-Gesten auf den abgerufenen Inhalten zu verarbeiten.
Photo Surface demonstriert, wie ein Repeater mit einem FolderListModel und einem FolderDialog verwendet wird, um auf Bilder aus einem vom Benutzer ausgewählten Ordner zuzugreifen, und wie das Ziehen, Drehen und Zoomen innerhalb desselben Elements mit Qt Quick Input Handlers gehandhabt werden kann.
Der gesamte Anwendungscode ist in einer QML-Datei enthalten, photosurface.qml
. Inline-JavaScript-Code wird zum Platzieren, Drehen und Skalieren von Bildern auf der Fotooberfläche verwendet.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorauszuführen, öffnen Sie den Modus Welcome und wählen Sie das Beispiel unter Examples aus. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.
Erstellen des Hauptfensters
Um das Hauptfenster für die Photo Surface-App zu erstellen, verwenden wir den QML-Typ Window als Stammelement. Er richtet das Fenster automatisch für die Verwendung mit Qt Quick grafischen Typen:
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
Zugriff auf den Inhalt von Ordnern
Wir verwenden einen Repeater QML-Typ zusammen mit FolderListModel, um zumindest die GIF-, JPG- und PNG-Bilder in einem Ordner anzuzeigen (obwohl main.cpp die Liste der unterstützten Bildtypen erweitern kann):
Repeater { model: FolderListModel { id: folderModel objectName: "folderModel" showDirs: false nameFilters: root.imageNameFilters }
Um den Typ FolderListModel zu verwenden, müssen wir ihn importieren:
import Qt.labs.folderlistmodel
Wir verwenden FolderDialog, um den Benutzern die Möglichkeit zu geben, den Ordner auszuwählen, der die Bilder enthält:
FolderDialog { id: folderDialog title: qsTr("Choose a folder with some images") onAccepted: folderModel.folder = selectedFolder }
Um den Typ FolderDialog zu verwenden, fügen wir die folgende Importanweisung hinzu:
import QtQuick.Dialogs
Wir verwenden die Funktion folderDialog.open()
, um den Dateidialog zu öffnen, wenn die anfängliche Diashow beendet ist, es sei denn, es wurde ein Ordnerpfad als Befehlszeilenargument angegeben:
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() }
Die Benutzer können auch auf das Symbol des Ordnerdialogs klicken, um ihn zu öffnen. Wir verwenden einen Image QML-Typ, um das Symbol anzuzeigen. Innerhalb des Image-Typs verwenden wir ein TapHandler mit dem onTapped
Signalhandler, um die Funktion folderDialog.open()
aufzurufen:
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() } }
Anzeige von Bildern auf der Fotooberfläche
Wir verwenden Rectangle als Delegierten für Repeater, um einen Rahmen für jedes Bild bereitzustellen, das FolderListModel im ausgewählten Ordner findet. Wir verwenden die JavaScript-Methoden Math()
, um die Rahmen zufällig auf der Fotooberfläche zu platzieren und sie in zufälligen Winkeln zu drehen, sowie die Bilder zu skalieren. Die Farbe des Rahmens zeigt den Zustand der Interaktion an:
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 }
Handhabung von Zieh- und Kneifgesten und der Maus
Wir verwenden ein DragHandler und ein PinchHandler in jedem Fotorahmen, um das Ziehen, Zoomen und Drehen zu steuern:
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) } }
Da PinchHandler innerhalb des Rechtecks deklariert ist, ist die Eigenschaft PinchHandler.target
implizit so eingestellt, dass Pinch-Gesten das Rechteck manipulieren. Die Rotationseigenschaften legen fest, dass die Rahmen in alle Richtungen gedreht werden können, und die Skalierungseigenschaften legen fest, dass sie zwischen 0.1
und 10
skaliert werden können. Die Pinch-Geste funktioniert auch auf einem Touchscreen oder einem Multi-Touch-Touchpad. Durch das Transformieren des Rahmens wird sein Inhalt (das Bild) transformiert.
Die Eigenschaft DragHandler.target
ist ebenfalls implizit gesetzt, so dass Sie ein Foto mit einem Finger auf einem Touchscreen oder Touchpad oder mit einer Maus ziehen können. Im Signalhandler von DragHandler( onActiveChanged
) wird der ausgewählte Fotorahmen nach oben verschoben, indem der Wert der Eigenschaft z
erhöht wird (während die gemeinsame Eigenschaft highestZ
den größten Wert von z
enthält, der bisher verwendet wurde). Nach Beendigung des Ziehens wird eine Animation gestartet, damit sich das Bild eine Weile in dieselbe Richtung bewegt und dann langsamer wird und zum Stillstand kommt. Wenn Sie ein Foto über den Rand der Oberfläche hinaus "schleudern", dehnt sich die Oberfläche aus, um ihre neue Position einzunehmen. Sie können sich bewegen, um verschiedene Teile der Oberfläche über die ScrollView zu betrachten, die den Repeater und alle von ihm befüllten Fotorahmen enthält.
Da Sie zwei Fotos mit zwei Fingern über ihre DragHandler ziehen können und Sie auch ein PinchHandler mit zwei Fingern zusammenschieben können und sich Fotosammlungen übereinander stapeln, müssen wir grabPermissions
so anpassen, dass PinchHandler Vorrang hat: Wenn die Zusammenschiebegeste beginnt, lässt sie nicht zu, dass die DragHandler die Touchpoint-Griffe wieder übernehmen.
Um das Beispiel auf Computern ohne Touch-Geräte interaktiver zu machen, fügen wir die HoverHandler hinzu, von der die obige border.color abhängt, sowie zwei WheelHandlers. Mit dem einen können Sie die Strg-Taste gedrückt halten und das Mausrad verwenden, um das Foto um den Mauszeiger zu drehen; mit dem anderen können Sie die Umschalttaste gedrückt halten und das Mausrad verwenden, um die Position unter dem Mauszeiger zu vergrößern oder zu verkleinern. In beiden Fällen wird das Foto auf die gleiche Weise angehoben, wie es in DragHandler der Fall ist:
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 }
Siehe auch QML-Anwendungen.
© 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.