基于Qt5的蓝牙打印开发实战:从扫描到小票打印的全流程
文章目录
- 前言
- 一、应用案例演示
- 二、开发环境搭建
- 2.1 硬件准备
- 2.2 软件配置
- 三、蓝牙通信原理剖析
- 3.1 实现原理
- 3.2 通信流程
- 3.3 流程详解
- 3.4 关键技术点
- 四、Qt蓝牙核心类深度解析
- 4.1 QBluetoothDeviceDiscoveryAgent
- 4.2 QBluetoothDeviceInfo
- 4.3 QBluetoothSocket
- 五、功能实现关键步骤
- 5.1 设备扫描与发现
- 5.2 设备连接与状态管理
- 5.3 打印数据封装与发送
前言
本文基于Qt5的蓝牙模块,详细讲解了Linux 下如何实现蓝牙设备扫描、连接、数据通信与打印功能的开发。文章内容涵盖核心类的解析、关键接口设计及讲解,助你快速掌握嵌入式蓝牙应用开发。
一、应用案例演示
演示视频之基于Qt5的蓝牙打印开发实战:从扫描到小票打印
二、开发环境搭建
2.1 硬件准备
- Orange Pi开发板(RK3566芯片)
- 支持SPP协议的蓝牙打印机
我使用的是香橙派的CM4开发板,您可以根据实际需求选择合适的开发板即可,系统信息如下所示:
root@orangepicm4:~# uname -a
Linux orangepicm4 5.10.160-rockchip-rk356x #1.0.6 SMP Mon May 27 17:03:18 CST 2024 aarch64 GNU/Linux
root@orangepicm4:~# cat /etc/issue
Orange Pi 1.0.6 Bullseye \l
而打印机方面,我选择的是这款便携式的热敏打印机:
2.2 软件配置
安装依赖:
sudo apt-get install libbluetooth-dev qtconnectivity5-dev
CMakeList.txt 配置:
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Bluetooth REQUIRED)
target_link_libraries(BluetoothPrinterDemo PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Bluetooth)
三、蓝牙通信原理剖析
3.1 实现原理
蓝牙打印功能基于经典蓝牙(BR/EDR)的SPP协议(Serial Port Profile),核心流程如下:
1. 设备发现: 扫描周围蓝牙设备,筛选支持SPP协议的设备。
2. 建立连接: 通过设备的MAC地址和服务UUID(00001101-0000-1000-8000-00805F9B34FB)创建Socket连接。
3. 数据通信: 向打印机发送符合ESC/POS标准的指令集(文本、格式控制、切纸等)。
4. 资源释放: 断开连接并释放蓝牙资源。
3.2 通信流程
┌─────────────┐ ┌───────────────┐ ┌──────────────┐
│ 启动扫描 │────>│ 发现蓝牙设备 │────>│ 显示设备列表 │
└─────────────┘ └───────────────┘ └──────────────┘│▼
┌─────────────┐ ┌───────────────┐ ┌──────────────┐
│ 用户选择设备 │────>│ 建立Socket连接 │───┬>│ 连接成功 │
└─────────────┘ └───────────────┘ │ └──────────────┘│ │▼ │
┌─────────────┐ ┌───────────────┐ │ ┌──────────────┐
│ 发送打印数据 │<────│ 生成打印指令 │ └─┤ 连接失败/超时 │
└─────────────┘ └───────────────┘ └──────────────┘│▼
┌─────────────┐ ┌───────────────┐
│ 断开连接 │<────│ 完成打印任务 │
└─────────────┘ └───────────────┘
3.3 流程详解
设备发现阶段:
- 调用QBluetoothDeviceDiscoveryAgent.start()启动扫描。
- 过滤设备类型(仅保留经典蓝牙设备)。
- 将设备信息(名称、MAC地址)显示在列表中。
连接阶段:
- 用户选择设备后,通过QBluetoothSocket连接设备的SPP服务。
- 设置超时监控(10秒未连接成功则自动取消)。
打印阶段:
- 数据封装:组合文本内容与ESC/POS指令(如\x1B\x40初始化打印机)。
- 编码处理:中文需转换为GBK编码(兼容大多数国产打印机)。
- 数据发送:通过QBluetoothSocket.write()发送字节流。
断开连接:
- 主动调用disconnectFromService()断开Socket。
- 在析构函数中自动释放资源,防止内存泄漏。
3.4 关键技术点
步骤 | 技术实现 | 对应代码类/方法 |
---|---|---|
设备扫描 | QBluetoothDeviceDiscoveryAgent | start()/deviceDiscovered() |
连接管理 | QBluetoothSocket + 服务UUID | connectToService() |
数据封装 | ESC/POS指令集 + 编码转换 | QByteArray/QTextCodec |
错误处理 | 监听errorOccurred信号 | handleSocketError() |
四、Qt蓝牙核心类深度解析
类名 | 功能说明 |
---|---|
QBluetoothDeviceDiscoveryAgent | 蓝牙设备扫描器,支持经典/低功耗双模式 |
QBluetoothDeviceInfo | 存储设备MAC地址、名称、信号强度等信息 |
QBluetoothSocket | 实现数据读写的核心通信通道 |
4.1 QBluetoothDeviceDiscoveryAgent
作用:
蓝牙设备扫描的核心控制器,负责发现周边可见的经典蓝牙设备(非BLE)。
关键方法:
方法 | 作用 | 代码示例 |
---|---|---|
start() | 启动设备扫描 | m_discoveryAgent->start() |
stop() | 停止扫描 | m_discoveryAgent->stop() |
isActive() | 检查是否正在扫描 | if(m_discoveryAgent->isActive()) |
信号:
// 设备发现时触发
void deviceDiscovered(const QBluetoothDeviceInfo &info);// 扫描完成时触发
void finished();
在代码中的应用:
// 初始化扫描器
m_discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);// 绑定设备发现信号
connect(m_discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,this, &BluetoothWindow::deviceDiscovered);// 启动扫描(代码截取自startScan())
m_discoveryAgent->start();
m_statusLabel->setText("正在扫描设备...");
关键实现细节:
- 设备过滤: 通过coreConfigurations()筛选经典蓝牙设备
if(device.coreConfigurations() & QBluetoothDeviceInfo::BaseRateCoreConfiguration) {// 只显示传统蓝牙设备
}
4.2 QBluetoothDeviceInfo
作用:
存储蓝牙设备的完整信息,包括名称、MAC地址、支持的服务等。
关键属性获取方法:
方法 | 返回值 | 代码示例 |
---|---|---|
name() | 设备名称(如"Printer-01") | device.name() |
address() | MAC地址(QBluetoothAddress类型) | device.address().toString() |
serviceUuids() | 设备支持的服务UUID列表 | device.serviceUuids().contains(QBluetoothUuid::SerialPort) |
在代码中的应用:
// 存储设备信息到列表项(deviceDiscovered()中)
QListWidgetItem *item = new QListWidgetItem(QString("%1 [%2]").arg(device.name()).arg(device.address().toString()));
item->setData(Qt::UserRole, QVariant::fromValue(device)); // 原始设备数据存储// 连接时获取设备信息(connectDevice()中)
m_currentDevice = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>();
设计亮点:
- 数据持久化:通过Qt::UserRole直接存储设备对象,避免后续从字符串重新解析MAC地址
- 服务验证:连接前检查设备是否支持串口服务
if(!m_currentDevice.serviceUuids().contains(QBluetoothUuid::SerialPort)) {QMessageBox::warning(this, "错误", "设备不支持打印服务");
}
4.3 QBluetoothSocket
作用:
实现蓝牙协议栈的数据传输,支持RFCOMM(经典蓝牙)和L2CAP协议。
关键方法:
方法 | 作用 | 代码示例 |
---|---|---|
connectToService() | 连接到指定服务 | socket->connectToService(addr, uuid) |
disconnectFromService() | 断开连接 | socket->disconnectFromService() |
write() | 发送数据 | socket->write(data) |
重要信号:
void stateChanged(QBluetoothSocket::SocketState state); // 连接状态变化
void errorOccurred(QBluetoothSocket::SocketError error); // 错误发生时
void bytesWritten(qint64 bytes); // 数据成功写入时
在代码中的应用:
// 创建Socket对象(connectDevice()中)
m_socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);// 连接状态处理
connect(m_socket, &QBluetoothSocket::stateChanged,this, &BluetoothWindow::socketStateChanged);// 错误处理
connect(m_socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),this, &BluetoothWindow::handleSocketError);// 发起连接(使用SerialPort服务UUID)
m_socket->connectToService(m_currentDevice.address(), QBluetoothUuid(QBluetoothUuid::SerialPort));
状态机详解:
状态值 | 含义 | 代码处理逻辑 |
---|---|---|
QBluetoothSocket::UnconnectedState | 未连接 | 显示"未连接"状态 |
QBluetoothSocket::ConnectingState | 正在连接 | 显示"连接中…" |
QBluetoothSocket::ConnectedState | 已连接 | 启用打印按钮 |
QBluetoothSocket::ClosingState | 正在断开 | 显示"断开中…" |
五、功能实现关键步骤
5.1 设备扫描与发现
// BluetoothWindow.cpp
void BluetoothWindow::startScan() {m_deviceList->clear();m_discoveryAgent->start(); // 启动扫描m_statusLabel->setText("正在扫描设备...");// 扫描完成处理connect(m_discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, [this]() {m_statusLabel->setText(QString("找到%1个设备").arg(m_deviceList->count()));});
}void BluetoothWindow::deviceDiscovered(const QBluetoothDeviceInfo &device) {if (device.coreConfigurations() & QBluetoothDeviceInfo::BaseRateCoreConfiguration) {QListWidgetItem *item = new QListWidgetItem(QString("%1 [%2]").arg(device.name()).arg(device.address().toString()));item->setData(Qt::UserRole, QVariant::fromValue(device)); // 存储原始设备数据m_deviceList->addItem(item);}
}
关键点:
- 通过QBluetoothDeviceDiscoveryAgent实现非阻塞设备扫描
- 使用Qt::UserRole存储设备原始数据,避免后续连接时重复解析字符串
- 过滤仅显示经典蓝牙设备(BaseRateCoreConfiguration)
5.2 设备连接与状态管理
void BluetoothWindow::connectDevice() {QListWidgetItem *item = m_deviceList->currentItem();if (!item) return;// 从Item中直接获取设备信息m_currentDevice = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>();if (m_socket) m_socket->deleteLater();m_socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);// 连接状态信号绑定connect(m_socket, &QBluetoothSocket::stateChanged, this, &BluetoothWindow::socketStateChanged);// 连接超时处理(10秒)m_connectionTimer->start(10000);m_socket->connectToService(m_currentDevice.address(), QBluetoothUuid(QBluetoothUuid::SerialPort));
}void BluetoothWindow::socketStateChanged(QBluetoothSocket::SocketState state) {switch (state) {case QBluetoothSocket::ConnectedState:m_statusLabel->setText("已连接:" + m_currentDevice.name());enableControls(true);break;case QBluetoothSocket::UnconnectedState:enableControls(false);break;}
}
关键点:
- 通过QBluetoothUuid::SerialPort指定串口协议(SPP)
- 使用QTimer实现连接超时保护
- 状态机管理连接流程(UI状态同步)
5.3 打印数据封装与发送
QByteArray BluetoothWindow::generatePrintData(CustomerInfo info) const
{// 获取当前日期QString currentDate = QDate::currentDate().toString("yyyy/MM/dd");const QString printData = QString("ID: %1\n""姓名: %2 性别: %3\n\n""OD(右眼): DS %4\n"" DC %5 \n"" AX %6° \n"" SE %7 \n\n""OD(左眼): DS %8\n"" DC %9 \n"" AX %10° \n"" SE %11 \n""瞳孔大小: (%12mm OD,%13mm OS)\n""瞳距: (%14mm)\n""结果: %15\n""日期: %16 (C) %17\n\n").arg(info.IdentityID)//1.arg(info.Name)//2.arg(info.Gender)//3.arg(info.reportData.RightEyeBallMirror) // 4 右眼 DS.arg(info.reportData.RightOphthlmoscope) // 5 右眼 DC.arg(info.reportData.RightEyeAxialPosition) // 6 右眼 AX.arg(info.reportData.RightEyeBallMirror + (info.reportData.RightOphthlmoscope/2)) // 7 右眼 SE.arg(info.reportData.LeftEyeBallMirror) // 8 左眼 DS.arg(info.reportData.LeftOphthlmoscope) // 9 左眼 DC.arg(info.reportData.LeftEyeAxialPosition) // 10 左眼 AX.arg(info.reportData.LeftEyeBallMirror + (info.reportData.LeftOphthlmoscope/2)) // 11 左眼 SE.arg(info.reportData.RightEyePupilSize) // 12 右眼瞳孔大小.arg(info.reportData.LeftEyePupilSize) // 13 左眼瞳孔大小.arg(info.reportData.PupillaryDistance) // 14 瞳距.arg(info.Result) // 15 结果.arg(currentDate) // 16 使用当天的日期.arg(info.hospital); // 17 医院// 添加中文支持检查和更完整的打印指令QByteArray data;data.append("\x1B\x40"); // 初始化// data.append("\x1C\x2E"); // 中文模式// data.append("\x1B\x21\x10"); // 设置字体大小// 使用更安全的编码检测if(QTextCodec::codecForName("GBK")) {QTextCodec *gbkCodec = QTextCodec::codecForName("GBK");data.append(gbkCodec->fromUnicode(printData));} else {data.append(printData.toLocal8Bit()); // 回退到本地编码}data.append("\n\n\x1D\x56\x41\x02"); // 更标准的切纸指令return data;
}
关键点:
- 兼容GBK编码与本地编码回退机制
- 使用ESC/POS标准指令集(\x1B\x40初始化,\x1D\x56\x41\x02切纸)
相关文章:
基于Qt5的蓝牙打印开发实战:从扫描到小票打印的全流程
文章目录 前言一、应用案例演示二、开发环境搭建2.1 硬件准备2.2 软件配置 三、蓝牙通信原理剖析3.1 实现原理3.2 通信流程3.3 流程详解3.4 关键技术点 四、Qt蓝牙核心类深度解析4.1 QBluetoothDeviceDiscoveryAgent4.2 QBluetoothDeviceInfo4.3 QBluetoothSocket 五、功能实现…...
Linux日志处理命令多管道实战应用
全文目录 1 日志处理1.1 实时日志分析1.1.1 nginx日志配置1.1.2 nginx日志示例1.1.3 日志分析示例 1.2 多文件合并分析1.3 时间范围日志提取 2 问题追查2.1 进程级问题定位2.2 网络连接排查2.3 硬件故障追踪 3 数据统计3.1 磁盘空间预警3.2 进程资源消耗排名3.3 HTTP状态码统计…...
Node.js CSRF 保护指南:示例及启用方法
解释 CSRF 跨站请求伪造 (CSRF/XSRF) 是一种利用用户权限劫持会话的攻击。这种攻击策略允许攻击者通过诱骗用户以攻击者的名义提交恶意请求,从而绕过我们的安全措施。 CSRF 攻击之所以可能发生,是因为两个原因。首先,CSRF 攻击利用了用户无法辨别看似合法的 HTML 元素是否…...
线性代数—向量与矩阵的范数(Norm)
参考链接: 范数(Norm)——定义、原理、分类、作用与应用 - 知乎 带你秒懂向量与矩阵的范数(Norm)_矩阵norm-CSDN博客 什么是范数(norm)?以及L1,L2范数的简单介绍_l1 norm-CSDN博客 范数(Norm…...
微服务基础-Ribbon
1. Ribbon简介: 客户端的负载均衡: 2....
移除生产环境所有console.log
大多数团队都会要求不能在生产环境输出业务侧的内容,但是往往业务开发人员会有疏漏,所以需要在工程化环境中,整体来管理console.log。我最近也是接到这样一个需求,整理了一下实现方案。 不同团队,不同场景,…...
数字人接大模型第二步:实时语音同步
接上例第一步,还是dh_live项目,增加了一个完整的实时对话样例,包含vad-asr-llm-tts-数字人全流程,以弥补之前的只有固定的问答的不足。 VAD(Voice Activity Detection,语音活动检测)VAD用于检测用户是否正在说话,从而触发后续的语音处理流程。 ASR(Automatic Speech R…...
Tomcat的安装与配置
Tomcat Tomcat是一个Java圈子中广泛使用的HTTP服务器. 后续学习Severlet内容,就是依赖Tomcat. Java程序员,要想写个网站出来,绕不开Tomcat. 我们这里使用Tomcat8 在bin目录下,这两个文件尤为重要,需要说明的是,Tomcat是那Java写的,所以在运行时需要jdk. bat后缀:是Window…...
Spring AI Alibaba - MCP连接 MySQL
先看效果 直接问他数据库有什么表。 大模型调用MySQL进行查询 搭建项目 添加依赖 创建项目后新添加Maven 依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> …...
Spring Cloud Stream喂饭级教程【搜集全网资料整理】
文章较长,建议收藏关注,随时查看 Spring Cloud Stream 简介 Spring Cloud Stream 是 Spring 提供的一个框架,用于构建与共享消息系统相连接的高度可伸缩的事件驱动微服务,它建立在 Spring 已有的成熟组件和最佳实践之上ÿ…...
prometheus手动添加k8s集群外的node-exporter监控
1、部署node-exporter 1)helm方式部署 rootiZj6c72dzbei17o2cuksmeZ:~# helm repo add prometheus-community https://prometheus-community.github.io/helm-charts "prometheus-community" has been added to your repositories rootiZj6c72dzbei17o2cu…...
Linux(Centos版本)中安装Docker
文章目录 Linux(Centos版本)中安装Docker整体流程 Linux(Centos版本)中安装Docker整体流程 进入root权限进行安装: 下面开始安装Docker: 1、安装docker的yum管理工具:记得将yum仓库更改为国内的镜像源&…...
C语言-- 深入理解指针(4)
C语言-- 深入理解指针(4) 一、回调函数二、冒泡排序三、qsort函数3.1 使用qsort函数排序整型数据3.2 使用qsort函数排序double数据3.3 使用qsort来排序结构体数据 四、模仿qsort库函数实现通用的冒泡排序4.1 通用冒泡排序函数排序整型数据4.2 通用冒泡排…...
牟乃夏《ArcGIS Engine地理信息系统开发教程》学习笔记3-地图基本操作与实战案例
目录 一、开发环境与框架搭建 二、地图数据加载与文档管理 1. 加载地图文档(MXD) 2. 动态添加数据源 三、地图浏览与交互操作 1. 基础导航功能 2. 书签管理 3. 量测功能 四、要素选择与属性查询 1. 属性查询 2. 空间查询 五、视图同步与鹰眼…...
Spark Streaming实时数据处理实战:从DStream基础到自定义数据源集成
park-Streaming概述 Spark-Streaming是什么 Spark Streaming 用于流式数据的处理。Spark Streaming 支持的数据输入源很多,例如:Kafka、Flume、Twitter等,以及和简单的 TCP 套接字等等。数据输入后可以用 Spark 的高度抽象原语如:…...
微软GraphRAG的安装和在RAG中的使用体会
文章目录 0. 简介(1)**技术原理**(2)**优势**(3)**开源与演进** 1. 下载graphrag.git2.安装 poetry3.初始化项目:建立cases目录4. 修改.env5.修改settings.yaml,将两处 api_base改成中转站地址:…...
Python学习记录7——集合set()的使用指南
文章目录 引言一、集合特性二、创建方式三、元素操作1、添加元素(1)add(element)(2)update(iterables) 2、删除元素(1)remove(element)(2)discard(element)(3)…...
apkpure 谷歌插件 下载的apk包
谷歌插件市场搜索 apkpure 然后直接搜索下载就行了 想看apk包中的静态资源,直接改apk 为zip后缀解压就行了 apple的ipa包也是相同的道理...
Android四大核心组件
目录 一、为什么需要四大组件? 二、Activity:看得见的界面 核心功能 生命周期图解 代码示例 三、Service:看不见的劳动者 两大类型 生命周期对比 注意陷阱 四、BroadcastReceiver:消息传递专员 两种注册方式 广播类型 …...
WSL2里手动安装Docker 遇坑
在 WSL2 里手动安装 Docker Engine 时遇坑:systemctl 和 service 命令在默认的 WSL2 Ubuntu 中 无法使用,因为 WSL2 没有 systemd。怎么办? 自己操作让 Docker Engine(dockerd)直接跑起来,挂到 /var/run/do…...
【ROS2】ROS开发环境配置——vscode和git
古月21讲-ROS2/1.系统架构/1.5_ROS2开发环境配置/ ROS机器人开发肯定离不开代码编写,课程中会给大家提供大量示例源码,这些代码如何查看、编写、编译 安Linux中安装装git sudo apt install git下载教程源码 《ROS2入门21讲》课程源码的下载方式&#x…...
django.db.models.query_utils.DeferredAttribute object
在 Django 中,当你看到 django.db.models.query_utils.DeferredAttribute 对象时,通常是因为你在查询时使用了 only() 或 defer() 方法来延迟加载某些字段。这两个方法允许你控制数据库查询中的字段加载方式,从而优化查询性能。 only() 方法…...
Linux内核中的编译时安全防护:以网络协议栈控制块校验为例
引言:内存安全的无声守卫者 在操作系统内核开发中,内存溢出引发的错误往往具有极高的隐蔽性和破坏性。Linux内核作为承载全球数十亿设备的基石,其网络协议栈的设计尤其注重内存安全性。本文通过分析一段看似简单的内核代码,揭示Linux如何通过编译时静态检查(Compile-Time…...
第11章 安全网络架构和组件(一)
11.1 OSI 模型 协议可通过网络在计算机之间进行通信。 协议是一组规则和限制,用于定义数据如何通过网络介质(如双绞线、无线传输等)进行传输。 国际标准化组织(ISO)在20世纪70年代晚期开发了开放系统互连(OSI)参考模型。 11.1.1 OSI模型的…...
Git常用命令简明教程
本教程整合并优化了Git核心命令,涵盖初始化、配置、文件操作、分支管理、远程仓库操作及常见场景,适合快速入门和日常参考。命令按使用流程分组,简洁明了,包含注意事项和最佳实践。 1. 初始化与配置 初始化Git仓库并设置基本配置…...
在 Ubuntu 24.04 系统上安装和管理 Nginx
1、安装Nginx 在Ubuntu 24.04系统上安装Nginx,可以按照下面的步骤进行: 1.1、 更新系统软件包列表 在安装新软件之前,需要先更新系统的软件包列表,确保获取到最新的软件包信息。打开终端,执行以下命令: …...
数据结构——二叉树和堆(万字,最详细)
目录 1.树 1.1 树的概念与结构 1.2 树相关的术语 1.3 树的表示法 2.二叉树 2.1 概念与结构 2.2 特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.3 二叉树存储结构 2.3.1 顺序结构 2.3.2 实现顺序结构二叉树 2.3.2.1 堆的概念与结构 2.3.2. 2 堆的插入与删除数据…...
IdeaVim 配置与使用指南
一、什么是 IdeaVim? IdeaVim 是 JetBrains 系列 IDE(如 IntelliJ IDEA, WebStorm, PyCharm 等)中的一个插件,让你在 IDE 里使用 Vim 的按键习惯,大大提升效率。 安装方法: 在 IDE 中打开 设置(Settings) →…...
前端浏览器窗口交互完全指南:从基础操作到高级控制
浏览器窗口交互是前端开发中构建复杂Web应用的核心能力,本文深入探讨23种关键交互技术,涵盖从传统API到最新的W3C提案,助您掌握跨窗口、跨标签页的完整控制方案。 一、基础窗口操作体系 1.1 窗口创建与控制 // 新窗口创建(现代浏…...
考研系列-计算机组成原理第五章、中央处理器
一、CPU的功能及结构 1.运算器的基本结构 2.控制器结构...
python+flask+flask-sockerio,部署后sockerio通信异常
前言 用python开发了一个flask web服务,前端用html,前后端通过socketio通信,开发环境,windowsminicondavscode,开发完成后本地运行没有问题,然后就开始部署,噩梦就开始了。 问题描述 程序是部…...
深度解析:TextRenderManager——Cocos Creator艺术字体渲染核心类
一、类概述 TextRenderManager 是 Cocos Creator 中实现动态艺术字体渲染的核心单例类。它通过整合资源加载、缓存管理、异步队列和自动布局等功能,支持普通字符模式和图集模式两种渲染方案,适用于游戏中的动态文本(如聊天内容、排行榜&…...
同样开源的自动化工作流工具n8n和Dify对比
n8n和Dify作为两大主流工具,分别专注于通用自动化和AI应用开发领域,选择哪个更“好用”需结合具体需求、团队能力及业务场景综合判断。以下是核心维度的对比分析: 一、核心定位与适用场景 维度n8nDify核心定位开源全场景自动化工具ÿ…...
设计模式每日硬核训练 Day 16:责任链模式(Chain of Responsibility Pattern)完整讲解与实战应用
🔄 回顾 Day 15:享元模式小结 在 Day 15 中,我们学习了享元模式(Flyweight Pattern): 通过共享对象,分离内部状态与外部状态,大量减少内存开销。适用于字符渲染、游戏场景、图标缓…...
基于边缘人工智能的AI无人机-更高效更安全的飞行任务执行
基于边缘人工智能的AI无人机-更高效更安全的飞行任务执行 人工智能有可能改变人们的生活和工作方式。人工智能和无人机是近年来发展迅速的两项技术。当这两种技术结合在一起时,它们会创造出许多以前不可能的应用。基于人工智能的无人机旨在独立执行任务,…...
30、不是说字符串是不可变的吗,string s=“abc“;s=“123“不就是变了吗?
一、核心概念澄清:不可变性的真实含义 1、不可变性的定义 字符串不可变性指对象内容不可修改,而非变量不可修改。 类比: 不可变字符串 装在密封信封里的信纸(内容不可更改)变量赋值 更换信封的指向(从…...
线上查询车辆出险记录:快速掌握事故情况!
在如今汽车成为人们日常不可或缺的交通工具之际,车辆出险记录成为了许多车主关注的焦点之一。为了帮助车主们快速了解车辆出险、理赔、事故记录,现在有了一种便捷的方式,那就是通过API接口在线查询。本文将介绍如何利用API接口,通…...
Python爬虫课程实验指导书
1.1Requests类库的认知 1.1.1 认识请求类库 Requests是用Python语言编写,基于,采用Apache2 Licensed开源协议的。它比urllib更加方便,可以节约我们大量的工作,完全满足HTTP测试需求。urllibHTTP库 Requests官网地址:ht…...
streamlit实现非原生的按钮触发效果 + flask实现带信息的按钮触发
目录 简介不携带信息的触发隐藏指定st.button(label, key)触发button的html代码汇总 携带信息的触发为什么需要携带信息前端JavaScript修改flask处理总代码 简介 由于streamlit可以同时在实现前后端结合,非常方便,但是这也造成了user难以方便的对页面的…...
机器学习基础——Seaborn使用
1.使用tips数据集,创建一个展示不同时间段(午餐/晚餐)账单总额分布的箱线图 import matplotlib.pyplot as plt import numpy as np import pandas as pd import seaborn as snstips pd.read_csv(./tips.csv)sns.boxplot(data tips,x time,y total_bill, )plt.show() 2.使用…...
Godot开发2D冒险游戏——第三节:游戏地图绘制
一、初步构建游戏地图 在游戏场景当中添加一个新的子节点:TileMapLayer 这一层称为瓦片地图层 根据提示,下一步显然是添加资源 为TileMapLayer节点添加一个TileSet 将地板添加进来,然后选择自动分割图集 自定义时要确保大小合适 让Godot自…...
Spark Mllib 机器学习
概述 机器学习是什么 根据百度百科的定义: 机器学习是一种通过算法和模型使计算机从数据中自动学习并进行预测或决策的技术。 定义比较抽象,根据常见的机器学习可以总结出三个关键字: 算法、经验、性能。 机器学习的过程可以抽象成一个pipel…...
在windows使用docker打包springboot项目镜像并上传到阿里云
1、前提:已有spring项目 2、在项目根目录下创建Dockerfile文件 FROM openjdk:11 WORKDIR /ruoyi-admin COPY ruoyi-admin/build/libs/lifecolor-web.jar lifecolor-web.jar CMD ["java", "-jar", "lifecolor-web.jar"] 3、选…...
前端高频面试题day3
JavaScript作用域理解 核心概念 作用域:定义变量/函数的可见范围及生命周期,分为 全局作用域、函数作用域、块级作用域。作用域链:变量查找从当前作用域逐级向上直至全局,遵循词法作用域(静态作用域)。闭…...
时空特征如何融合?LSTM+Resnet有奇效,SOTA方案预测准确率超91%
LSTM有着不错的时序信息提取能力,ResNet有着不错的空间特征信息提取能力。如果现在有时空特征融合的创新需求,我们是否能将LSTM和ResNet两者的优点融合起来呢? 随着这个思路下去,LSTM ResNet混合模型横空出世,在各个…...
蓝桥杯Java全攻略:从零到一掌握竞赛与企业开发实战
蓝桥杯Java软件开发竞赛已成为全国高校学生展示编程能力的重要舞台,本指南将带您从零开始构建完整的Java知识体系,不仅覆盖蓝桥杯高频考点,还延伸至企业级开发实战,助您在竞赛中脱颖而出并为未来职业发展奠定坚实基础。 一、Java基础语法与数据结构 竞赛解题流程图设计 蓝…...
【Nginx】负载均衡配置详解
Nginx作为高性能的HTTP服务器和反向代理服务器,提供了强大的负载均衡功能。本文将详细介绍Nginx负载均衡的配置方法和相关策略。 一、基础负载均衡配置 1.单服务示例配置 配置nginx.conf模块 在Nginx配置文件中定义upstream模块: worker_processes a…...
打造企业级AI文案助手:GPT-J+Flask全栈开发实战
一、智能文案革命的序幕:为什么需要AI文案助手? 在数字化营销时代,内容生产效率成为企业核心竞争力。据统计,营销人员平均每天需要撰写3.2篇文案,而传统人工创作存在三大痛点: 效率瓶颈:创意构…...
【文献速递】snoRNA-SNORD113-3/ADAR2通过对PHKA2的A-to-I编辑影响胶质母细胞瘤糖脂代谢
Cui等人于2025年在Cellular & Molecular Biology Letters上的发表一篇研究论文,题目为“Effect of SNORD113-3/ADAR2 on glycolipid metabolism in glioblastoma via A-to-I editing of PHKA2”。这篇文章的核心内容是研究胶质母细胞瘤(GBMÿ…...
视频HLS分片与关键帧优化深度解析
视频HLS分片与关键帧优化深度解析 🌐 HLS基础架构 #mermaid-svg-OQmrXfradiCv3EGC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-OQmrXfradiCv3EGC .error-icon{fill:#552222;}#mermaid-svg-OQmrXfrad…...