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

Qt绘制仪表————附带详细说明和代码示例

文章目录

  • 1 效果
  • 2 原理
  • 3 编码实践
    • 3.1 创建仪表属性类
    • 3.2 设置类属性
    • 3.3 绘制图案
      • 3.3.1 设置反走样
      • 3.3.2 绘制背景
      • 3.3.3 重新定义坐标原点
      • 3.3.4 绘制圆环
      • 3.3.5 绘制刻度线
      • 3.3.6 绘制刻度线上的描述值
      • 3.3.7 绘制指针
      • 3.3.8 绘制指针数值和单位
      • 3.3.9 控制指针变化
  • 扩展
  • 福利
  • 参考

1 效果

下面仪表模拟的是转速表和速度表,转速表中有怠速转速,降功转速的逻辑。
在这里插入图片描述
下面是模拟双针仪表的效果:

在这里插入图片描述

2 原理

1,重写paintEvent进行仪表绘制,使用QPropertyAnimation进行动画绘制;

2,进行属性动画绘制时,需要使用Q_PROPERTY宏用于声明类的属性;

3 编码实践

下面代码位调用方法,接口的具体实现在后文中有详细描述。

发射的信号:

    //发送发动机转速void sendEngineSpeed(double);//发送大机速度值void sendTrainSpeedNum(short);

创建仪表类并设置参数:

//发动机转速表DashBoardWidget3 *dashBoardWidget5 = new DashBoardWidget3(this);dashBoardWidget5->setScaleMajor(6);//6个大区间dashBoardWidget5->setScaleMinor(5);//每个区间5个小格dashBoardWidget5->setUnit("");dashBoardWidget5->setText("RPMx100");dashBoardWidget5->setmax(30);dashBoardWidget5->setUnitDrawInterval(1);//每隔一个大区间画一个刻度线描述值dashBoardWidget5->setGeometry(750, 20, 300, 300);connect(this, &MainInterface::sendEngineSpeed,dashBoardWidget5, &DashBoardWidget3::valueChanged);//汽车速度表DashBoardWidget3 *dashBoardWidget6 = new DashBoardWidget3(this);dashBoardWidget6->setScaleMajor(12);//大区间dashBoardWidget6->setScaleMinor(2);//每个区间的小值dashBoardWidget6->setUnit("");dashBoardWidget6->setText("km/h");dashBoardWidget6->setmax(120);dashBoardWidget6->setUnitDrawInterval(2);// dashBoardWidget->move(600, 20);dashBoardWidget6->setGeometry(750, 300, 300, 300);connect(this, &MainInterface::sendTrainSpeedNum,dashBoardWidget6, &DashBoardWidget3::valueChanged);

3.1 创建仪表属性类

struct DashBoardWidgetPrivate{//刻度值的最大值和最小值int maxValue = 100;int minValue = 0;//刻度值角度double startAngle = -50;double endAngle = 230;double value = minValue;//大区间,最小区间int scaleMajor = 10;int scaleMinor = 5;//单位和描述文字QString unit = "";QString text = "";//仪表颜色QColor arcColor = QColor(56, 61, 74);//QColor(0, 128, 255);//刻度颜色QColor scaleColor = QColor(71, 186, 252);//QColor(4, 168, 173);//指针颜色QColor pointerColor = QColor(255, 0, 0);//文件颜色QColor textColor = QColor(144, 133, 116);//背景颜色QColor backgroundColor = Qt::transparent;//仪表指针1:属性动画QPropertyAnimation *animation;};

3.2 设置类属性

    Q_PROPERTY(double value READ value WRITE setValue)Q_PROPERTY(double min READ min WRITE setMin)Q_PROPERTY(double max READ max WRITE setmax)Q_PROPERTY(double startAngle READ startAngle WRITE setStartAngle)Q_PROPERTY(double endAngle READ endAngle WRITE setEndAngle)Q_PROPERTY(int scaleMajor READ scaleMajor WRITE setScaleMajor)Q_PROPERTY(int scaleMinor READ scaleMinor WRITE setScaleMinor)Q_PROPERTY(QString unit READ unit WRITE setUnit)Q_PROPERTY(QString text READ text WRITE setText)Q_PROPERTY(QColor arcColor READ arcColor WRITE setArcColor)Q_PROPERTY(QColor scaleColor READ scaleColor WRITE setScaleColor)Q_PROPERTY(QColor pointerColor READ pointerColor WRITE setPointerColor)Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)

创建对应的函数:

    QSize sizeHint() const override;QSize minimumSizeHint() const override;double value() const;void setValue(const double value);void setMin(const double min);double min() const;void setmax(const double max);double max() const;void setStartAngle(const double startAngle);double startAngle() const;void setEndAngle(const double endAngle);double endAngle() const;void setScaleMajor(const int scale);int scaleMajor() const;void setScaleMinor(const int scale);int scaleMinor() const;void setUnit(const QString &unit);//设置单位QString unit() const;void setText(const QString &text);//设置文字QString text() const;void setArcColor(const QColor &color);QColor arcColor() const;void setScaleColor(const QColor &color);QColor scaleColor() const;void setPointerColor(const QColor &color);QColor pointerColor() const;void setTextColor(const QColor &color);QColor textColor() const;void setBackgroundColor(const QColor &color);QColor backgroundColor() const;

3.3 绘制图案

在类绘制事件中,添加各种绘制信息:

void DashBoardWidget3::paintEvent(QPaintEvent *event){QWidget::paintEvent(event);QPainter painter(this);//....
}

3.3.1 设置反走样

//反走样是图形学中的重要概念,用以防止通常所说的“锯齿”现象的出现。很多系统的绘图 API 里面都内置了有关反走样的算法,不过由于性能问题,默认一般是关闭的painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

3.3.2 绘制背景

    // 背景if (d->backgroundColor != Qt::transparent) {painter.setPen(Qt::NoPen);painter.fillRect(rect(), d->backgroundColor);}

3.3.3 重新定义坐标原点

    // 平移中心painter.translate(width() / 2, height() / 2);

调整之前:
在这里插入图片描述

调整之后:

在这里插入图片描述

3.3.4 绘制圆环

    // 圆环drawArc(&painter);

实现函数:

void DashBoardWidget3::drawArc(QPainter *painter)
{double min = qMin(width(), height());double arcWidth = min / 15.0;double radius = min / 3 - arcWidth;QRectF rect = QRectF(-radius, -radius, radius * 2, radius * 2);QPen pen;pen.setWidthF(arcWidth);pen.setCapStyle(Qt::FlatCap);// 圆弧背景double angle = d->endAngle - d->startAngle;pen.setColor(d->arcColor);painter->setPen(pen);painter->drawArc(rect, d->startAngle * 16, angle * 16);
}

绘制效果如下:

在这里插入图片描述

3.3.5 绘制刻度线

    // 刻度线drawScale(&painter);

实现函数:

void DashBoardWidget3::drawScale(QPainter *painter)
{painter->save();painter->rotate(270 - d->endAngle);int steps = (d->scaleMajor * d->scaleMinor);//区间*每个区间的小刻度double angleStep = (d->endAngle - d->startAngle) / steps;double min = qMin(width(), height());double radius = min / 3;QPen pen(d->scaleColor);pen.setCapStyle(Qt::RoundCap);for (int i = 0; i <= steps; i++) {if (i % d->scaleMinor == 0) {//画大刻度pen.setWidthF(1.5);painter->setPen(pen);painter->drawLine(0, radius - 8, 0, radius + 5);//画刻度线长度}else{//画小刻度pen.setWidthF(0.5);painter->setPen(pen);painter->drawLine(0, radius - 8, 0, radius - 3);}painter->rotate(angleStep);}painter->restore();
}

效果如下:

在这里插入图片描述

3.3.6 绘制刻度线上的描述值

    // 刻度线上的描述值drawScaleNum(&painter);

实现函数:

//画刻度线上的说明值
void DashBoardWidget3::drawScaleNum(QPainter *painter)
{painter->save();painter->setPen(d->scaleColor);double min = qMin(width(), height());double radius = min / 2.4;//半径QFont font("Microsoft YaHei", min / 25);painter->setFont(font);double startRad = d->endAngle * (M_PI / 180);//qDebug()<<"startRad:"<<startRad;double deltaRad = (d->endAngle - d->startAngle) * (M_PI / 180) / d->scaleMajor;QFontMetrics fontMetrics(font);if(m_unitDrawInterval > d->scaleMajor){m_unitDrawInterval = d->scaleMajor;}for (int i = 0; i <= d->scaleMajor; i += m_unitDrawInterval) {//每个大区间都要画刻度值double sina = qSin(startRad - i * deltaRad);double cosa = qCos(startRad - i * deltaRad);double value = 1.0 * i * ((d->maxValue - d->minValue) / d->scaleMajor) + d->minValue;// 1.0 * 1 *((1200 -0)/10) + 0// qDebug()<<"d->maxValue:"<<d->maxValue;//qDebug()<<"d->minValue:"<<d->minValue;//qDebug()<<"value:"<<value;QString strValue = QString("%1").arg(value);double textWidth = fontMetrics.horizontalAdvance(strValue);double textHeight = fontMetrics.height();int x = radius * cosa - textWidth / 2;int y = -radius * sina + textHeight / 4;painter->drawText(x, y, strValue);}painter->restore();
}

效果如下:

在这里插入图片描述

3.3.7 绘制指针

    // 指示器(指针)drawPointer(&painter);

实现函数:

//画指针
void DashBoardWidget3::drawPointer(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);painter->setBrush(d->pointerColor);//设置画笔颜色double radius = qMin(width(), height()) / 3.0;QPolygonF pts;pts << QPointF(-5, 0) << QPointF(0, -8)<< QPointF(5, 0) << QPointF(0, radius);painter->rotate(270 - d->endAngle);double degRotate = (d->endAngle - d->startAngle) / (d->maxValue - d->minValue) * (d->value - d->minValue);painter->rotate(degRotate);painter->drawConvexPolygon(pts);painter->restore();
}

效果如下:

在这里插入图片描述

3.3.8 绘制指针数值和单位

    // 显示指针数值和单位drawValue(&painter);

实现函数:

//画数值和单位
void DashBoardWidget3::drawValue(QPainter *painter)
{painter->save();painter->setPen(d->textColor);double min = qMin(width(), height());double radius = min / 2.0 - min / 4.8;QFont font("Microsoft YaHei", min / 25);painter->setFont(font);//绘制指针数值和单位QString strValue = QString("%1 %2").arg(d->value).arg(d->unit);QRectF valueRect(-radius, radius / 2.5, radius * 2, radius / 3.5);QColor pointerColor = QColor(0, 0, 0);painter->setBrush(pointerColor);//设置颜色painter->setPen(QPen(QColor(0, 0, 0)));painter->drawText(valueRect, Qt::AlignCenter, strValue);//绘制描述文字QRectF text2Rect(-radius, radius / 1.5, radius * 2, radius / 2.5);painter->setPen(QPen(QColor(255, 0, 0)));//设置画笔颜色painter->setBrush(d->textColor);//设置画笔颜色font.setPixelSize(12);painter->setFont(font);painter->drawText(text2Rect, Qt::AlignCenter, d->text);painter->restore();
}

实现效果:

在这里插入图片描述

3.3.9 控制指针变化

signals:void valueChanged(const double value);DashBoardWidget3::DashBoardWidget3(QWidget *parent): QWidget(parent), d(new DashBoardWidgetPrivate)
{d->animation = new QPropertyAnimation(this, "value", this);setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);connect(this, &DashBoardWidget3::valueChanged,this, &DashBoardWidget3::onStartAnimation);}

实现函数:

//仪表指针变动的动画
void DashBoardWidget3::onStartAnimation(double value)
{if(value < d->minValue|| value > d->maxValue|| value == d->value){}else{double start = d->value;double end = value;d->animation->setStartValue(start);d->animation->setEndValue(end);d->animation->start();}
}

扩展

可以思考以下,下面的效果如何实现?

在这里插入图片描述

福利

完整的项目代码

欢迎各位start

参考

Qt自定义控件之仪表盘的完整实现

相关文章:

Qt绘制仪表————附带详细说明和代码示例

文章目录 1 效果2 原理3 编码实践3.1 创建仪表属性类3.2 设置类属性3.3 绘制图案3.3.1 设置反走样3.3.2 绘制背景3.3.3 重新定义坐标原点3.3.4 绘制圆环3.3.5 绘制刻度线3.3.6 绘制刻度线上的描述值3.3.7 绘制指针3.3.8 绘制指针数值和单位3.3.9 控制指针变化 扩展福利参考 1 效…...

百度地图JavaScript API核心功能指引

百度地图JavaScript API是一套由JavaScript语言编写的应用程序接口&#xff0c;它能够帮助您在网站中构建功能丰富、交互性强的地图应用&#xff0c;包含了构建地图基本功能的各种接口&#xff0c;提供了诸如本地搜索、路线规划等数据服务。百度地图JavaScript API支持HTTP和HT…...

mp4影像和m4a音频无损合成视频方法

第一步&#xff1a;复制高清视频地址 url 第二步:打开网址粘贴复制的视频url视频下载 第三步&#xff1a;下载-影像.mp4和-音频.m4a 第四步&#xff1a;合并视频&#xff1b; 使用ffmpeg进行无损合成&#xff08;如果没有安装ffmpeg请自行下载安装下载 FFmpeg (p2hp.com)&…...

Ubuntu下将Julia嵌入Jupyter内核

一.安装 Julia 如果 Julia 尚未安装&#xff1a; 打开终端&#xff0c;下载最新的 Julia 安装包&#xff1a; wget https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.3-linux-x86_64.tar.gz 解压并移动到 /opt&#xff1a; tar -xvzf julia-1.9.3-linux-x86_…...

openGauss开源数据库实战二十五

文章目录 任务二十五 openGauss 数据库的物理备份与恢复任务目标实施步骤一、为进行物理备份做准备1.确保数据库工作在归档模式2.创建保存数据库物理备份的目录3.创建保存归档日志备份的目录 二、进行openGauss数据库的物理备份1.备份数据库2.切换WAL3.备份归档日志 三、openGa…...

[C/C++] List相关操作

List相关操作 1 链表二分 目标&#xff1a; &#xff08;1&#xff09;对于偶数节点&#xff0c;正好对半分&#xff1b; &#xff08;2&#xff09;对于奇数节点&#xff0c;前 后 1 &#xff08;3&#xff09;断开链表&#xff0c;方便后期合并 // 使用快慢指针完成中点…...

继电器控制与C++编程:实现安全开关控制的技术分享

在现代生活中,继电器作为一种重要的电气控制元件,在电气设备的安全控制中起到了至关重要的作用。通过低电流控制高电流,继电器能够有效地隔离控制电路与被控设备,从而保障使用者的安全。本项目将介绍如何通过树莓派Pico与继电器模块结合,使用C++编程实现继电器的控制。 一…...

题解 - 找子序列(2024.12上海月赛丙组T4)

题目描述 Dave 有一个长度为 n 的非负整数序列 a1-n, 和一个非负整数 m 。 他希望知道是否有一个 a 的非空子序列&#xff0c;使得子序列中所有元素的按位与(bitwise AND)结果为 m。 换言之&#xff0c;他想知道是否存在一个下标序列 i1-k(k ≥ 1),满足 1 ≤ i1 < i2 < …...

在centos 7.9上面安装mingw交叉编译工具

1.说明 为了在centos上面编译windows的程序&#xff0c;需要安装mingw工具&#xff0c;mingw工具是可以编译windows程序的一些工具链&#xff0c;使用方式和linux一致 2.下载脚本 使用脚本方式编译&#xff0c;github的脚本位置&#xff1a;https://github.com/Zeranoe/ming…...

ubuntu wine mobaxterm找不到串口和解决方案

安装好 打开MobaXterm时发现&#xff0c;没有可供选择的串口 我们再检查wine设备映射 ls -la ~/.wine/dosdevices/ 串口是存在的&#xff0c;我们再来一番神操作&#xff0c;并没有回滚操作&#xff0c;不知是否是必要修改 打开 注册表&#xff0c;在HKEY_LOCAL_MACHINE中的…...

如何编译安装系统settings设置应用(5.0.0-Release)

本文介绍如何在OpenHarmony 5.0.0 r版本中修改系统设置应用&#xff0c;并且编译安装到开发板上 开发环境 1.dayu200开发板 2.OpenHarmony 5.0.0r 固件 3.API12 full sdk &#xff08;如果安装full sdk过程中出现报错hvigor ERROR: Cannot find module typescript,请参考 h…...

<项目代码>YOLOv8 车牌识别<目标检测>

项目代码下载链接 &#xff1c;项目代码&#xff1e;YOLOv8 车牌识别&#xff1c;目标检测&#xff1e;https://download.csdn.net/download/qq_53332949/90121387YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题…...

协同办公软件新升级:细节优化,让办公更简单

细节决定成败&#xff0c;企业酷信协同办公系统通过贴近客户实际需求的一系列改进和创新&#xff0c;在技术架构、系统结构、管理理念和使用性能上&#xff0c;都达到了国内先进水平&#xff0c;同时具备独特的优势。让我们看看企业酷信是如何通过这些细节提升&#xff0c;为企…...

【原创学习笔记】西门子1200 PLC实现变频器控制

一、实现的功能及应用的场合 通过PLC的不同指令&#xff0c;发送指令控制电机的启停和速度大小 二、硬件配置 1、西门子1214 PLC 2.TIA V16 3.SINAMICS G120C 三、实现功能步骤 1.添加设备G120C PN-调整以太网地址 根据实际情况选择有无滤波器&#xff0c;电机参数&#xf…...

SQL server学习02-使用T-SQL创建数据库

目录 一&#xff0c; 使用T-SQL创建数据库 1&#xff0c;数据库的存储结构 2&#xff0c;创建数据库的语法结构 1&#xff09;使用T-SQL创建学生成绩管理数据库 二&#xff0c;使用T-SQL修改数据库 1&#xff0c;修改数据库的语法结构 1&#xff09;修改学生成绩管理数…...

2024153读书笔记|《春烂漫:新平摄影作品选》——跳绳酷似人生路,起落平常,进退平常,莫惧征途万里长

2024153读书笔记|《春烂漫&#xff1a;新平摄影作品选》——跳绳酷似人生路&#xff0c;起落平常&#xff0c;进退平常&#xff0c;莫惧征途万里长 《春烂漫&#xff1a;新平摄影作品选》作者新平&#xff0c;2019.12.25年读完的小书&#xff0c;当时就觉得挺不错&#xff0c;今…...

MySQL有哪些高可用方案?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL有哪些高可用方案?】面试题。希望对大家有帮助&#xff1b; MySQL有哪些高可用方案? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 高可用方案旨在确保数据库系统的高可靠性、低宕机时间、以及在硬件故障…...

前台进程是什么

前台进程是什么 前台进程的定义 前台进程是指在操作系统中&#xff0c;与用户当前正在交互的进程。这些进程通常拥有最高的优先级&#xff0c;因为它们直接影响用户体验&#xff0c;是用户正在关注或者正在使用的应用程序对应的进程。例如&#xff0c;当你在手机上打开一个游戏…...

Redis学习笔记之——学习计划

Redis——Remote Dictionary Server&#xff0c;开源、基于内存、速度快、key-value... Redis做为一个高性能的键值存储系统&#xff0c;广泛应用于缓存、会话存储、分布式锁以及其他需要快速访问的数据场景中。熟悉掌握redis&#xff0c;似乎已成为广大码农们必备的一项技能。…...

npm : 无法加载文件 D:\nodejs\npm.ps1

问题描述 npm run serve 启动一个Vue项目&#xff0c;报错如下&#xff1a; npm : 无法加载文件 D:\nodejs\npm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 https:/go.microsoft.com/fwlink/? LinkID135170 中的 about_Execution_Policies。…...

Zookeeper集群启动失败?从myid配置到防火墙,保姆级排错指南来了

Zookeeper集群启动失败&#xff1f;从myid配置到防火墙&#xff0c;保姆级排错指南来了当你满怀期待地执行bin/zkServer.sh start命令&#xff0c;却只看到一堆晦涩的错误日志时&#xff0c;那种挫败感我太熟悉了。Zookeeper作为分布式系统的"神经中枢"&#xff0c;其…...

同事还在手动整理文件,我已经让 Open Claw 全自动搞定了|Windows 一键部署

⚡OpenClaw 一键安装包&#xff5c;一键部署&#xff0c;告别复杂环境配置⚡ 适配系统 Windows10/11 64 位 当前版本 2.7.5 版本&#xff08;虾壳云版&#xff09; 核心优势 全程可视化操作&#xff0c;无需命令行、无需手动配置 Python/Node.js&#xff0c;内置所有运行…...

AI编程新纪元已来(Claude 3.5 Sonnet代码能力压测报告:GitHub Copilot vs Cursor vs 原生Claude)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;AI编程新纪元已来&#xff08;Claude 3.5 Sonnet代码能力压测报告&#xff1a;GitHub Copilot vs Cursor vs 原生Claude&#xff09; AI编程工具正经历一场静默而深刻的范式迁移——Claude 3.5 Sonnet …...

神经网络从入门到精通:10个核心概念+8个实战代码,小白也能懂

神经网络从入门到精通:10个核心概念+8个实战代码,小白也能懂 副标题: 从像素到概念的函数映射,附完整训练流程实战 一、痛点:为什么神经网络这么难理解? 很多初学者第一次接触神经网络时,会被各种术语绕晕:神经元、权重、偏置、激活函数、反向传播、梯度下降… 感觉像…...

Alibaba组件选型与架构设计

Alibaba组件选型与架构设计 前言 本文将总结Spring Cloud Alibaba各组件的特点&#xff0c;并根据不同业务场景提供选型建议和架构设计指导。 一、组件对比与选型 1.1 注册中心对比 特性NacosEurekaConsulCAP模型CP/AP可切换APCP多语言支持HTTP/DNSHTTPHTTP/DNS配置管理原生支持…...

【咨询业AI Agent应用成熟度评估模型】:基于217家机构实测数据的4级能力图谱与升级路线图

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;【咨询业AI Agent应用成熟度评估模型】&#xff1a;基于217家机构实测数据的4级能力图谱与升级路线图 本模型基于对全球217家管理咨询、战略咨询与数字化转型服务商的实地调研与系统性能力测评&#xff0c;覆…...

【AI Agent娱乐行业落地实战指南】:2024年头部平台已验证的7大爆款应用模型与避坑清单

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;AI Agent在娱乐行业的核心价值与演进趋势 AI Agent正从被动响应工具跃升为娱乐内容生态的主动协作者与智能策展者。其核心价值不仅体现在效率提升&#xff0c;更在于重构创意生产链路、深化用户参与机制…...

30个专业模板轻松美化Power BI报表:零基础也能打造惊艳数据可视化

30个专业模板轻松美化Power BI报表&#xff1a;零基础也能打造惊艳数据可视化 【免费下载链接】PowerBI-ThemeTemplates Snippets for assembling Power BI Themes 项目地址: https://gitcode.com/gh_mirrors/po/PowerBI-ThemeTemplates 还在为Power BI报表设计发愁吗&a…...

基于RK平台的智慧出行方案:从芯片选型到车规级开发的实战指南

1. 项目概述&#xff1a;当“智慧出行”遇上“RK平台”最近几年&#xff0c;如果你关注汽车电子或者物联网领域&#xff0c;一定对“智慧出行”这个词不陌生。它早已不是科幻电影里的概念&#xff0c;而是真真切切地走进了我们的生活&#xff0c;从智能座舱里流畅的语音交互、多…...

初创团队如何利用Taotoken统一管理多项目的AI模型调用

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 初创团队如何利用Taotoken统一管理多项目的AI模型调用 对于初创团队而言&#xff0c;同时推进多个小项目是常态。每个项目可能都需…...