本页内容

QML 相机应用程序

此基于Qt Quick 的应用程序演示了如何使用API拍摄静态图像或录制视频。

相机应用在横屏模式下显示实时预览和拍摄控制按钮

本示例演示了如何通过 QML 访问相机功能,并展示了如何更改设置以及拍摄静止图像或视频。

运行示例

您可以通过以下方式运行该示例:

应用程序结构

本示例中的大部分 QML 代码用于支持用户界面。已利用现有的Qt Quick 控件实现了满足相关要求的自定义类型。

利用屏幕方向选择布局

屏幕方向和控件布局状态的逻辑封装在一个独立的 Item(controlLayout )中,如下所示:

Item {
    id: controlLayout

    readonly property bool isMobile: Qt.platform.os === "android" || Qt.platform.os === "ios"
    readonly property bool isLandscape: Screen.desktopAvailableWidth >= Screen.desktopAvailableHeight
    property int buttonsWidth: state === "MobilePortrait" ? Screen.desktopAvailableWidth / 3.4 : 114

    states: [
        State {
            name: "MobileLandscape"
            when: controlLayout.isMobile && controlLayout.isLandscape
        },
        State {
            name: "MobilePortrait"
            when: controlLayout.isMobile && !controlLayout.isLandscape
        },
        State {
            name: "Other"
            when: !controlLayout.isMobile
        }
    ]

    onStateChanged: {
        console.log("State: " + controlLayout.state)
    }
}

stillControls 和videoControls 对象均绑定到该Item的state 和buttonsWidth 属性,如stillControls 所示:

PhotoCaptureControls {
    id: stillControls
    state: controlLayout.state
    anchors.fill: parent
    buttonsWidth: controlLayout.buttonsWidth
    buttonsPanelPortraitHeight: cameraUI.buttonsPanelPortraitHeight
    buttonsPanelWidth: cameraUI.buttonsPanelLandscapeWidth
    captureSession: captureSession
    visible: (cameraUI.state === "PhotoCapture")
    onPreviewSelected: cameraUI.state = "PhotoPreview"
    onVideoModeSelected: cameraUI.state = "VideoCapture"
    previewAvailable: imageCapture.preview.length !== 0
}

为了支持调试,系统会记录一条关于布局状态变化的日志。

以下是纵向布局:

相机应用在纵向模式下显示实时预览和拍摄控制按钮

可以看到,state 属性初始值被设置为PhotoCapture 。

随后,states 本身被定义如下:

states: [
    State {
        name: "PhotoCapture"
        StateChangeScript {
            script: {
                camera.start()
            }
        }
    },
    State {
        name: "PhotoPreview"
    },
    State {
        name: "VideoCapture"
        StateChangeScript {
            script: {
                camera.start()
            }
        }
    },
    State {
        name: "VideoPreview"
        StateChangeScript {
            script: {
                camera.stop()
            }
        }
    }
]

用于捕获的控件

用于捕获的控件在PhotoCaptureControls.qml 和VideoCaptureControls.qml中实现。它们均基于FocusScope ,该文件定义了控件按钮所使用的通用按钮尺寸和边距,随后声明了这些按钮。

这会在屏幕右侧生成一列控件,其中从上到下依次包含以下控件:

  • 一个Capture 或Record 按钮,用于启动捕获。
  • 一个capture properties 按钮,用于显示当前所选白平衡模式的图标;按下该按钮时,会通过弹出窗口显示以下选项的图标:
    • 闪光灯模式(如有)
    • 白平衡模式
    • 曝光补偿
  • View 按钮,在完成拍摄后显示。
  • 一个用于显示当前选定拍摄设备的按钮,按下后会通过弹出窗口提供可供切换的设备列表。
  • 一个Switch To 按钮,根据当前的活动选择显示替代捕获模式(视频或照片),按下时切换模式。
  • 一个Quit 按钮,用于退出应用程序。

照片拍摄控制面板

视频采集控制面板

图像拍摄

触发此功能的按钮在 CameraButton.qml 中定义:但其与相机的交互逻辑位于控件类型中,让我们看看 PhotoCaptureControls:

CameraButton {
    text: "Capture"
    implicitWidth: captureControls.buttonsWidth
    visible: captureControls.captureSession.imageCapture.readyForCapture
    onClicked: captureControls.captureSession.imageCapture.captureToFile("")
}

变焦控件

ZoomControl 类型在ZoomControl.qml 中实现,基于 Item 构建,并生成一条表示变焦级别的滑动条,该滑动条支持拖动。它采用指数计算方法,根据grove 的位置来确定变焦倍数。

只有当 initialZoom 大于 1 时,该进度条才会显示。这意味着当前活动的相机具有变焦功能。

可调节的缩放级别滑块

Item {
    id : zoomControl
    property real currentZoom : 1
    property real maximumZoom : 1
    property real minimumZoom : 1
    signal zoomTo(real target)

    visible: zoomControl.maximumZoom > zoomControl.minimumZoom

    MouseArea {
        id : mouseArea
        anchors.fill: parent

        property real initialZoom : 0
        property real initialPos : 0

        onPressed: {
            initialPos = mouseY
            initialZoom = zoomControl.currentZoom
        }

        onPositionChanged: {
            if (pressed) {
                var target = initialZoom * Math.pow(5, (initialPos-mouseY)/zoomControl.height);
                target = Math.max(zoomControl.minimumZoom, Math.min(target, zoomControl.maximumZoom))
                zoomControl.zoomTo(target)
            }
        }
    }

    Item {
        id : bar
        x : 16
        y : parent.height/4
        width : 24
        height : parent.height/2

        Rectangle {
            anchors.fill: parent

            smooth: true
            radius: 8
            border.color: "white"
            border.width: 2
            color: "black"
            opacity: 0.3
        }

        Rectangle {
            id: groove
            x : 0
            y : parent.height * (1.0 - (zoomControl.currentZoom-zoomControl.minimumZoom) / (zoomControl.maximumZoom-zoomControl.minimumZoom))
            width: parent.width
            height: parent.height - y
            smooth: true
            radius: 8
            color: "white"
            opacity: 0.5
        }

        Text {
            id: zoomText
            anchors {
                left: bar.right; leftMargin: 16
            }
            y: Math.min(parent.height - height, Math.max(0, groove.y - height / 2))
            text: "x" + Math.round(zoomControl.currentZoom * 100) / 100
            font.bold: true
            color: "white"
            style: Text.Raised; styleColor: "black"
            opacity: 0.85
            font.pixelSize: 18
        }
    }
}

在 PhotoCaptureControls.qml 和 VideoCaptureControls.qml 中,zoomTo 信号将把所选摄像机的zoomFactor 属性设置为计算出的target 值,并更新 ZoomControl 滑块。

ZoomControl {
    x : 0
    y : 0
    width : 100
    height: parent.height - (flashControl.visible * flashControl.height) -
            (captureControls.state === "MobilePortrait" ? buttonPaneShadow.height : 0)

    currentZoom: captureControls.camera.zoomFactor
    maximumZoom: captureControls.camera.maximumZoomFactor
    minimumZoom: captureControls.camera.minimumZoomFactor
    onZoomTo: (target) => captureControls.camera.zoomFactor = target
}

闪光灯和手电筒控制

在闪光灯和手电筒模式之间切换

该功能在FlashControl.qml 中定义,允许通过开关(Switch)选择闪光灯模式并切换手电筒功能。与变焦控制类似,只有当当前设备支持这些功能时,这些开关才会显示在预览窗口上方。

在此处,我们检查设备是否支持这些功能:

required property Camera camera

property bool mIsFlashSupported: camera.isFlashModeSupported(Camera.FlashOn)
property bool mIsTorchSupported: camera.isTorchModeSupported(Camera.TorchOn)

在此我们实现了flashModeControl 开关,该开关还直接控制相机设备。

Switch {
    id: flashModeControl
    visible: topItem.mIsFlashSupported
    checked: topItem.camera.flashMode === Camera.FlashOn
    opacity: checked ? 0.75 : 0.25
    text: "Flash"

    contentItem: Text {
        text: flashModeControl.text
        color: "white"
        leftPadding: flashModeControl.indicator.width + flashModeControl.spacing
    }

    onClicked: topItem.camera.flashMode = checked ? Camera.FlashOn : Camera.FlashOff
}

手电筒控制的实现方式与此类似。

示例项目 @ code.qt.io

© 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.