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

Qt 串口编程-从入门到实战

1. Qt 串口通信流程解析

1.1 串行通信和并行通信对比

  • 并行通信适合距离较短的通信,且信号容易受干扰,成本高
  • 串口通讯-设备(蓝牙, wifi, gprs, gps)

在这里插入图片描述

1.2 Qt 串口通信具体流程

  • 1. 创建 QSerialPort 对象
  • 2. 配置属性(波特率, 数据位, 停止, 校验位)
  • 3. 打开设备
  • 4. 发送数据到串口 write
  • 5. 在槽函数中读取数据(当串口有数据可读的时候会发送 readyRead 信号)
1.2.1 serialapp.pro
QT       += core gui serialport
1.2.2 serialapp.h
#ifndef SERIALAPP_H
#define SERIALAPP_H#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QIODevice>
#include <QByteArray>
#include <QString>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class SerialApp; }
QT_END_NAMESPACEclass SerialApp : public QWidget {Q_OBJECTpublic:SerialApp(QWidget *parent = nullptr);~SerialApp();private slots:void on_openBt_clicked();void on_sendBt_clicked();void read_data();private:Ui::SerialApp *ui;// 1、创建 QSerialPort 对象QSerialPort mSerial;
};
#endif // SERIALAPP_H
1.2.3 serialapp.cpp
#include "serialapp.h"
#include "ui_serialapp.h"SerialApp::SerialApp(QWidget *parent) : QWidget(parent), ui(new Ui::SerialApp) {ui->setupUi(this);// 2、配置设备,波特率,数据位,停止位,校验位mSerial.setPortName("COM1");  // 选择对应的端口号mSerial.setBaudRate(QSerialPort::Baud115200);mSerial.setDataBits(QSerialPort::Data8);mSerial.setStopBits(QSerialPort::OneStop);mSerial.setParity(QSerialPort::NoParity);connect(&mSerial, &QSerialPort::readyRead, this, &SerialApp::read_data);
}SerialApp::~SerialApp() {delete ui;
}// 3、打开设备 (读写)
void SerialApp::on_openBt_clicked() {if (mSerial.open(QIODevice::ReadWrite)) {qDebug() << "open success!";} else {qDebug() << "open failed!";}
}// 4、发送数据到串口 write
void SerialApp::on_sendBt_clicked() {QString data = ui->textEdit->toPlainText();mSerial.write(data.toUtf8());
}// 5、读取串口数据 read
void SerialApp::read_data() {QByteArray array = mSerial.readAll();ui->textBrowser->append(QString(array));
}
1.2.4 serialapp.ui

在这里插入图片描述

2. Qt 虚拟串口调试

2.1 VSPD 创建虚拟串口

  • VSPD (Virtual Serial Port Driver) 是一个虚拟串口驱动程序

    • 它可以模拟多个串口设备,使得应用程序可以通过虚拟串口与物理串口设备进行通信
    • 使用 VSPD 可以方便地进行串口调试、数据采集、数据转发等操作
    • VSPD 还支持多种协议,例如模拟 GPS 设备、模拟调制解调器、与虚拟机通信等
  • VSPD虚拟串口软件安装及使用

在这里插入图片描述

2.2 SecureCRT 连接虚拟串口

  • SecureCRT 是一款安全的终端模拟器,常用于远程访问服务器和网络设备
    • 它可以让用户通过 SSH、Telnet、Rlogin 或者串口等协议连接到远程设备,并在本地进行命令行操作
    • SecureCRT 还提供了多重会话管理、脚本编写、自动登录、加密通信等多种功能
  • SecureCRT安装教程

在这里插入图片描述

2.3 Qt 虚拟串口实现

  • serialapp.h

    #ifndef SERIALAPP_H
    #define SERIALAPP_H#include <QWidget>
    #include <QSerialPort>
    #include <QSerialPortInfo>
    #include <QIODevice>
    #include <QByteArray>
    #include <QString>
    #include <QDebug>
    #include <QList>QT_BEGIN_NAMESPACE
    namespace Ui { class SerialApp; }
    QT_END_NAMESPACEclass SerialApp : public QWidget {Q_OBJECTpublic:SerialApp(QWidget *parent = nullptr);~SerialApp();private slots:void on_openBt_clicked();void on_sendBt_clicked();void read_data();private:Ui::SerialApp *ui;// 创建 QSerialPort 对象QSerialPort mSerial;
    };
    #endif // SERIALAPP_H
    
  • serialapp.cpp

    #include "serialapp.h"
    #include "ui_serialapp.h"SerialApp::SerialApp(QWidget *parent) : QWidget(parent), ui(new Ui::SerialApp) {ui->setupUi(this);// 获取当前设备上的所有串口QList<QSerialPortInfo> list =  QSerialPortInfo::availablePorts();for (int i = 0; i < list.size(); i++) {ui->comboBox->addItem(list.at(i).portName());}// 配置设备,波特率,数据位,停止位,校验位//mSerial.setPortName("COM1");mSerial.setBaudRate(QSerialPort::Baud115200);mSerial.setDataBits(QSerialPort::Data8);mSerial.setStopBits(QSerialPort::OneStop);mSerial.setParity(QSerialPort::NoParity);connect(&mSerial, &QSerialPort::readyRead, this, &SerialApp::read_data);
    }SerialApp::~SerialApp() {delete ui;
    }// 打开设备 (读写)
    void SerialApp::on_openBt_clicked() {if (mSerial.isOpen()) {mSerial.close();}mSerial.setPortName(ui->comboBox->currentText());  // 设置端口if (mSerial.open(QIODevice::ReadWrite)) {qDebug() << "open success!";} else {qDebug() << "open failed!";}
    }// 发送数据到串口 write
    void SerialApp::on_sendBt_clicked() {QString data = ui->textEdit->toPlainText();mSerial.write(data.toUtf8());
    }// 读取串口数据 read
    void SerialApp::read_data() {QByteArray array = mSerial.readAll();ui->textBrowser->append(QString(array));
    }
    
  • serialapp.ui

在这里插入图片描述

2.4 Qt 与 SecureCRT 建立虚拟串口连接

在这里插入图片描述

3. Qt 编写串口调试工具

在这里插入图片描述

3.1 serialportapp.h

#ifndef SERIALPORTAPP_H
#define SERIALPORTAPP_H#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QList>
#include <QStringList>
#include <QString>
#include <QIODevice>
#include <QDebug>
#include <QByteArray>
#include <QMessageBox>
#include <QTimerEvent>
#include <QFileDialog>
#include <QFile>QT_BEGIN_NAMESPACE
namespace Ui { class SerialPortApp; }
QT_END_NAMESPACEclass SerialPortApp : public QWidget {Q_OBJECTpublic:SerialPortApp(QWidget *parent = nullptr);~SerialPortApp();void timerEvent(QTimerEvent *event);private slots:void on_openBt_clicked();void on_closeBt_clicked();void on_sendBt_clicked();void on_autoCheckBox_clicked(bool checked);void on_clearSendSizeBt_clicked();void on_sendHexCb_clicked(bool checked);void on_recvHexCb_clicked(bool checked);void read_data();void on_clearRecvSizeBt_clicked();void on_selectfileBt_clicked();void on_sendfileBt_clicked();void send_file_text(quint64 size);private:Ui::SerialPortApp *ui;QSerialPort mSerial;int timerid;qint32 sendsize;qint32 recvsize;QFile file;  // 发送文件qint32 sendfilesize;
};
#endif // SERIALPORTAPP_H

3.2 serialportapp.cpp

#include "serialportapp.h"
#include "ui_serialportapp.h"SerialPortApp::SerialPortApp(QWidget *parent) : QWidget(parent), ui(new Ui::SerialPortApp) {ui->setupUi(this);// 遍历获取当前设备上的所有串口QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();for (int i = 0; i < infos.size(); i++) {ui->comCb->addItem(infos.at(i).portName());}// 设置波特率显示QStringList list;list << "1200" << "2400" << "4800" << "9600" << "19200" << "38400" << "57600" << "115200";ui->rateCb->addItems(list);ui->rateCb->setCurrentIndex(7);  // 设置默认波特率为 115200list.clear();// 设置数据位list << "5" << "6" << "7" << "8" << "-1";ui->dataCb->addItems(list);ui->dataCb->setCurrentIndex(3);  // 设置默认数据位为 8list.clear();// 设置停止位list << "1" << "3" << "2" << "-1";ui->stopCb->addItems(list);list.clear();// 设置校验位list << "None" << "NULL" << "Even" << "Odd" << "Space" << "Mark";ui->priCb->addItems(list);list.clear();// 把关闭按钮设置失效ui->closeBt->setEnabled(false);// 当串口有数据可读时会发送 readyRead 信号connect(&mSerial, &QSerialPort::readyRead, this, &SerialPortApp::read_data);// 初始化发送、接收的字节数记录sendsize = recvsize = 0;
}SerialPortApp::~SerialPortApp() {delete ui;
}// 打开
void SerialPortApp::on_openBt_clicked() {// 配置端口,波特率,数据位,停止位,校验位mSerial.setPortName(ui->comCb->currentText());mSerial.setBaudRate(ui->rateCb->currentText().toInt());mSerial.setDataBits((QSerialPort::DataBits)ui->dataCb->currentText().toInt());mSerial.setStopBits((QSerialPort::StopBits)ui->stopCb->currentText().toInt());mSerial.setParity((QSerialPort::Parity)ui->priCb->currentText().toInt());// 打开设备if (mSerial.open(QIODevice::ReadWrite)) {ui->closeBt->setEnabled(true);ui->openBt->setEnabled(false);}
}// 关闭
void SerialPortApp::on_closeBt_clicked() {// 关闭设备mSerial.close();ui->closeBt->setEnabled(false);ui->openBt->setEnabled(true);
}// 手动发送数据
void SerialPortApp::on_sendBt_clicked() {QString data = ui->sendText->toPlainText();if (ui->sendHexCb->isChecked()) {// 转十六进制:data = 4142 --> 0x41 0x42QByteArray array;if (data.size() % 2 != 0) {data.insert(0, '0');}for (int i = 0; i < data.size() / 2; i++) {QString t = data.mid(2*i, 2);bool ok = false;int ihex = t.toInt(&ok, 16);array.append(ihex);}int size = mSerial.write(array);  // 发送数据sendsize += size;                 // 累计发送的字节数} else {int size = mSerial.write(data.toUtf8());  // 发送数据sendsize += size;}// 设置显示已发送的字节数ui->sendsizelabel->setText(QString::number(sendsize));
}// 定时自动发送数据
void SerialPortApp::on_autoCheckBox_clicked(bool checked) {if (checked) {// 获取定时发送周期int ms = ui->autotimeEdit->text().toInt();if (ms < 100) {QMessageBox::warning(this, "time hint", "time should > 100ms");ui->autoCheckBox->setChecked(false);return;}// 启动定时器事件timerid = this->startTimer(ms);} else {// 关闭定时器事件this->killTimer(timerid);}
}// 定时器事件
void SerialPortApp::timerEvent(QTimerEvent *event) {on_sendBt_clicked();
}// 清空已发送的字节数
void SerialPortApp::on_clearSendSizeBt_clicked() {sendsize = 0;ui->sendText->clear();ui->sendsizelabel->setText("0");
}// 发送端:十六进制和十进制转换
void SerialPortApp::on_sendHexCb_clicked(bool checked) {if (checked) {  // 十进制 --> 十六进制QString data = ui->sendText->toPlainText();QByteArray array = data.toUtf8().toHex();ui->sendText->setText(QString(array));} else {  // 十六进制 --> 十进制QString data = ui->sendText->toPlainText();QByteArray array;if (data.size() % 2 != 0) {data.insert(0, '0');}for (int i = 0; i < data.size() / 2; i++) {QString t = data.mid(2*i, 2);bool ok = false;int ihex = t.toInt(&ok, 16);array.append(ihex);}ui->sendText->setText(QString(array));}
}// 接收端:十六进制和十进制转换
void SerialPortApp::on_recvHexCb_clicked(bool checked) {if (checked) {  // 十进制 --> 十六进制QString data = ui->recvText->toPlainText();QByteArray array = data.toUtf8().toHex();ui->recvText->setText(QString(array));} else {  // 十六进制 --> 十进制QString data = ui->recvText->toPlainText();QByteArray array;if (data.size() % 2 != 0) {data.insert(0, '0');}for (int i = 0; i < data.size() / 2; i++) {QString t = data.mid(2*i, 2);bool ok = false;int ihex = t.toInt(&ok, 16);array.append(ihex);}ui->recvText->setText(QString(array));}
}// 接收串口数据
void SerialPortApp::read_data() {// 读到的数据是一个个字节QByteArray array = mSerial.readAll();recvsize += array.size();  // 显示已接收到的字节数if (ui->recvHexCb->isChecked()) {ui->recvText->append(array.toHex());} else {ui->recvText->append(array);}// 设置显示已接收到的字节数ui->recvsizelabel->setText(QString::number(recvsize));
}// 清空已接收的字节数
void SerialPortApp::on_clearRecvSizeBt_clicked() {recvsize = 0;ui->recvText->clear();ui->recvsizelabel->setText("0");
}// 选择要发送的文件
void SerialPortApp::on_selectfileBt_clicked() {QString path = QFileDialog::getOpenFileName(this);ui->filepathEdit->setText(path);
}// 发送文件
void SerialPortApp::on_sendfileBt_clicked() {// 当数据发送完毕后会发出一个信号 &QSerialPort::bytesWritten// 每当有效载荷的数据写入到设备当前的写入通道时,就会发出这个信号connect(&mSerial, &QSerialPort::bytesWritten, this, &SerialPortApp::send_file_text);// 打开文件file.setFileName(ui->filepathEdit->text());if (!file.open(QIODevice::ReadOnly)) {return;}// 获取文件大小int filesize = file.size();ui->progressBar->setMaximum(filesize);// 设置进度条显示QByteArray array = file.read(128);  // 每次读取 128 字节内容sendfilesize = mSerial.write(array);ui->progressBar->setValue(sendfilesize);
}// 循环(每 128 字节)发送文件
void SerialPortApp::send_file_text(quint64 size) {// 设置进度条显示QByteArray array = file.read(128);quint64 mSize = mSerial.write(array);sendfilesize += mSize;ui->progressBar->setValue(sendfilesize);// 判断文件是否发送完毕if (sendfilesize == ui->progressBar->maximum()) {file.close();disconnect(&mSerial, &QSerialPort::bytesWritten, this, &SerialPortApp::send_file_text);}
}

3.3 serialportapp.ui

在这里插入图片描述

相关文章:

Qt 串口编程-从入门到实战

1. Qt 串口通信流程解析 1.1 串行通信和并行通信对比 并行通信适合距离较短的通信&#xff0c;且信号容易受干扰&#xff0c;成本高串口通讯-设备&#xff08;蓝牙&#xff0c; wifi&#xff0c; gprs&#xff0c; gps&#xff09; 1.2 Qt 串口通信具体流程 1. 创建 QSerial…...

如何获得微软MVP徽章

要成为微软MVP&#xff0c;需要在特定领域成为专家&#xff0c;并积极参与社区&#xff0c;为其他人提供帮助和支持。以下是一些步骤可以帮助你成为MVP&#xff1a; 在特定领域成为专家&#xff1a;要成为MVP&#xff0c;需要在某个领域具有专业知识和经验。这可以通过阅读相关…...

Java架构师软件架构开发

目录 1 基于架构的软件开发导论2 ABSD架构方法论3 ABSD方法论具体实现4 ABSD金融业案例5 基于特定领域的软件架构开发导论6 DSSA领域分析7 DSSA领域设计和实现8 DSSA国际电商平台架构案例9 架构思维方法论概述10 AT方法论和案例想学习架构师构建流程请跳转:Java架构师系统架构…...

西南科技大学数字电子技术实验一(数字信号基本参数与逻辑门电路功能测试及FPGA 实现 )预习报告

手写报告稍微认真点写,80+随便有 目录 一、计算/设计过程 1、通过虚拟示波器观察和测量信号 2、通过实际电路(电阻、开关、发光二极管)模拟逻辑门电路 二、画出并填写实验指导书上的预表...

Java八股文面试全套真题【含答案】- SpringMVC篇

以下是一些关于Spring MVC语言的经典面试题以及它们的答案&#xff1a; 什么是Spring MVC框架&#xff1f;它的特点是什么&#xff1f; Spring MVC是基于Java的一种Web应用框架&#xff0c;用于开发基于MVC&#xff08;模型-视图-控制器&#xff09;模式的Web应用程序。它的特…...

Spring第二课响应的完全,如何理解前后端互联

目录 一、响应 Control,RestController 1.Controller的源码&#xff0c;代表什么意思 2.返回数据 Responsebody 3.返回HTML片段 4.返回JSON 5.那么假如我们使用集合会怎么样呢 设置状态码&#xff0c;虽然不影响展示&#xff0c;但是确实显示起来也就是401的情况。 2.我…...

html实现各种瀑布流(附源码)

文章目录 1.设计来源1.1 动态响应瀑布流1.2 分页瀑布流1.3 响应瀑布流 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134613121 html实现各种瀑布流(附源码)&#xff0c;…...

万字解析设计模式之责任链模式、状态模式

目录 一、责任链模式 1.1概述 1.2结构 1.3实现 1.4 优缺点 1.5应用场景 1.6源码解析 二、状态模式 2.1概述 2.2结构 2.3实现 2.4优缺点 2.5应用场景 三、责任链模式实验 任务描述 实现方式 编程要求 测试说明 四、状态模式实验 任务描述 实现方式 编程要…...

二十三种设计模式全面解析-深入探讨状态模式的高级应用技术:释放对象行为的无限可能

在软件开发中&#xff0c;状态管理是一个常见的挑战。当对象的行为随着内部状态的变化而变化时&#xff0c;有效地管理对象的状态和相应的行为变得至关重要。在这方面&#xff0c;状态模式提供了一种优雅而灵活的解决方案。它允许对象在运行时根据内部状态的改变而改变其行为&a…...

论文笔记--Toolformer: Language Models Can Teach Themselves to Use Tools

论文笔记--Toolformer: Language Models Can Teach Themselves to Use Tools 1. 文章简介2. 文章概括3 文章重点技术3.1 Toolformer3.2 APIs 4. 文章亮点5. 原文传送门 1. 文章简介 标题&#xff1a;Toolformer: Language Models Can Teach Themselves to Use Tools作者&#…...

stm32实现0.96oled图片显示,菜单功能

stm32实现0.96oled图片显示&#xff0c;菜单功能 功能展示简介代码介绍oled.coled.holedfont.h&#xff08;字库文件&#xff09;main函数 代码思路讲解 本期内容&#xff0c;我们将学习0.96寸oled的进阶使用&#xff0c;展示图片&#xff0c;实现菜单切换等功能&#xff0c;关…...

sqlite外键约束 保证数据一致性

1. 外键约束 在SQLite中&#xff0c;可以通过使用外键&#xff08;Foreign Key&#xff09;约束和CASCADE选项来实现通过外键删除相关信息。 CASCADE选项是指在主键表中删除记录时&#xff0c;相应的外键表中的相关记录也将被自动删除。 -- 创建主键表 CREATE TABLE Persons…...

Vue轻松入门,附带学习笔记和相关案例

目录 案例 一Vue基础 什么是Vue&#xff1f; 补充&#xff1a;mvvm框架 mvvm的组成 详解 Vue的使用方法 1.直接下载并引入 2.通过 CDN 使用 Vue 3.通过npm安装 4.使用Vue CLI创建项目 二插值表达式 什么是插值表达式&#xff1f; 插值表达式的缺点 解决方法 …...

【青蛙跳台阶问题 —— (三种算法)】

青蛙跳台阶问题 —— (三种算法&#xff09; 一.题目介绍1.1.题目1.2.图示 二.解题思路三.题解及其相关算法3.1.递归分治法3.2.动态规划算法&#xff08;Dynamic Programming&#xff09;3.3.斐波那契数列法 四.注意细节 一.题目介绍 1.1.题目 一只青蛙一次可以跳上1级台阶&am…...

联想yoga AMD处理器 转接头无法电量外接显示器

第一次买AMD的处理器&#xff0c;当时就是为了yogaAMD这款的接口要比英特尔的接口多&#xff0c;没想到AMD处理器真的问题多。经常蓝屏不说&#xff0c;偶尔还点不亮外接显示器。遇到这种问题&#xff0c;不是什么驱动问题&#xff0c;可能你按照网上各种方法打开设备管理器→显…...

OSG粒子系统与阴影 - ​​​​​​​阴影shadow(7)

OSG阴影 在虚拟现实仿真中&#xff0c;为了真实地模拟自然效果&#xff0c;阴影效果是不可缺少的&#xff0c;它对一个场景的真实性是非常重要的。在游戏或仿真中&#xff0c;一个高效的阴影往往能够提供非常强悍的视觉真实感。 osgShadow库 在OSG中专门定义了一个名字空间osg…...

vue3项目中使用富文本编辑器

前言 适配 Vue3 的富文本插件不多&#xff0c;我看了很多插件官网&#xff0c;也有很多写的非常棒的&#xff0c;有UI非常优雅让人耳目一新的&#xff0c;也有功能非常全面的。 如&#xff1a; Quill&#xff0c;简单易用&#xff0c;功能全面。editorjs&#xff0c;UI极其优…...

Java EE 进程线程

JavaEE 进程&线程 文章目录 JavaEE 进程&线程1. 进程1.1 概念1.2 进程管理1.3 PCB (Process Control Block) 2. 线程2.1 概念2.1 线程与进程的区别2.3 创建线程 1. 进程 1.1 概念 什么是进程&#xff1f; 进程是操作系统对一个正在执行的程序的一种抽象 我们可以打开…...

GPT写SQL的模版

表&#xff1a;profit_loss_sum_m_snapshot 计算字段&#xff1a;成本cost_whole求和&#xff0c;收入income_whole求和&#xff0c;收入求和-成本求和&#xff0c;成本目标cost_target求和&#xff0c;收入求和-成本目标求和 条件&#xff1a;日期statis_date在2023-11-01&…...

蓝桥杯官网练习题(平均)

问题描述 有一个长度为 n 的数组&#xff08; n 是 10 的倍数&#xff09;&#xff0c;每个数 ai 都是区间 [0,9] 中的整数。小明发现数组里每种数出现的次数不太平均&#xff0c;而更改第 i 个数的代价为 bi&#xff0c;他想更改若干个数的值使得这 10 种数出现的次数相等…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...