Superficie fotográfica
Aplicación QML para dispositivos táctiles que utiliza un repetidor con FolderListModel para acceder al contenido de una carpeta y PinchHandler para realizar gestos de pellizco sobre el contenido obtenido.

Photo Surface muestra cómo utilizar un Repeater con un FolderListModel y un FolderDialog para acceder a imágenes de una carpeta seleccionada por un usuario. El ejemplo también muestra cómo manejar el arrastre, la rotación y el zoom de pellizco dentro del mismo elemento utilizando Qt Quick Input Handlers.
Todo el código de la aplicación está contenido en un archivo QML, photosurface.qml. El código JavaScript en línea coloca, rota y escala las imágenes en la superficie de la foto.
Ejecución del ejemplo
Para ejecutar el ejemplo desde Qt Creatorabra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.
Crear la ventana principal
Para crear la ventana principal de la aplicación Photo Surface, utiliza el tipo QML Window como elemento raíz. Automáticamente configura la ventana para su uso con Qt Quick tipos gráficos:
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
Acceder al contenido de la carpeta
Utiliza un tipo QML Repeater junto con el FolderListModel para mostrar las imágenes GIF, JPG y PNG localizadas en una carpeta (aunque main.cpp puede ampliar la lista de tipos de imagen soportados):
Repeater { model: FolderListModel { id: folderModel objectName: "folderModel" showDirs: false nameFilters: root.imageNameFilters }
Importe el tipo FolderListModel:
import Qt.labs.folderlistmodel
Un FolderDialog permite a los usuarios seleccionar la carpeta que contiene las imágenes:
FolderDialog { id: folderDialog title: qsTr("Choose a folder with some images") onAccepted: folderModel.folder = selectedFolder }
Para utilizar el tipo FolderDialog, añada la siguiente sentencia import:
import QtQuick.Dialogs
La función folderDialog.open() abre el diálogo de archivo cuando finaliza la presentación de diapositivas inicial, a menos que se haya proporcionado una ruta de carpeta como argumento de la línea de comandos:
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() }
Los usuarios también pueden hacer clic en el icono de diálogo de carpeta para abrirlo. Aquí, un tipo QML Imagen muestra el icono. Dentro del tipo Image, un TapHandler con el manejador de señal onTapped llama a la función 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() } }
Visualización de imágenes en la superficie fotográfica
Un Rectangle se utiliza como delegado de un Repeater para proporcionar un marco para cada imagen que el FolderListModel encuentra en la carpeta seleccionada. Los métodos JavaScript Math() colocan los marcos aleatoriamente en la superficie de la foto, los giran en ángulos aleatorios y escalan las imágenes. El color del borde indica el estado de la interacción:
delegate: Rectangle { id: photoFrame required property date fileModified required property string fileName required property url fileUrl 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 }
Manejo de los gestos de arrastrar y pellizcar, y del ratón
Un DragHandler y un PinchHandler en cada marco de foto manejan los gestos de arrastrar, pellizcar y rotar:
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) } }
Debido a que el PinchHandler se declara dentro del Rectángulo, la propiedad PinchHandler.target se establece implícitamente para que los gestos de pellizco manipulen el Rectángulo. Las propiedades de rotación especifican que los marcos se pueden rotar en todos los ángulos, y las propiedades de escala especifican que se pueden escalar entre 0.1 y 10. El gesto de pellizcar funciona igual de bien en una pantalla táctil o en un panel táctil multitáctil. Transformar el marco transforma su contenido (la Imagen).
La propiedad DragHandler.target también se establece implícitamente, de modo que se puede arrastrar una foto con un dedo en una pantalla táctil o touchpad, o con un ratón. En el manejador de señales DragHandler's onActiveChanged, el marco de la foto seleccionada se eleva a la parte superior aumentando el valor de su propiedad z (mientras que la propiedad compartida highestZ mantiene el mayor valor z que se haya utilizado hasta el momento). Cuando finaliza el arrastre, comienza una animación que lo mantiene en movimiento en la misma dirección durante un rato, ralentizándose y llegando a detenerse. Si "lanza" una foto más allá del borde de la superficie, ésta se expande para adaptarse a su nueva posición. Puedes desplazarte para ver distintas partes de la superficie a través de la página ScrollView que contiene el Repetidor y todos los marcos de fotos que rellena.
Como puede arrastrar dos fotos con dos dedos a través de sus DragHandlers, y también puede pellizcar una PinchHandler con dos dedos, y las colecciones de fotos tienden a apilarse unas sobre otras, necesita ajustar grabPermissions para que el PinchHandler tenga prioridad: cuando comienza el gesto de pellizcar, no permite que los DragHandlers vuelvan a hacerse cargo de los agarres de los puntos de contacto.
Para hacer el ejemplo más interactivo en ordenadores sin dispositivos táctiles, añade el HoverHandler del que depende el border.color anterior, y dos WheelHandlers. Uno te permite mantener pulsada la tecla Ctrl y utilizar la rueda del ratón para hacer girar la foto alrededor del cursor del ratón; con el otro, puedes mantener pulsada la tecla Mayús y utilizar la rueda del ratón para acercar o alejar la posición bajo el cursor. Ambas opciones también levantan la foto de la misma forma que lo hace la página DragHandler anterior:
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 }
Archivos fuente
Ver también Aplicaciones QML y Qt Quick Ejemplos y Tutoriales.
© 2026 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.