夜雨聆风学习资料网

ARTICLE · 1295134

全网罕见的二维《工业制图软件》源码项目

全网罕见的二维《工业制图软件》源码项目

欢迎来到【Qt开发笔记】微信公众号【知识宝库】!

大家好,今天给大家看一个全网罕见的二维《工业制图软件》源码项目——工程制图软件 v1.0。

它不是简单的画线画圆Demo,而是一套基于Qt 6 / C++17 + Graphics View Framework构建的二维工程绘图编辑器雏形:基础图形、电气符号、流程图符号三大组件库支持拖拽创建;直线、圆、矩形、折线、样条曲线、图形连线等绘制模式齐全;属性编辑、网格显示、对象捕捉、图层管理、缩放平移、橡皮筋框选、撤销重做、XML工程文件保存/加载,一条绘图编辑器的核心链路基本打通。

更硬核的是,项目采用.edw + XML文本格式保存图层与图形对象,基于QUndoStack实现AddShapeCommand、RemoveShapeCommand、MoveShapeCommand、ChangePropertyCommand等命令体系,并包含GridManager、SnapManager、图层模型与图层管理器等可扩展模块。对于想研究Qt桌面应用架构、图形编辑器、工业符号库、撤销重做与序列化的开发者来说,这套源码的参考价值远超普通画板项目。

如果你想做一个真正像“软件”的Qt项目,而不是只能截图交作业的Demo,这个工程值得拆开看看。

👉 关注【Qt开发笔记】,获取更多Qt/C++硬核技术干货。

⭐关注博主后私信领取源码/学习资料📑。

一、【工程项目运行】

1、基础图形

2、电气符号

3、流程图符号

二、【工程项目简介】

1、项目简介

工程制图软件是一款基于Qt 6 / C++17开发的桌面端二维工程绘图应用。项目使用Qt Widgets与Graphics View Framework构建绘图画布,支持基础几何图形、电气符号、流程图符号的绘制与拖拽创建,并提供文件保存/加载、撤销重做、属性编辑、网格显示、对象捕捉、图层模型、测量工具等功能。

当前应用名称与窗口标题为工程制图软件 v1.0,默认工程文件扩展名为.edw,底层采用XML文本格式保存。

2、使用技术栈

| 分类     | 技术 || 编程语言 | C++17|| GUI 框架 | Qt 6 Widgets || 绘图框架 | Qt Graphics View Framework || 文件格式 | XML / .edw || 撤销重做 | Qt Undo Framework / QUndoStack || 资源系统 | Qt Resource System/ .qrc || 构建系统 | qmake || 推荐环境 | Qt 6.5.x、MinGW 64-bit、Windows 10/11|
3、功能特性

3.1 文件管理

- 新建工程图

- 打开.edw工程图文件

- 保存当前工程图

- 另存为工程图

- 关闭窗口时检测绘图区内容并提示保存

- 使用 XML 保存图层与图形对象

- 支持底层网表文本生成接口

3.2 绘图能力

工具栏和菜单支持以下绘制模式:

- 选择

- 直线

- 圆

- 矩形

- 折线

- 样条曲线

- 图形连线

状态栏会根据当前工具显示操作提示,例如绘制直线、绘制圆、绘制折线、绘制样条曲线和连接图形等。

3.3 组件库

左侧组件库支持拖拽组件到绘图区域创建图形,分为三类。

基础图形

- 直线 Line

- 圆 Circle

- 椭圆 Ellipse

- 圆弧 Arc

- 扇形 Sector

- 多边形 Polygon

- 星形 Star

- 矩形 Rectangle

- 圆角矩形 RoundedRect

- 箭头 Arrow

- 文本框 TextBox

- 折线 Polyline

- 样条曲线 Spline

电气符号

- 普通二极管 Diode

- 变容二极管 VaricapDiode

- NPN 三极管 NPNTransistor

- PNP 三极管 PNPTransistor

- 电阻 Resistor

- 电容 Capacitor

- 电感 Inductor

- 开关 Switch

- 接地 Ground

- 电源 PowerSupply

流程图符号

- 开始/结束 Terminator

- 处理 Process

- 判断 Decision

- 数据 Data

- 文档 Document

- 连接器 Connector

3.4 属性编辑

右侧属性面板支持对选中图形进行属性查看与编辑,主要包括:

- 图形名称

- 画笔宽度

- 画笔颜色

- 填充颜色

- 部分图形的专有属性显示

3.5 视图操作

- 抗锯齿绘制

- 平滑图像变换

- 橡皮筋框选

- Ctrl + 鼠标滚轮 缩放

- 鼠标中键拖动画布平移

- 放大、缩小、适应窗口

- 以鼠标位置为缩放锚点

3.6 网格与捕捉

GridManager支持:

- 显示/隐藏网格

- 设置网格大小

- 设置网格颜色

- 在场景背景中绘制网格

SnapManager支持的捕捉类型:

- NoSnap

- EndPoint

- MidPoint

- Center

- Intersection

- Grid

- All

3.7 图层管理

项目包含图层模型与图层管理器,支持:

- 创建图层

- 删除图层

- 清空图层

- 设置当前图层

- 查找图层

- 图层可见性

- 图层锁定状态

- 图层颜色

- 图形与图层关联

图层信息会保存到.edw文件中。

3.8 撤销与重做

基于QUndoStack实现撤销重做,包含命令类:

- AddShapeCommand:添加图形

- RemoveShapeCommand:删除图形

- MoveShapeCommand:移动图形

- ChangePropertyCommand:修改图形属性

三、【工程核心源码】

1、arcshape.h

#ifndef ARCSHAPE_H#define ARCSHAPE_H#include "shape.h"classArcShape : publicShape{public:explicitArcShape(const QPointF &center = QPointF(), qreal radius = 50.0,                      qreal startAngle = 0.0, qreal spanAngle = 90.0,                      QGraphicsItem *parent = nullptr);ShapeType shapeType() constoverride { return CircleType; }    Shape* clone() constoverride;QPointF center() const { return m_center; }voidsetCenter(const QPointF &center);qreal radius() const { return m_radius; }voidsetRadius(qreal radius);qreal startAngle() const { return m_startAngle; }voidsetStartAngle(qreal angle);qreal spanAngle() const { return m_spanAngle; }voidsetSpanAngle(qreal angle);qreal endAngle() const { return m_startAngle + m_spanAngle; }qreal arcLength() const;QPointF startPoint() const;QPointF endPoint() const;// QGraphicsItem接口QRectF boundingRect() constoverride;voidpaint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;QPainterPath shape() constoverride;// 序列化voidsaveToXml(QXmlStreamWriter &writer) constoverride;voidloadFromXml(QXmlStreamReader &reader) override;// 调整大小voidupdateResizeHandles() override;private:    QPointF m_center;    qreal m_radius;    qreal m_startAngle;  // 起始角度(度)    qreal m_spanAngle;   // 跨越角度(度)};#endif // ARCSHAPE_H
2、arcshape.cpp
#include "arcshape.h"#include "resizehandle.h"#include <QPainter>#include <QtMath>ArcShape::ArcShape(const QPointF &center, qreal radius, qreal startAngle, qreal spanAngle, QGraphicsItem *parent)    : Shape(parent)    , m_center(center)    , m_radius(radius)    , m_startAngle(startAngle)    , m_spanAngle(spanAngle){}Shape* ArcShape::clone() const{    ArcShape *newShape = new ArcShape(m_center, m_radius, m_startAngle, m_spanAngle);    newShape->setPen(m_pen);    newShape->setBrush(m_brush);    newShape->setPos(pos());return newShape;}voidArcShape::setCenter(const QPointF &center){prepareGeometryChange();    m_center = center;update();}voidArcShape::setRadius(qreal radius){prepareGeometryChange();    m_radius = qAbs(radius);update();}voidArcShape::setStartAngle(qreal angle){prepareGeometryChange();// 规范化角度到 0-360 范围    m_startAngle = fmod(angle, 360.0);if(m_startAngle < 0) m_startAngle += 360.0;update();}voidArcShape::setSpanAngle(qreal angle){prepareGeometryChange();// 限制跨越角度在 -360 到 360 之间    m_spanAngle = qBound(-360.0, angle, 360.0);update();}qreal ArcShape::arcLength() const{// 弧长 = 半径 × 弧度    qreal radians = qDegreesToRadians(qAbs(m_spanAngle));return m_radius * radians;}QPointF ArcShape::startPoint() const{    qreal rad = qDegreesToRadians(m_startAngle);return QPointF(m_center.x() + m_radius * qCos(rad),                   m_center.y() - m_radius * qSin(rad));}QPointF ArcShape::endPoint() const{    qreal rad = qDegreesToRadians(m_startAngle + m_spanAngle);return QPointF(m_center.x() + m_radius * qCos(rad),                   m_center.y() - m_radius * qSin(rad));}QRectF ArcShape::boundingRect() const{    qreal extra = m_pen.width() / 2.0;return QRectF(m_center.x() - m_radius - extra,                  m_center.y() - m_radius - extra,2 * m_radius + 2 * extra,2 * m_radius + 2 * extra);}voidArcShape::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){Q_UNUSED(option);Q_UNUSED(widget);    painter->setPen(m_pen);    painter->setBrush(Qt::NoBrush);  // 确保不填充// 使用 QPainterPath 绘制圆弧,确保不填充QRectF rect(m_center.x() - m_radius, m_center.y() - m_radius,2 * m_radius, 2 * m_radius);int startAngle16 = qRound(m_startAngle * 16);int spanAngle16 = qRound(m_spanAngle * 16);    QPainterPath path;    path.arcMoveTo(rect, m_startAngle);    path.arcTo(rect, m_startAngle, m_spanAngle);    painter->drawPath(path);  // 只绘制路径,不填充if(isSelected()) {        painter->setPen(QPen(Qt::blue, 1, Qt::DashLine));        painter->setBrush(Qt::NoBrush);        painter->drawRect(boundingRect());// 绘制中心点        painter->setPen(QPen(Qt::blue, 2));        painter->setBrush(Qt::blue);        painter->drawEllipse(m_center, 3, 3);// 绘制起点和终点        painter->setPen(QPen(Qt::green, 2));        painter->setBrush(Qt::green);        painter->drawEllipse(startPoint(), 4, 4);        painter->setPen(QPen(Qt::red, 2));        painter->setBrush(Qt::red);        painter->drawEllipse(endPoint(), 4, 4);// 绘制半径线        painter->setPen(QPen(Qt::blue, 1, Qt::DotLine));        painter->setBrush(Qt::NoBrush);        painter->drawLine(m_center, startPoint());        painter->drawLine(m_center, endPoint());// 绘制完整圆的虚线参考(不填充)        painter->setPen(QPen(Qt::gray, 1, Qt::DotLine));        painter->setBrush(Qt::NoBrush);        painter->drawEllipse(m_center, m_radius, m_radius);    }}QPainterPath ArcShape::shape() const{    QPainterPath path;QRectF rect(m_center.x() - m_radius, m_center.y() - m_radius,2 * m_radius, 2 * m_radius);    path.arcMoveTo(rect, m_startAngle);    path.arcTo(rect, m_startAngle, m_spanAngle);    QPainterPathStroker stroker;    stroker.setWidth(qMax(m_pen.widthF(), 5.0));return stroker.createStroke(path);}voidArcShape::saveToXml(QXmlStreamWriter &writer) const{    writer.writeStartElement("Arc");    writer.writeAttribute("cx", QString::number(m_center.x()));    writer.writeAttribute("cy", QString::number(m_center.y()));    writer.writeAttribute("radius", QString::number(m_radius));    writer.writeAttribute("startAngle", QString::number(m_startAngle));    writer.writeAttribute("spanAngle", QString::number(m_spanAngle));saveBaseProperties(writer);    writer.writeEndElement();}voidArcShape::loadFromXml(QXmlStreamReader &reader){    QXmlStreamAttributes attrs = reader.attributes();if(attrs.hasAttribute("cx") && attrs.hasAttribute("cy")) {        m_center.setX(attrs.value("cx").toDouble());        m_center.setY(attrs.value("cy").toDouble());    }if(attrs.hasAttribute("radius")) {        m_radius = attrs.value("radius").toDouble();    }if(attrs.hasAttribute("startAngle")) {        m_startAngle = attrs.value("startAngle").toDouble();    }if(attrs.hasAttribute("spanAngle")) {        m_spanAngle = attrs.value("spanAngle").toDouble();    }loadBaseProperties(reader);}voidArcShape::updateResizeHandles(){hideResizeHandles();// 在圆弧的起点添加手柄(调整起始角度)    ResizeHandle *startHandle = new ResizeHandle(ResizeHandle::TopLeft, this);    startHandle->setPos(startPoint());    m_resizeHandles.append(startHandle);// 在圆弧的终点添加手柄(调整跨越角度)    ResizeHandle *endHandle = new ResizeHandle(ResizeHandle::TopRight, this);    endHandle->setPos(endPoint());    m_resizeHandles.append(endHandle);// 在圆弧的中点添加手柄(调整半径)    qreal midAngle = m_startAngle + m_spanAngle / 2.0;    qreal rad = qDegreesToRadians(midAngle);QPointF midPoint(m_center.x() + m_radius * qCos(rad),                     m_center.y() - m_radius * qSin(rad));    ResizeHandle *radiusHandle = new ResizeHandle(ResizeHandle::Right, this);    radiusHandle->setPos(midPoint);    m_resizeHandles.append(radiusHandle);}
3、arrowshape.h
#ifndef ARROWSHAPE_H#define ARROWSHAPE_H#include "shape.h"classArrowShape : publicShape{public:enum ArrowStyle {        SingleArrow,    // 单向箭头        DoubleArrow,    // 双向箭头        FilledArrow,    // 实心箭头        OpenArrow       // 空心箭头    };explicitArrowShape(const QPointF &start = QPointF(), const QPointF &end = QPointF(),                       qreal arrowSize = 15.0, ArrowStyle style = FilledArrow,                       QGraphicsItem *parent = nullptr);ShapeType shapeType() constoverride { return LineType; }    Shape* clone() constoverride;QPointF startPoint() const { return m_start; }voidsetStartPoint(const QPointF &point);QPointF endPoint() const { return m_end; }voidsetEndPoint(const QPointF &point);qreal arrowSize() const { return m_arrowSize; }voidsetArrowSize(qreal size);ArrowStyle arrowStyle() const { return m_style; }voidsetArrowStyle(ArrowStyle style);qreal length() const;qreal angle() const;// QGraphicsItem接口QRectF boundingRect() constoverride;voidpaint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;QPainterPath shape() constoverride;// 序列化voidsaveToXml(QXmlStreamWriter &writer) constoverride;voidloadFromXml(QXmlStreamReader &reader) override;// 调整大小voidupdateResizeHandles() override;private:    QPointF m_start;    QPointF m_end;    qreal m_arrowSize;    ArrowStyle m_style;QPolygonF createArrowHead(const QPointF &tip, qreal angle) const;};#endif // ARROWSHAPE_H
4、arrowshape.cpp
#include"arrowshape.h"#include"resizehandle.h"#include<QPainter>#include<QtMath>ArrowShape::ArrowShape(const QPointF &start, const QPointF &end, qreal arrowSize, ArrowStyle style, QGraphicsItem *parent)    : Shape(parent)    , m_start(start)    , m_end(end)    , m_arrowSize(qAbs(arrowSize))    , m_style(style){}Shape* ArrowShape::clone()const{    ArrowShape *newShape = newArrowShape(m_start, m_end, m_arrowSize, m_style);    newShape->setPen(m_pen);    newShape->setBrush(m_brush);    newShape->setPos(pos());return newShape;}voidArrowShape::setStartPoint(const QPointF &point){prepareGeometryChange();    m_start = point;update();}voidArrowShape::setEndPoint(const QPointF &point){prepareGeometryChange();    m_end = point;update();}voidArrowShape::setArrowSize(qreal size){prepareGeometryChange();    m_arrowSize = qAbs(size);update();}voidArrowShape::setArrowStyle(ArrowStyle style){prepareGeometryChange();    m_style = style;update();}qreal ArrowShape::length()const{returnQLineF(m_start, m_end).length();}qreal ArrowShape::angle()const{QLineF line(m_start, m_end);return line.angle();}QPolygonF ArrowShape::createArrowHead(const QPointF &tip, qreal angle)const{    QPolygonF arrowHead;    qreal radAngle = qDegreesToRadians(angle);    qreal arrowAngle = M_PI / 6.0; // 30度箭头角    QPointF p1 = tip - QPointF(m_arrowSize * qCos(radAngle - arrowAngle),                                -m_arrowSize * qSin(radAngle - arrowAngle));    QPointF p2 = tip - QPointF(m_arrowSize * qCos(radAngle + arrowAngle),                                -m_arrowSize * qSin(radAngle + arrowAngle));    arrowHead << tip << p1 << p2;return arrowHead;}QRectF ArrowShape::boundingRect()const{    qreal extra = (m_pen.width() + m_arrowSize) / 2.0;    QRectF rect = QRectF(m_start, m_end).normalized();return rect.adjusted(-extra, -extra, extra, extra);}voidArrowShape::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){Q_UNUSED(option);Q_UNUSED(widget);    painter->setPen(m_pen);    painter->setBrush(m_brush);// 绘制线段QLineF line(m_start, m_end);    painter->drawLine(line);// 计算箭头角度    qreal angle = line.angle();// 绘制终点箭头    QPolygonF endArrow = createArrowHead(m_end, angle);if (m_style == FilledArrow || m_style == DoubleArrow) {        painter->setBrush(m_pen.color());        painter->drawPolygon(endArrow);    } else {        painter->setBrush(Qt::NoBrush);        painter->drawPolyline(endArrow);    }// 如果是双向箭头,绘制起点箭头if (m_style == DoubleArrow) {        QPolygonF startArrow = createArrowHead(m_start, angle + 180.0);        painter->setBrush(m_pen.color());        painter->drawPolygon(startArrow);    }if (isSelected()) {        painter->setPen(QPen(Qt::blue, 1, Qt::DashLine));        painter->setBrush(Qt::NoBrush);        painter->drawRect(boundingRect());    }}QPainterPath ArrowShape::shape()const{    QPainterPath path;// 线段路径    path.moveTo(m_start);    path.lineTo(m_end);// 添加箭头区域QLineF line(m_start, m_end);    qreal angle = line.angle();    QPolygonF endArrow = createArrowHead(m_end, angle);    path.addPolygon(endArrow);if (m_style == DoubleArrow) {        QPolygonF startArrow = createArrowHead(m_start, angle + 180.0);        path.addPolygon(startArrow);    }    QPainterPathStroker stroker;    stroker.setWidth(m_pen.width() + 4);return stroker.createStroke(path);}voidArrowShape::saveToXml(QXmlStreamWriter &writer)const{    writer.writeStartElement("Arrow");    writer.writeAttribute("x1", QString::number(m_start.x()));    writer.writeAttribute("y1", QString::number(m_start.y()));    writer.writeAttribute("x2", QString::number(m_end.x()));    writer.writeAttribute("y2", QString::number(m_end.y()));    writer.writeAttribute("arrowSize", QString::number(m_arrowSize));    writer.writeAttribute("style", QString::number(static_cast<int>(m_style)));saveBaseProperties(writer);    writer.writeEndElement();}voidArrowShape::loadFromXml(QXmlStreamReader &reader){    QXmlStreamAttributes attrs = reader.attributes();if (attrs.hasAttribute("x1") && attrs.hasAttribute("y1")) {        m_start.setX(attrs.value("x1").toDouble());        m_start.setY(attrs.value("y1").toDouble());    }if (attrs.hasAttribute("x2") && attrs.hasAttribute("y2")) {        m_end.setX(attrs.value("x2").toDouble());        m_end.setY(attrs.value("y2").toDouble());    }if (attrs.hasAttribute("arrowSize")) {        m_arrowSize = attrs.value("arrowSize").toDouble();    }if (attrs.hasAttribute("style")) {        m_style = static_cast<ArrowStyle>(attrs.value("style").toInt());    }loadBaseProperties(reader);}voidArrowShape::updateResizeHandles(){hideResizeHandles();// 起点手柄    ResizeHandle *startHandle = newResizeHandle(ResizeHandle::TopLeft, this);    startHandle->setPos(m_start);    m_resizeHandles.append(startHandle);// 终点手柄    ResizeHandle *endHandle = newResizeHandle(ResizeHandle::BottomRight, this);    endHandle->setPos(m_end);    m_resizeHandles.append(endHandle);}
5、capacitorshape.h
#ifndef CAPACITORSHAPE_H#define CAPACITORSHAPE_H#include"shape.h"classCapacitorShape : public Shape{public:explicitCapacitorShape(const QPointF &center = QPointF(), qreal size = 70.0, QGraphicsItem *parent = nullptr);ShapeType shapeType()constoverride{ return LineType; }Shape* clone()constoverride;QPointF center()const{ return m_center; }voidsetCenter(const QPointF &center);qreal size()const{ return m_size; }voidsetSize(qreal size);QRectF boundingRect()constoverride;voidpaint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr)override;QPainterPath shape()constoverride;voidsaveToXml(QXmlStreamWriter &writer)constoverride;voidloadFromXml(QXmlStreamReader &reader)override;protected:voidupdateResizeHandles()override;private:    QPointF m_center;    qreal m_size;};#endif// CAPACITORSHAPE_H
6、capacitorshape.cpp
#include "capacitorshape.h"#include "resizehandle.h"#include <QPainter>#include <QtMath>CapacitorShape::CapacitorShape(const QPointF &center, qreal size, QGraphicsItem *parent)    : Shape(parent)    , m_center(center)    , m_size(qAbs(size)){}Shape* CapacitorShape::clone() const{    CapacitorShape *newShape = new CapacitorShape(m_center, m_size);    newShape->setPen(m_pen);    newShape->setBrush(m_brush);    newShape->setPos(pos());return newShape;}voidCapacitorShape::setCenter(const QPointF &center){prepareGeometryChange();    m_center = center;update();}voidCapacitorShape::setSize(qreal size){prepareGeometryChange();    m_size = qAbs(size);update();}QRectF CapacitorShape::boundingRect() const{constqreal extra = m_pen.widthF() / 2.0 + 2.0;constqreal halfSize = m_size / 2.0;constqreal plateWidth = m_size * 0.45;return QRectF(m_center.x() - plateWidth / 2.0 - extra,                  m_center.y() - halfSize - extra,                  plateWidth + 2.0 * extra,                  m_size + 2.0 * extra);}voidCapacitorShape::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){Q_UNUSED(option);Q_UNUSED(widget);    painter->setPen(m_pen);    painter->setBrush(Qt::NoBrush);constqreal halfSize = m_size / 2.0;constqreal plateWidth = m_size * 0.45;constqreal gap = m_size * 0.12;constqreal plateY1 = m_center.y() - gap / 2.0;constqreal plateY2 = m_center.y() + gap / 2.0;// 上引线    painter->drawLine(QPointF(m_center.x(), m_center.y() - halfSize),QPointF(m_center.x(), plateY1));// 电容两极板(两条平行线)    painter->drawLine(QPointF(m_center.x() - plateWidth / 2.0, plateY1),QPointF(m_center.x() + plateWidth / 2.0, plateY1));    painter->drawLine(QPointF(m_center.x() - plateWidth / 2.0, plateY2),QPointF(m_center.x() + plateWidth / 2.0, plateY2));// 下引线    painter->drawLine(QPointF(m_center.x(), plateY2),QPointF(m_center.x(), m_center.y() + halfSize));if(isSelected()) {        painter->setPen(QPen(Qt::blue, 1, Qt::DashLine));        painter->setBrush(Qt::NoBrush);        painter->drawRect(boundingRect());        painter->setBrush(Qt::blue);        painter->drawEllipse(m_center, 3, 3);    }}QPainterPath CapacitorShape::shape() const{    QPainterPath path;constqreal halfSize = m_size / 2.0;constqreal plateWidth = m_size * 0.45;constqreal gap = m_size * 0.12;constqreal plateY1 = m_center.y() - gap / 2.0;constqreal plateY2 = m_center.y() + gap / 2.0;    path.moveTo(m_center.x(), m_center.y() - halfSize);    path.lineTo(m_center.x(), plateY1);    path.moveTo(m_center.x() - plateWidth / 2.0, plateY1);    path.lineTo(m_center.x() + plateWidth / 2.0, plateY1);    path.moveTo(m_center.x() - plateWidth / 2.0, plateY2);    path.lineTo(m_center.x() + plateWidth / 2.0, plateY2);    path.moveTo(m_center.x(), plateY2);    path.lineTo(m_center.x(), m_center.y() + halfSize);    QPainterPathStroker stroker;    stroker.setWidth(qMax(m_pen.widthF(), 6.0));return stroker.createStroke(path);}voidCapacitorShape::saveToXml(QXmlStreamWriter &writer) const{    writer.writeStartElement("Capacitor");    writer.writeAttribute("cx", QString::number(m_center.x()));    writer.writeAttribute("cy", QString::number(m_center.y()));    writer.writeAttribute("size", QString::number(m_size));saveBaseProperties(writer);    writer.writeEndElement();}voidCapacitorShape::loadFromXml(QXmlStreamReader &reader){constQXmlStreamAttributes attrs = reader.attributes();if(attrs.hasAttribute("cx") && attrs.hasAttribute("cy")) {        m_center.setX(attrs.value("cx").toDouble());        m_center.setY(attrs.value("cy").toDouble());    }if(attrs.hasAttribute("size")) {        m_size = attrs.value("size").toDouble();    }loadBaseProperties(reader);}voidCapacitorShape::updateResizeHandles(){hideResizeHandles();    ResizeHandle *handle = new ResizeHandle(ResizeHandle::Bottom, this);    handle->setPos(m_center.x(), m_center.y() + m_size / 2.0);    m_resizeHandles.append(handle);}
希望这篇文章能为您的C++/Qt开发等学习提供有价值的参考!感谢您的关注👉【Qt开发笔记】微信公众号,获取更多技术干货。

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料