当前位置: 首页 > news >正文

开源 C++ QT QML 开发(二十)多媒体--摄像头拍照

           文章的目的为了记录使用QT QML开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

 相关链接:

开源 C++ QT QML 开发(一)基本介绍

开源 C++ QT QML 开发(二)工程结构

开源 C++ QT QML 开发(三)常用控件

开源 C++ QT QML 开发(四)复杂控件--Listview

开源 C++ QT QML 开发(五)复杂控件--Gridview

开源 C++ QT QML 开发(六)自定义控件--波形图

开源 C++ QT QML 开发(七)自定义控件--仪表盘

推荐链接:

开源 C# 快速开发(一)基础知识

开源 C# 快速开发(二)基础控件

开源 C# 快速开发(三)复杂控件

开源 C# 快速开发(四)自定义控件--波形图

开源 C# 快速开发(五)自定义控件--仪表盘

开源 C# 快速开发(六)自定义控件--圆环

开源 C# 快速开发(七)通讯--串口

开源 C# 快速开发(八)通讯--Tcp服务器端

开源 C# 快速开发(九)通讯--Tcp客户端

开源 C# 快速开发(十)通讯--http客户端

开源 C# 快速开发(十一)线程

开源 C# 快速开发(十二)进程监控

开源 C# 快速开发(十三)进程--管道通讯

开源 C# 快速开发(十四)进程--内存映射

开源 C# 快速开发(十五)进程--windows消息

开源 C# 快速开发(十六)数据库--sqlserver增删改查

本章节主要内容是:演示了基于qt和qml的多媒体应用中,笔记本电脑摄像头的拍照功能。

1.代码分析

2.所有源码

3.效果演示

一、代码分析

1. Backend.h 详细分析
构造函数分析

explicit Backend(QObject *parent = nullptr) : QObject(parent) {// 创建保存图片的目录QString picturesPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);m_saveDir = QDir(picturesPath).filePath("CameraDiagnosticTool");if (!QDir().exists(m_saveDir)) {QDir().mkpath(m_saveDir);}qDebug() << "图片保存目录:" << m_saveDir;
}


功能细节:

QStandardPaths::writableLocation(QStandardPaths::PicturesLocation):获取系统标准的图片存储路径

Windows: C:\Users\Username\Pictures

macOS: /Users/Username/Pictures

Linux: /home/Username/Pictures

QDir(picturesPath).filePath("CameraDiagnosticTool"):构建应用专属目录路径

QDir().mkpath(m_saveDir):递归创建目录,确保父目录存在

输出目录信息便于调试

onImageCaptured 函数
 

void onImageCaptured(const QString &previewPath) {QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");qDebug() << "[" << timestamp << "] 图像已捕获,预览路径:" << previewPath;emit statusMessageChanged("照片已捕获,显示预览");
}


参数分析:

const QString &previewPath:常量引用传递,避免拷贝开销

预览路径通常是临时文件路径

时间格式化:

"yyyy-MM-dd hh:mm:ss":年-月-日 时:分:秒 格式

使用24小时制建议改为 "yyyy-MM-dd HH:mm:ss"

onImageSaved 函数
 

void onImageSaved(int requestId, const QString &filePath) {QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");qDebug() << "[" << timestamp << "] 图像已保存,请求ID:" << requestId << "路径:" << filePath;emit statusMessageChanged(QString("照片已保存到: %1").arg(filePath));
}


参数说明:

requestId:异步操作标识符,用于匹配请求和响应

filePath:最终保存的完整文件路径

showMessage 函数
 

void showMessage(const QString &message) {QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");qDebug() << "[" << timestamp << "]" << message;emit statusMessageChanged(message);
}


设计模式:Facade模式,统一消息处理接口


captureImage 函数
 

Q_INVOKABLE void captureImage(const QImage &image) {if (image.isNull()) {emit statusMessageChanged("错误: 捕获的图像为空");return;}// 生成文件名QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss_zzz");QString fileName = QString("capture_%1.jpg").arg(timestamp);QString filePath = QDir(m_saveDir).filePath(fileName);// 保存图片if (image.save(filePath, "JPG", 90)) {emit statusMessageChanged(QString("照片已保存: %1").arg(fileName));emit imageSaved(filePath);qDebug() << "图片保存成功:" << filePath;} else {emit statusMessageChanged("错误: 保存图片失败");qDebug() << "图片保存失败:" << filePath;}
}


关键点分析:

Q_INVOKABLE:使C++函数在QML中可调用

image.isNull():健壮性检查

时间戳格式:"yyyyMMdd_hhmmss_zzz" 包含毫秒,避免重名

图片质量:JPG格式,90%质量平衡文件大小和清晰度

双信号发射:状态消息 + 保存完成通知

getSaveDirectory 函数
 

Q_INVOKABLE QString getSaveDirectory() const {return m_saveDir;
}


const 修饰符:线程安全,不会修改对象状态

简单的getter函数,提供目录信息给QML


2. main.qml 详细分析
属性定义
 

property string lastCapturedImage: ""
property var cameraList: QtMultimedia.availableCameras || []
property int currentCameraIndex: 0
属性分析:lastCapturedImage:记录最后捕获的图片路径cameraList:使用 || [] 提供默认值,防止undefinedcurrentCameraIndex:当前选中摄像头的索引

摄像头信息区域
 

Label {text: {if (cameraList.length > 0) {var cam = cameraList[currentCameraIndex]return "当前摄像头: " + (cam.displayName || "未知摄像头")} else {return "未检测到摄像头"}}color: "#ecf0f1"
}


绑定表达式:使用JavaScript代码块动态计算文本内容


Camera 组件分析
 

Camera {id: cameradeviceId: cameraList.length > 0 ? cameraList[currentCameraIndex].deviceId : ""position: cameraList.length > 0 ? cameraList[currentCameraIndex].position : Camera.UnspecifiedPositiononError: {var errorMsg = "摄像头错误: " + errorString + " (错误代码: " + error + ")"console.log(errorMsg)backend.showMessage(errorMsg)}
}


错误处理机制:

errorString:人类可读的错误描述

error:错误代码,用于程序化处理

同时输出到控制台和用户界面


VideoOutput 中的图像捕获
 

VideoOutput {id: videoOutput// ... 其他属性property var imageCapture: camera.imageCapturefunction captureImage() {if (camera.cameraStatus === Camera.ActiveStatus) {backend.showMessage("正在拍照...")camera.imageCapture.captureToLocation(backend.getSaveDirectory() + "/capture_" + new Date().toLocaleString(Qt.locale(), "yyyyMMdd_hhmmss_zzz") + ".jpg")} else {backend.showMessage("错误: 请先启动摄像头")}}
}


关键函数:

camera.imageCapture:Qt 5.14中访问ImageCapture的方式

captureToLocation():直接保存到指定路径的异步方法

路径构建:与C++端保持一致的命名规则

状态覆盖层函数
qml
function getStatusText() {
    switch(camera.cameraStatus) {
    case Camera.ActiveStatus:
        return "摄像头运行正常";
    case Camera.StartingStatus:
        return "摄像头启动中...";
    case Camera.StoppingStatus:
        return "摄像头停止中...";
    case Camera.StandbyStatus:
        return "摄像头待机中";
    case Camera.LoadedStatus:
        return "摄像头已加载";
    case Camera.LoadingStatus:
        return "摄像头加载中...";
    case Camera.UnloadingStatus:
        return "摄像头卸载中...";
    case Camera.UnloadedStatus:
        return "摄像头未加载";
    case Camera.UnavailableStatus:
        return "摄像头不可用";
    default:
        return "摄像头状态未知: " + camera.cameraStatus;
    }
}
状态机处理:完整覆盖Camera的所有可能状态信号连接系统

// 连接后端信号

Connections {target: backendonStatusMessageChanged: {var timestamp = new Date().toLocaleTimeString()statusText.text = "[" + timestamp + "] " + message + "\n" + statusText.text}onImageSaved: {photoPreview.source = "file:///" + filePath}
}// 连接摄像头图像捕获信号
Connections {target: camera.imageCaptureonImageCaptured: {photoPreview.source = previewbackend.onImageCaptured(preview)}onImageSaved: {backend.onImageSaved(requestId, path)backend.showMessage("照片已保存: " + path)}
}


多目标连接:

后端状态消息:更新日志显示

图像保存完成:更新预览图片

摄像头捕获事件:处理预览和保存


组件初始化
 

Component.onCompleted: {backend.showMessage("应用程序启动完成")backend.showMessage("检测到 " + cameraList.length + " 个摄像头")backend.showMessage("照片保存目录: " + backend.getSaveDirectory())if (cameraList.length === 0) {backend.showMessage("警告: 未检测到任何摄像头设备")backend.showMessage("请检查摄像头连接和驱动程序")} else {for (var i = 0; i < cameraList.length; i++) {var cam = cameraList[i]backend.showMessage("摄像头 " + i + ": " + (cam.displayName || "未知") +" (位置: " + getPositionName(cam.position) + ")")}}
}


启动流程:

应用启动通知

摄像头数量检测

目录信息显示

设备详情枚举


3. main.cpp 详细分析
主函数结构
 

int main(int argc, char *argv[])
{// 1. 应用程序属性设置QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);// 2. 应用程序实例化QGuiApplication app(argc, argv);// 3. 应用程序元数据app.setApplicationName("笔记本电脑摄像头诊断工具");app.setApplicationVersion("1.1");app.setOrganizationName("YourCompany");// 4. 后端对象创建Backend backend;// 5. QML引擎初始化QQmlApplicationEngine engine;// 6. 上下文属性设置engine.rootContext()->setContextProperty("backend", &backend);// 7. QML文件加载engine.load(QUrl(QStringLiteral("qrc:/main.qml")));// 8. 启动检查if (engine.rootObjects().isEmpty()) {return -1;}// 9. 调试信息输出qDebug() << "照片保存目录:" << backend.getSaveDirectory();// 10. 事件循环启动return app.exec();
}


关键技术点分析
高DPI支持:


QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
自动适配高分辨率显示器

解决在高DPI设备上界面元素过小的问题

应用程序元数据:


app.setApplicationName("笔记本电脑摄像头诊断工具");
app.setApplicationVersion("1.1");
app.setOrganizationName("YourCompany");
用于系统集成(如设置存储、关于对话框等)

遵循Qt应用程序最佳实践

上下文属性绑定:


engine.rootContext()->setContextProperty("backend", &backend);
将C++对象注入QML上下文

在QML中通过 backend 标识符访问

资源加载机制:


engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
使用Qt资源系统(qrc)

编译时嵌入资源,避免运行时文件依赖

健全性检查:


if (engine.rootObjects().isEmpty()) {
    return -1;
}
确保QML文件正确加载

防止空窗口应用程序

整体架构总结
数据流向
text
用户操作 → QML界面 → 信号发射 → C++后端处理 → 文件系统操作
                                     ↓
状态反馈 ← 信号发射 ← QML更新 ←───┘

二、所有源码

.pro文件添加

QT += quick quickcontrols2 multimedia

backend.h文件源码

#ifndef BACKEND_H
#define BACKEND_H#include <QObject>
#include <QString>
#include <QDebug>
#include <QDateTime>
#include <QImage>
#include <QDir>
#include <QStandardPaths>class Backend : public QObject
{Q_OBJECTpublic:explicit Backend(QObject *parent = nullptr) : QObject(parent) {// 创建保存图片的目录QString picturesPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);m_saveDir = QDir(picturesPath).filePath("CameraDiagnosticTool");if (!QDir().exists(m_saveDir)) {QDir().mkpath(m_saveDir);}qDebug() << "图片保存目录:" << m_saveDir;}public slots:// 处理图像捕获事件void onImageCaptured(const QString &previewPath) {QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");qDebug() << "[" << timestamp << "] 图像已捕获,预览路径:" << previewPath;emit statusMessageChanged("照片已捕获,显示预览");}// 处理图像保存事件void onImageSaved(int requestId, const QString &filePath) {QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");qDebug() << "[" << timestamp << "] 图像已保存,请求ID:" << requestId << "路径:" << filePath;emit statusMessageChanged(QString("照片已保存到: %1").arg(filePath));}// 显示消息void showMessage(const QString &message) {QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");qDebug() << "[" << timestamp << "]" << message;emit statusMessageChanged(message);}// 拍照并保存Q_INVOKABLE void captureImage(const QImage &image) {if (image.isNull()) {emit statusMessageChanged("错误: 捕获的图像为空");return;}// 生成文件名QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss_zzz");QString fileName = QString("capture_%1.jpg").arg(timestamp);QString filePath = QDir(m_saveDir).filePath(fileName);// 保存图片if (image.save(filePath, "JPG", 90)) {emit statusMessageChanged(QString("照片已保存: %1").arg(fileName));emit imageSaved(filePath);qDebug() << "图片保存成功:" << filePath;} else {emit statusMessageChanged("错误: 保存图片失败");qDebug() << "图片保存失败:" << filePath;}}// 获取保存目录Q_INVOKABLE QString getSaveDirectory() const {return m_saveDir;}signals:void statusMessageChanged(const QString &message);void imageSaved(const QString &filePath);private:QString m_saveDir;
};#endif // BACKEND_H

main.qml文件源码

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtMultimedia 5.12ApplicationWindow {id: mainWindowwidth: 800height: 600title: "笔记本电脑摄像头诊断工具"visible: trueproperty string lastCapturedImage: ""property var cameraList: QtMultimedia.availableCameras || []property int currentCameraIndex: 0// 背景Rectangle {anchors.fill: parentgradient: Gradient {GradientStop { position: 0.0; color: "#2c3e50" }GradientStop { position: 1.0; color: "#34495e" }}}ColumnLayout {anchors.fill: parentanchors.margins: 10spacing: 10// 标题Label {text: "摄像头诊断工具"Layout.alignment: Qt.AlignHCentercolor: "white"font.pixelSize: 24font.bold: true}// 摄像头信息区域Rectangle {Layout.fillWidth: trueLayout.preferredHeight: 100color: "#34495e"radius: 5border.color: "#7f8c8d"ColumnLayout {anchors.fill: parentanchors.margins: 10Label {text: "摄像头信息:"color: "white"font.bold: true}Label {text: "检测到的摄像头数量: " + cameraList.lengthcolor: "#ecf0f1"}Label {text: {if (cameraList.length > 0) {var cam = cameraList[currentCameraIndex]return "当前摄像头: " + (cam.displayName || "未知摄像头")} else {return "未检测到摄像头"}}color: "#ecf0f1"}// 摄像头选择(如果有多个摄像头)ComboBox {id: cameraSelectorLayout.fillWidth: truemodel: cameraListvisible: cameraList.length > 1textRole: "displayName"onCurrentIndexChanged: {if (camera.cameraStatus === Camera.ActiveStatus) {camera.stop()}currentCameraIndex = currentIndexbackend.showMessage("已选择摄像头: " + currentText)}}}}// 摄像头预览区域Rectangle {id: previewContainerLayout.fillWidth: trueLayout.fillHeight: truecolor: "#1a1a1a"border.color: camera.cameraStatus === Camera.ActiveStatus ? "#27ae60" : "#e74c3c"border.width: 2radius: 8Camera {id: cameradeviceId: cameraList.length > 0 ? cameraList[currentCameraIndex].deviceId : ""position: cameraList.length > 0 ? cameraList[currentCameraIndex].position : Camera.UnspecifiedPositiononError: {var errorMsg = "摄像头错误: " + errorString + " (错误代码: " + error + ")"console.log(errorMsg)backend.showMessage(errorMsg)}onCameraStateChanged: {var stateMsg = "摄像头状态: "switch(camera.cameraState) {case Camera.ActiveState:stateMsg += "运行中";break;case Camera.LoadedState:stateMsg += "已加载";break;case Camera.UnloadedState:stateMsg += "未加载";break;default:stateMsg += "未知状态";}backend.showMessage(stateMsg)}onCameraStatusChanged: {var statusMsg = "摄像头状态码: " + camera.cameraStatusbackend.showMessage(statusMsg)}}VideoOutput {id: videoOutputanchors.fill: parentanchors.margins: 5source: camerafillMode: VideoOutput.PreserveAspectCropfocus: visible// 在 Qt 5.x 中,ImageCapture 需要这样使用property var imageCapture: camera.imageCapturefunction captureImage() {if (camera.cameraStatus === Camera.ActiveStatus) {backend.showMessage("正在拍照...")camera.imageCapture.captureToLocation(backend.getSaveDirectory() + "/capture_" +new Date().toLocaleString(Qt.locale(), "yyyyMMdd_hhmmss_zzz") + ".jpg")} else {backend.showMessage("错误: 请先启动摄像头")}}}// 状态覆盖层Rectangle {anchors.fill: parentcolor: "#80000000"visible: camera.cameraStatus !== Camera.ActiveStatusColumn {anchors.centerIn: parentspacing: 10Label {text: getStatusText()color: "white"font.pixelSize: 16anchors.horizontalCenter: parent.horizontalCenter}BusyIndicator {running: camera.cameraStatus === Camera.StartingStatusanchors.horizontalCenter: parent.horizontalCentervisible: running}}}function getStatusText() {switch(camera.cameraStatus) {case Camera.ActiveStatus:return "摄像头运行正常";case Camera.StartingStatus:return "摄像头启动中...";case Camera.StoppingStatus:return "摄像头停止中...";case Camera.StandbyStatus:return "摄像头待机中";case Camera.LoadedStatus:return "摄像头已加载";case Camera.LoadingStatus:return "摄像头加载中...";case Camera.UnloadingStatus:return "摄像头卸载中...";case Camera.UnloadedStatus:return "摄像头未加载";case Camera.UnavailableStatus:return "摄像头不可用";default:return "摄像头状态未知: " + camera.cameraStatus;}}}// 控制按钮区域RowLayout {Layout.alignment: Qt.AlignHCenterspacing: 20Button {id: startButtontext: "启动摄像头"Layout.preferredWidth: 140Layout.preferredHeight: 40background: Rectangle {color: parent.down ? "#27ae60" :parent.hovered ? "#2ecc71" : "#27ae60"radius: 5}contentItem: Text {text: parent.textcolor: "white"horizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenterfont.pixelSize: 14font.bold: true}onClicked: {backend.showMessage("正在启动摄像头...")console.log("尝试启动摄像头,设备ID:", camera.deviceId)camera.start()}}Button {id: stopButtontext: "停止摄像头"Layout.preferredWidth: 140Layout.preferredHeight: 40background: Rectangle {color: parent.down ? "#c0392b" :parent.hovered ? "#e74c3c" : "#c0392b"radius: 5}contentItem: Text {text: parent.textcolor: "white"horizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenterfont.pixelSize: 14font.bold: true}onClicked: {camera.stop()backend.showMessage("摄像头已停止")}}// 拍照按钮Button {id: captureButtontext: "拍照"Layout.preferredWidth: 140Layout.preferredHeight: 40enabled: camera.cameraStatus === Camera.ActiveStatusbackground: Rectangle {color: parent.down ? "#f39c12" :parent.hovered ? "#f1c40f" :parent.enabled ? "#f39c12" : "#95a5a6"radius: 5}contentItem: Text {text: parent.textcolor: "white"horizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenterfont.pixelSize: 14font.bold: true}onClicked: {videoOutput.captureImage()}}Button {id: refreshButtontext: "刷新摄像头列表"Layout.preferredWidth: 140Layout.preferredHeight: 40background: Rectangle {color: parent.down ? "#2980b9" :parent.hovered ? "#3498db" : "#2980b9"radius: 5}contentItem: Text {text: parent.textcolor: "white"horizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenterfont.pixelSize: 14font.bold: true}onClicked: {// 强制刷新摄像头列表cameraList = QtMultimedia.availableCameras || []backend.showMessage("已刷新摄像头列表,检测到 " + cameraList.length + " 个摄像头")}}}// 图片预览区域Rectangle {id: previewSectionLayout.fillWidth: trueLayout.preferredHeight: 150color: "transparent"visible: photoPreview.source !== ""Label {text: "最新照片预览:"color: "white"font.bold: trueanchors.top: parent.topanchors.left: parent.left}RowLayout {anchors.fill: parentanchors.topMargin: 25spacing: 10// 图片预览Image {id: photoPreviewLayout.preferredWidth: 120Layout.preferredHeight: 120fillMode: Image.PreserveAspectFitcache: false}// 照片信息ColumnLayout {Layout.fillWidth: truespacing: 5Label {text: "尺寸: " + (photoPreview.sourceSize.width + "x" + photoPreview.sourceSize.height)color: "#ecf0f1"font.pixelSize: 12}Label {text: "保存目录:"color: "#ecf0f1"font.pixelSize: 12font.bold: true}Label {text: backend.getSaveDirectory()color: "#bdc3c7"font.pixelSize: 10wrapMode: Text.WrapLayout.maximumWidth: 400}Button {text: "打开保存文件夹"Layout.preferredWidth: 120Layout.preferredHeight: 30visible: Qt.platform.os !== "android" && Qt.platform.os !== "ios"background: Rectangle {color: parent.down ? "#16a085" :parent.hovered ? "#1abc9c" : "#16a085"radius: 3}contentItem: Text {text: parent.textcolor: "white"horizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenterfont.pixelSize: 11}onClicked: {Qt.openUrlExternally("file:///" + backend.getSaveDirectory())}}}}}// 诊断信息区域Rectangle {Layout.fillWidth: trueLayout.preferredHeight: 80color: "#2c3e50"radius: 5border.color: "#7f8c8d"ScrollView {anchors.fill: parentanchors.margins: 5TextArea {id: statusTextreadOnly: truewrapMode: Text.Wrapcolor: "#ecf0f1"font.pixelSize: 11background: nulltext: "应用程序已启动\n" +"正在初始化摄像头系统..."}}}}// 连接后端信号Connections {target: backendonStatusMessageChanged: {var timestamp = new Date().toLocaleTimeString()statusText.text = "[" + timestamp + "] " + message + "\n" + statusText.text}onImageSaved: {photoPreview.source = "file:///" + filePath}}// 连接摄像头图像捕获信号Connections {target: camera.imageCaptureonImageCaptured: {photoPreview.source = previewbackend.onImageCaptured(preview)}onImageSaved: {backend.onImageSaved(requestId, path)backend.showMessage("照片已保存: " + path)}}// 应用启动时自动检测Component.onCompleted: {backend.showMessage("应用程序启动完成")backend.showMessage("检测到 " + cameraList.length + " 个摄像头")backend.showMessage("照片保存目录: " + backend.getSaveDirectory())if (cameraList.length === 0) {backend.showMessage("警告: 未检测到任何摄像头设备")backend.showMessage("请检查摄像头连接和驱动程序")} else {for (var i = 0; i < cameraList.length; i++) {var cam = cameraList[i]backend.showMessage("摄像头 " + i + ": " + (cam.displayName || "未知") +" (位置: " + getPositionName(cam.position) + ")")}}}function getPositionName(position) {switch(position) {case Camera.BackFace: return "后置";case Camera.FrontFace: return "前置";case Camera.UnspecifiedPosition: return "未指定";default: return "未知";}}// 应用退出时停止摄像头onClosing: {camera.stop()}
}

main.cpp文件源码

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QIcon>
#include "backend.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);// 设置应用程序信息app.setApplicationName("笔记本电脑摄像头诊断工具");app.setApplicationVersion("1.1");app.setOrganizationName("YourCompany");// 注册后端类Backend backend;QQmlApplicationEngine engine;// 将后端对象暴露给QMLengine.rootContext()->setContextProperty("backend", &backend);// 加载QML文件engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty()) {return -1;}// 显示保存目录信息qDebug() << "照片保存目录:" << backend.getSaveDirectory();return app.exec();
}

三、效果演示

点击启动摄像头,进行拍照,照片自动保存,同时具有预览功能。

http://www.dtcms.com/a/482246.html

相关文章:

  • Redis速通
  • 误删mysql某表数据,通过binlog2sql工具数据恢复
  • MyBatisPlus中LambdaQueryChainWrapper链式条件查询的常用示例
  • STM32与W25Q64 SPI通信全解析
  • 创办个人网站淘客怎样做网站
  • 网站流量用完了湘潭网络公司
  • Cogent DataHub vs Kepware,两大工业数据中间件的深度对比分析
  • ElasticSearch沙盒绕过漏洞复现:原理详解+环境搭建+渗透实践(CVE-2015-1427)
  • 学习笔记《区块链技术与应用》ETH 第三天 GHOST协议
  • 分辨海外IP是否为住宅IP的方法
  • 处理文本编辑器存的json格式报错问题,对编辑器存的字段进行转换处理,再通过json返回
  • 电子电气架构 --- 智能化浪潮下汽车软件架构的革新与生态重构
  • 【春秋云镜】CVE-2024-9047 Wordpress File Upload 插件 文件遍历漏洞
  • yahoo怎么提交网站下载拼多多app免费下载
  • php网站怎么注入网业协同是什么意思
  • 天机学堂day10领取优惠券接口编写mapper层sql语句时无法解析表的解决办法(更加完整、详细图解)
  • 力扣Hot100--102.二叉树的层序遍历
  • 【Linux】udp网络程序
  • 网站首页地址 网站域名海外购物商城
  • 解码Linux文件IO之标准IO
  • React惰性初始化函数(Lazy Initializer)(首次渲染时执行一次,只执行一次,应对昂贵初始化逻辑)(传入一个函数、传入函数)
  • C++中的类
  • 网站上线 流程wordpress禁止加载谷歌字体
  • 阿里云是做网站的吗榆林公司做网站
  • 2018年10月江苏省自考《信息组织》试题
  • 跨域处理的核心是解决浏览器的“同源策略”限制,主流方案
  • Web 开发 30
  • 小迪web自用笔记62
  • Nginx 代理 WebSocket 失败排查全过程:从 426 到连接成功的完整复盘
  • multi-head attention 多头注意力实现细节