照片表面
一个用于触摸设备的 QML 应用程序,它使用一个带有 FolderListModel 的 Repeater 来访问文件夹中的内容,并使用一个 PinchHandler 来处理获取到的内容上的捏合手势。
照片表面 展示了如何使用 Repeater 和 FolderListModel 以及 FolderDialog 来访问用户选择的文件夹中的图像,以及如何使用 Qt Quick 输入处理程序 在同一个项目内处理拖动、旋转和捏合缩放。
所有应用程序代码都包含在一个 QML 文件中,即 photosurface.qml
。使用内联 JavaScript 代码在照片表面上定位、旋转和缩放图像。
运行示例
要从 Qt Creator 运行示例,请开启 欢迎 模式,然后从 示例 中选择示例。有关更多信息,请参阅 构建和运行示例.
创建主窗口
为了创建 Photo Surface 应用的主窗口,我们使用 Window 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 来显示文件夹中至少包含的 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 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() }
用户还可以点击文件夹对话框图标打开它。我们使用 Image QML 类型来显示图标。在 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() } }
在照片表面显示图片
我们使用一个矩形作为重复器的代理,为文件夹中找到的每一张图片提供框架。我们使用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 }
处理拖拽、捏合手势以及鼠标
我们在每个照片框架中使用拖拽处理程序和捏合处理程序来处理拖拽、捏合缩放和旋转
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.target
属性被隐式设置为捏合手势操纵矩形。旋转属性指定框架可以旋转到所有角度,缩放属性指定它们可以缩放到0.1
和10
之间。捏合手势在触摸屏或多点触控触摸板上都能很好地工作。变换框架将变换其内容(即图片)。
DragHandler.target
属性也被隐式设置,因此您可以在触摸屏或触摸板上使用单指拖拽一张照片,或使用鼠标拖拽。在拖拽处理程序的onActiveChanged
信号处理程序中,我们通过增加其z
属性的值将选中的照片框架提到最上方(而共享的highestZ
属性保存迄今为止使用的最大的z
值)。当拖拽结束时,我们开始一个动画,使其保持移动一段时间,然后减速并停止。如果您将照片“甩”到表面的边缘之外,表面将扩展以适应其新的位置。您可以通过包含重复器和填充它的所有照片框架的滚动视图来查看表面的不同部分。
由于您可以通过它们的拖拽处理程序使用两指拖拽两张照片,您还可以使用两指捏合一个捏合处理程序,照片集合通常堆叠在一起,因此我们需要调整grabPermissions
,以便捏合处理程序具有优先级:当捏合手势开始时,它不允许拖拽处理程序再次抢夺触点抓取。
为了使示例在没有触控设备的电脑上更有交互性,我们在取决于hover处理程序的边框颜色上添加了它,并添加了两个轮处理程序。其中一个允许您按住Ctrl键,然后使用鼠标滚轮围绕鼠标光标旋转照片;使用另一个,按住Shift键然后使用鼠标滚轮在光标下的位置进行缩放。这两个都可以通过与上面提到的拖拽处理程序相同的方式将照片提升起来
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应用程序。
© 2024 The Qt Company Ltd. 本文档中包含的文档贡献归各自的拥有者所有。提供的文档根据自由软件基金会发布的、GNU自由文档许可证版本1.3的条款进行许可。Qt及其相关标志为芬兰及全球其他国家的The Qt Company Ltd.的商标。所有其他商标均为各自拥有者的财产。