(在线CAD控件)网页CAD实现粗糙度标注的方法

简介: 本文介绍了通过MxCAD二次开发实现机械制图中表面粗糙度符号的标注功能。表面粗糙度符号用于表示零件表面微观不平度,基本形式为三角形,可结合不同修饰(如加横线、小圆等)表达具体加工要求。文章解析了符号含义,并基于McDbCustomEntity类创建自定义实体,实现符号绘制、数据持久化、夹点设置等功能。此外,还提供了用户交互式标注方法,支持根据直线、圆弧或指定角度生成粗糙度标注。最后展示了效果演示及扩展开发示例,便于开发者进一步定制功能。

前言

‌表面粗糙度符号是机械制图中的重要标注符号,用于表示零件表面的微观不平度。它的基本形式是一个三角形,尖端从材料外垂直指向被标注的表面。符号的尖端必须从材料外垂直指向被标注的表面,标注可以注在尺寸界线上、轮廓线上、延长线上或代号中‌。在本篇文章中我们将通过解析表面粗糙度符号,调用mxcad二次开发实现粗糙度标注功能。

表面粗糙度符号解析

image-20250516105056600.png

  1. 基本符号:这些符号代表了表面可以用任何方法获得。它们简洁而直观,是表达设计意图的基础。
  2. 加工方法符号:在基本符号的长边上加上一横线,可以标注相关的加工方法。无论是车削、铣削还是其他任何去除材料的方法,都能通过这些符号清晰地表达出来。
  3. 去除材料方法符号:在基本符号上加上一小圆,表示表面是通过去除材料的方法获得的。这不仅可以是车、铣等传统加工方法,也可以是磨削、抛光等更精细的处理方式。
  4. 相同去除方法符号:如果多个表面具有相同的去除材料方法,可以在基本符号上加上一个小圆,表示这些表面有相同的粗糙度要求。
  5. 保持原供应状况符号:在某些情况下,表面需要保持其原始供应状况,这时可以在基本符号上加上一个小圆,表示这些表面不需要进行任何额外的处理。
  6. 符号与代号的组合:在实际设计中,我们可能会遇到多种符号的组合使用。例如,基本符号加一短线和说明划线,表示表面是通过特定的去除材料方法获得的。

自定义实体实现

根据上述内容中对粗糙度符号的分析,我们可以得到粗糙度标注的核心数据,并根据这些数据通过mxcad里的自定义实体[McDbCustomEntity]实现粗糙度标注实体。

1.基本结构设置

 export class McDbTestRoughness extends McDbCustomEntity {
   
       // 基本属性定义
       private position: McGePoint3d = new McGePoint3d();  // 标注位置
       private textDownString: string[] = ['1.6'];         // 下方文本
       private textUpString: string[] = [];                // 上方文本
       private textLeftString: string = '';                // 左侧文本
       private CornerType: string = '';                    // 角标类型
       private markType: number = 0;                       // 标注类型
       private dimSize: number = 5;                        // 标注尺寸
       private rotation: number = 0;                       // 旋转角度
       private dimHeight: number = 10;                     // 标注高度
       private isSameRequire: boolean = false;             // 是否是相同需求
       private isAddLongLine: boolean = false;             // 是否加长处理
       private isMostSymbols: boolean = false;             // 多数符号
       // 包围盒
       private minPt: McGePoint3d = new McGePoint3d();
       private maxPt: McGePoint3d = new McGePoint3d();
   }

2.构造函数和创建方法

   constructor(imp?: any) {
   
       super(imp);
   }
   public create(imp: any) {
   
       return new McDbTestRoughness(imp);
   }
   public getTypeName(): string {
   
       return "McDbTestRoughness";
   }

3.数据持久化

// 读取自定义实体数据
       public dwgInFields(filter: IMcDbDwgFiler): boolean {
   
           this.position = filter.readPoint("position").val;
           this.minPt = filter.readPoint("minPt").val;
           this.maxPt = filter.readPoint("maxPt").val;
           const textDownStr = filter.readString("textDownStr").val;
           this.textDownString = textDownStr.split(',').filter((item) => item != "");;
           const textUpStr = filter.readString("textUpStr").val;
           this.textUpString = textUpStr.split(',').filter((item) => item != "");;
           this.textLeftString = filter.readString("textLeftStr").val;
           this.CornerType = filter.readString('CornerType').val;
           this.markType = filter.readLong('markType').val;
           this.dimSize = filter.readDouble('dimSize').val;
           this.rotation = filter.readDouble('rotation').val;
           this.dimHeight = filter.readDouble('dimHeight').val;
           this.isSameRequire = filter.readLong('isSameRequire').val == 1 ? true : false;
           this.isAddLongLine = filter.readLong('isAddLongLine').val == 1 ? true : false;
           this.isMostSymbols = filter.readLong('isMostSymbols').val == 1 ? true : false;
           return true;
       }
       // 写入自定义实体数据
       public dwgOutFields(filter: IMcDbDwgFiler): boolean {
   
           filter.writePoint("position", this.position);
           filter.writePoint("maxPt", this.maxPt);
           filter.writePoint("minPt", this.minPt);
           const textDownStr = this.textDownString.join(',');
           const textUpStr = this.textUpString.join(',');
           filter.writeString("textDownStr", textDownStr);
           filter.writeString("textUpStr", textUpStr);
           filter.writeString("textLeftStr", this.textLeftString);
           filter.writeString('CornerType', this.CornerType);
           filter.writeLong('markType', this.markType);
           filter.writeDouble('dimSize', this.dimSize);
           filter.writeDouble('rotation', this.rotation);
           filter.writeDouble('dimHeight', this.dimHeight);
           filter.writeLong('isSameRequire', this.isSameRequire ? 1 : 0);
           filter.writeLong('isAddLongLine', this.isAddLongLine ? 1 : 0);
           filter.writeLong('isMostSymbols', this.isMostSymbols ? 1 : 0);
           return true;
       }

4.设置标注夹点及夹点移动规则

// 移动夹点:标注点即为夹点,若夹点移动则标注点随之移动
   public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
   
       this.assertWrite();
       this.position.x += dXOffset;
       this.position.y += dYOffset;
       this.position.z += dZOffset;
   }
   // 获取夹点
   public getGripPoints(): McGePoint3dArray {
   
       let ret = new McGePoint3dArray();
       ret.append(this.position);
       return ret;
   }

5.绘制标注实体

// 获取所有实体
       public getAllEntity(): McDbEntity[] {
   
           //  根据粗糙度绘制粗糙度形状
           const mxcad = MxCpp.getCurrentMxCAD();
           const entityArr = this.drawShape(this.markType, this.position, this.dimSize, true);
           const pl = entityArr[0] as McDbPolyline;
           const lastPoint = pl.getPointAt(pl.numVerts() - 1).val;
           // 添加左侧文字
           if (this.textLeftString) {
   
               const textLeft = new McDbText();
               textLeft.textString = this.textLeftString;
               textLeft.height = this.dimSize * (9 / 10);
               textLeft.alignmentPoint = textLeft.position = this.position.clone().addvec(McGeVector3d.kYAxis.clone().mult(this.dimSize * (1 / 10))).addvec(McGeVector3d.kXAxis.clone().negate().mult(this.dimSize))
               textLeft.horizontalMode = McDb.TextHorzMode.kTextRight;
               entityArr.push(textLeft)
           }
           // 添加角标
           if (this.CornerType) {
   
               const textCorner = new McDbText();
               textCorner.textString = this.CornerType;
               textCorner.height = this.dimSize * (7 / 10);
               textCorner.alignmentPoint = textCorner.position = this.position.clone().addvec(McGeVector3d.kYAxis.clone().mult(this.dimSize * (3 / 10))).addvec(McGeVector3d.kXAxis.clone().mult(this.dimSize * (9 / 10)))
               textCorner.horizontalMode = McDb.TextHorzMode.kTextLeft;
               entityArr.push(textCorner)
           }
           // 相同要求
           if (this.isSameRequire) {
   
               const cirlce = new McDbCircle();
               cirlce.center = lastPoint.clone();
               cirlce.radius = this.dimSize * (3 / 10);
               entityArr.push(cirlce);
           }
           // 加长横线
           let endX = lastPoint.x;
           // 绘制上标文字
           const height = (7 / 10) * this.dimSize;
           const basePos = lastPoint.clone().addvec(McGeVector3d.kXAxis.clone().mult(this.dimSize * (1 / 2))).addvec(McGeVector3d.kYAxis.clone().mult(this.dimSize * (1 / 5)))
           let basePos_x: number = basePos.x;

           let lineArr: McDbLine[] = []
           if (this.textUpString.length === 1) {
   
               const text = new McDbText();
               text.textString = this.textUpString[0];
               text.height = height;
               text.alignmentPoint = text.position = basePos;

               entityArr.push(text)

               const {
    maxPt } = this.getTextBox(text)

               if (maxPt.x > endX) endX = maxPt.x;
               basePos_x = text.position.x;

           } else if (this.textUpString.length === 2) {
   
               const text1 = new McDbText();
               text1.textString = this.textUpString[0];
               text1.height = height;

               const pos1 = basePos.clone();

               const text2 = new McDbText();
               text2.height = height;
               text2.textString = this.textUpString[1];

               const v = lastPoint.sub(this.position).mult(2 / 3)
               const pos2 = pos1.clone().addvec(v);
               const lastPoint2 = lastPoint.clone().addvec(v);

               text1.alignmentPoint = text1.position = new McGePoint3d(pos2.x, pos1.y);
               text2.alignmentPoint = text2.position = pos2;
               basePos_x = pos2.x;

               const res1 = this.getTextBox(text1)
               const res2 = this.getTextBox(text2)

               const endPt_x = res1.maxPt.x > res2.maxPt.x ? res1.maxPt.x : res2.maxPt.x;
               if (endX < endPt_x) endX = endPt_x + height * 0.3;

               const endPoint2 = new McGePoint3d(endX, lastPoint2.y);
               const line2 = new McDbLine(lastPoint2.x, lastPoint2.y, lastPoint2.z, endPoint2.x, endPoint2.y, endPoint2.y);
               const line3 = new McDbLine(lastPoint.x, lastPoint.y, lastPoint.z, lastPoint2.x, lastPoint2.y, lastPoint2.z);
               lineArr.push(line2);
               entityArr.push(text2);
               entityArr.push(text1);
               entityArr.push(line3);
           }

           // 绘制下标文字
           if (this.textDownString.length) {
   
               const pos = new McGePoint3d(basePos_x, lastPoint.y);
               this.textDownString.forEach((str, index) => {
   
                   const text = new McDbText();
                   text.textString = str;
                   text.height = height;
                   let v: McGeVector3d = new McGeVector3d()
                   v = McGeVector3d.kYAxis.clone().negate().mult(height * (index + 1 + (1 / 6)));
                   text.alignmentPoint = text.position = pos.clone().addvec(v);
                   entityArr.push(text)

                   const res = this.getTextBox(text)

                   endX = endX < res.maxPt.x ? res.maxPt.x : endX;
               });
           };

           if (this.isAddLongLine) {
   
               const endPoint = lastPoint.clone().addvec(McGeVector3d.kXAxis.clone().mult(this.dimSize * 2))
               const line = new McDbLine(lastPoint.x, lastPoint.y, lastPoint.z, endPoint.x, endPoint.y, endPoint.y);
               if (endX < endPoint.x) {
   
                   endX = endPoint.x;
                   entityArr.push(line);
               }
           }

           const endPoint = new McGePoint3d(endX, lastPoint.y)
           const line = new McDbLine(lastPoint.x, lastPoint.y, lastPoint.z, endPoint.x, endPoint.y, endPoint.y);
           entityArr.push(line)
           if (lineArr.length) lineArr.forEach(line => {
   
               line.endPoint.x = endX;
               entityArr.push(line);
           })

           // 多数符号
           const drawArc = (params: McGePoint3d[]) => {
   
               const arc = new McDbArc();
               arc.computeArc(params[0].x, params[0].y, params[1].x, params[1].y, params[2].x, params[2].y);
               entityArr.push(arc)
           }
           if (this.isMostSymbols) {
   
               // 绘制多数符号(两个圆弧+两条直线)
               // 两个圆弧
               const pt = this.position.clone().addvec(McGeVector3d.kYAxis.clone().mult(this.dimSize));
               const basePt = new McGePoint3d(endX, pt.y);

               const radius = this.dimSize * (7 / 5);
               const center1 = basePt.clone().addvec(McGeVector3d.kXAxis.clone().mult(this.dimSize * (7 / 5)));
               const v1 = McGeVector3d.kXAxis.clone().mult(radius);
               const cirlce1_pt1 = center1.clone().addvec(v1.clone().rotateBy(40 * (Math.PI / 180)));
               const cirlce1_pt2 = center1.clone().addvec(v1.clone());
               const cirlce1_pt3 = center1.clone().addvec(v1.clone().rotateBy(320 * (Math.PI / 180)));
               drawArc([cirlce1_pt1, cirlce1_pt2, cirlce1_pt3]);

               const center2 = basePt.clone().addvec(McGeVector3d.kXAxis.clone().mult(this.dimSize * (12 / 5)));
               const cirlce2_pt1 = center2.clone().addvec(v1.clone().rotateBy(140 * (Math.PI / 180)));
               const cirlce2_pt2 = center2.clone().addvec(v1.clone().negate());
               const cirlce2_pt3 = center2.clone().addvec(v1.clone().rotateBy(220 * (Math.PI / 180)));
               drawArc([cirlce2_pt1, cirlce2_pt2, cirlce2_pt3]);

               // 绘制两条直线
               const point = center1.clone().addvec(center2.sub(center1).mult(1 / 3)).addvec(McGeVector3d.kYAxis.clone().negate().mult(this.dimSize * (4 / 5)));
               this.drawShape(2, point, this.dimSize * (4 / 5), false).forEach(ent => {
   
                   entityArr.push(ent)
               });
           };

           this.getBox(entityArr);
           const mat = new McGeMatrix3d();
           const _height = this.maxPt.y - this.minPt.y;
           if (this.dimHeight) {
   
               const scale = this.dimHeight / _height;
               mat.setToScaling(scale, this.position);
           } else {
   
               mat.setToScaling(1, this.position);
           };
           entityArr.forEach(ent => {
   
               ent.transformBy(mat);
           })
           return entityArr
       }
       // 根据粗糙度type类型绘制粗糙度形状
       private drawShape(markType, position, dimSize, flag): McDbEntity[] {
   
           const entityArr: McDbEntity[] = [];
           const v = McGeVector3d.kYAxis.clone().mult(dimSize);
           const vec = McGeVector3d.kXAxis.clone().mult(dimSize * (3 / 5));
           const midPt = position.clone().addvec(v);
           const point1 = midPt.clone().addvec(vec);
           const point2 = midPt.clone().addvec(vec.clone().negate());

           let len = dimSize * (2 / 5);
           if (this.textDownStr.length > 2 && flag) len = dimSize * (1 / 2);
           const point3 = position.clone().addvec(point1.sub(position).mult(len));
           if (markType === 0) {
   
               //  原始样式(倒三角)
               const pl = new McDbPolyline();
               pl.addVertexAt(point1);
               pl.addVertexAt(point2);
               pl.addVertexAt(position);
               pl.addVertexAt(point3);
               entityArr.push(pl)
           } else {
   
               // 不封口三角
               const pl = new McDbPolyline();
               pl.addVertexAt(point2);
               pl.addVertexAt(position);
               pl.addVertexAt(point3);
               entityArr.push(pl)
           }

           if (markType === 1) {
   
               //  带圆:三角形内切圆
               const a = position.distanceTo(point1);
               const b = position.distanceTo(point2);
               const c = point1.distanceTo(point2);
               const s = (a + b + c) / 2;
               const h = position.distanceTo(midPt);
               const A = (c * h) / 2;
               const circle = new McDbCircle();
               circle.radius = A / s;
               circle.center = midPt.clone().addvec(McGeVector3d.kYAxis.clone().negate().mult(circle.radius));
               entityArr.push(circle)
           }

           return entityArr
       }
       // 绘制实体
       public worldDraw(draw: MxCADWorldDraw): void {
   
           const entityArr = this.getAllEntity();
           this.getBox(entityArr);
           entityArr.forEach(item => {
   
               const _clone = item.clone() as McDbEntity;
               if (this.rotation) _clone.rotate(this.position, this.rotation);
               draw.drawEntity(_clone);
           });
       }

6.暴露获取、设置实体内部数据的属性或方法

  // 获取或设置下标文本内容
       public set textDownStr(val: string[]) {
   
           this.textDownString = val;
       }
       public get textDownStr(): string[] {
   
           return this.textDownString;
       }
       // 获取或设置上标文本内容
       public set textUpStr(val: string[]) {
   
           this.textUpString = val;
       }
       public get textUpStr(): string[] {
   
           return this.textUpString;
       }
       // 获取或设置左边文本内容
       public set textLeftStr(val: string) {
   
           this.textLeftString = val;
       }
       public get textLeftStr(): string {
   
           return this.textLeftString;
       }
       // 获取或设置角标类型
       public set rougCornerType(val: string) {
   
           this.CornerType = val;
       }
       public get rougCornerType(): string {
   
           return this.CornerType;
       }
       // 获取或设置标注类型
       public set rougMarkType(val: number) {
   
           this.markType = val;
       }
       public get rougMarkType(): number {
   
           return this.markType;
       }
       // 获取或设置相同要求
       public set isRoungSameRequire(val: boolean) {
   
           this.isSameRequire = val;
           if (val) this.isAddLongLine = true;
       }
       public get isRoungSameRequire(): boolean {
   
           return this.isSameRequire;
       }
       // 获取或设置加长
       public set isAddRougLongLine(val: boolean) {
   
           this.isAddLongLine = val;
       }
       public get isAddRougLongLine(): boolean {
   
           return this.isAddLongLine;
       }
       // 获取或设置多数符号
       public set isShowMostSymbols(val: boolean) {
   
           this.isMostSymbols = val;
       }
       public get isShowMostSymbols(): boolean {
   
           return this.isMostSymbols;
       }
       // 获取或设置粗糙度标注高度
       public set rouDimHeight(val: number) {
   
           this.dimHeight = val;
       }
       public get rouDimHeight(): number {
   
           return this.dimHeight;
       }
       // 设置粗糙度标注位置
       public setPos(pt: McGePoint3d) {
   
           this.position = pt.clone();
       }
       // 获取粗糙度标注位置
       public getPos() {
   
           return this.position;
       }
       // 旋转角度
       public setRotation(angle: number) {
   
           this.rotation = angle
       }
       // 旋转角度
       public getRotation(): number {
   
           return this.rotation
       }
       // 获取包围盒
       public getBoundingBox(): {
    minPt: McGePoint3d; maxPt: McGePoint3d; ret: boolean; } {
   
           const entityArr = this.getAllEntity();
           this.getBox(entityArr);
           return {
    minPt: this.minPt, maxPt: this.maxPt, ret: true }
       }

使用粗糙度标注

根据粗糙度标注于直线、圆弧或圆时标注将垂直于曲线的切线上的位置特点,我们可以通过识别标注点所在的实体类型获取该实体在标注点的切线方向和位置,并以此来确定标注的旋转角度和方向。

// 粗糙度
async function Mx_Roughness() {
   
    const mxcad = MxCpp.getCurrentMxCAD();
    let rotation = 0;
    const roughness = new McDbTestRoughness();
    roughness.rougMarkType = 0;
    roughness.rougCornerType = '';
    const getPos = new MxCADUiPrPoint();
    getPos.setMessage(t('请设置定位点或直线或圆弧或圆'));
    getPos.setUserDraw((pt, pw) => {
   
        roughness.setPos(pt);
        pw.drawMcDbEntity(roughness)
    });
    const pos = await getPos.go();
    let filter = new MxCADResbuf([DxfCode.kEntityType, "LINE,ARC,CIRCLE,LWPOLYLINE"]);
    let objId = MxCADUtility.findEntAtPoint(pos.x, pos.y, pos.z, -1, filter);
    if (objId.isValid()) {
   
        const ent = objId.getMcDbEntity();
        // 拖动确定标注位置
        const getDirect = new MxCADUiPrPoint();
        getDirect.setMessage(t('拖动确定标注位置'));
        getDirect.setUserDraw((pt, pw) => {
   
            const line = ent.clone() as McDbLine;
            const closePt = line.getClosestPointTo(pt, true).val;
            const v = pt.sub(closePt);
            rotation = v.angleTo2(McGeVector3d.kYAxis, McGeVector3d.kNegateZAxis);
            roughness.setPos(closePt);
            roughness.setRotation(rotation);
            pw.drawMcDbEntity(roughness)
        });
        getDirect.setDisableDynInput(true);
        getDirect.disableAllTrace(true);
        const pt = await getDirect.go();
        if (!pt) return;
        mxcad.drawEntity(roughness)
    } else {
   
        roughness.setPos(pos);
        // 指定旋转方向
        const getAngle = new MxCADUiPrAngle();
        getAngle.setBasePt(pos);
        getAngle.setMessage(t('请指定或输入角度'));
        getAngle.setUserDraw((pt, pw) => {
   
            const line = new McDbLine(pt, pos);
            pw.drawMcDbEntity(line);
            const v = pt.sub(pos);
            rotation = v.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
            roughness.setRotation(rotation);
            pw.drawMcDbEntity(roughness)
        });
        let val = await getAngle.go();
        if (!val) return;
        const angle = getAngle.value();
        roughness.setRotation(angle);
        mxcad.drawEntity(roughness);
    }
}

效果演示

在线demo查看地址:https://demo2.mxdraw3d.com:3000/mxcad/

基础效果演示:
image-20250516115207697.png

根据上述内容可做扩展开发,设置粗糙度弹框,其示例效果如下:
image-20250516131912328.png

相关文章
|
自然语言处理 iOS开发
iOS 国际化(多语言)如何指定默认语言
iOS 国际化(多语言)如何指定默认语言
625 0
|
10月前
|
传感器 人工智能 物联网
《跨越架构鸿沟:分布式软总线实现设备通信大一统》
随着设备多样性增加,不同芯片架构(如X86、ARM、RISC-V)在通信中面临诸多障碍。分布式软总线技术应运而生,通过融合底层通信技术、协议货架适配和中间适配层,屏蔽硬件、操作系统及协议差异,实现高效统一通信。该技术已在智能家居与办公场景中展现价值,未来结合AI与新一代通信技术,将助力万物互联愿景的实现。
441 6
|
前端开发 数据可视化 Java
第一篇:瑞吉外卖项目概述
第一篇:瑞吉外卖项目概述
3519 0
第一篇:瑞吉外卖项目概述
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
掌握从模型选型到部署优化的全流程
本文深入探讨了AI大模型的开发与应用,涵盖基础概念、模型架构、关键技术、训练方法、应用策略、评估优化及伦理安全七大核心内容。从人工智能的定义到深度学习、通用人工智能(AGI)的探索,再到Transformer架构、混合专家模型(MoE)等前沿技术,系统解析了构建智能系统的基石与工程效率的引擎。文章还介绍了提示工程、检索增强生成(RAG)、AI智能体等应用策略,强调了模型评估与优化的重要性,并探讨了AI伦理与安全的关键议题。适合希望全面了解AI大模型开发的技术人员与研究者参考。
507 0
|
9月前
|
消息中间件 存储 JSON
日志采集 Agent 性能大比拼——LoongCollector 性能深度测评
为了展现 LoongCollector 的卓越性能,本文通过纵向(LoongCollector 与 iLogtail 产品升级对比)和横向(LoongCollector 与其他开源日志采集 Agent 对比)两方面对比,深度测评不同采集 Agent 在常见的日志采集场景下的性能。
886 35
|
机器学习/深度学习 人工智能 自然语言处理
人工智能与未来医疗:AI技术在疾病诊断中的应用前景####
本文探讨了人工智能(AI)在现代医疗领域,尤其是疾病诊断方面的应用潜力和前景。随着技术的不断进步,AI正逐渐改变传统医疗模式,提高诊断的准确性和效率。通过分析当前的技术趋势、具体案例以及面临的挑战,本文旨在为读者提供一个全面的视角,理解AI如何塑造未来医疗的面貌。 ####
|
存储 Java
Java“(array) <X> Not Initialized” (数组未初始化)错误解决
在Java中,遇到“(array) &lt;X&gt; Not Initialized”(数组未初始化)错误时,表示数组变量已被声明但尚未初始化。解决方法是在使用数组之前,通过指定数组的大小和类型来初始化数组,例如:`int[] arr = new int[5];` 或 `String[] strArr = new String[10];`。
519 2
|
存储 编解码 算法
Transformers 4.37 中文文档(九十三)(4)
Transformers 4.37 中文文档(九十三)
568 1
|
Ubuntu 数据安全/隐私保护
百度搜索:蓝易云【如何在 Ubuntu 22.04 LTS 上安装分区编辑器 GParted?】
希望这些步骤能够帮助您在Ubuntu 22.04 LTS上安装GParted并顺利使用它进行分区管理。
348 0