1. 界面排布

m_pVLayout->addWidget(m_pMenuBar);m_pHLayout->addWidget(m_pToolBar);m_pHLayout->addWidget(m_pSvgMainWin);m_pHLayout->addWidget(m_pCanvasParamsBar);m_pVLayout->addLayout(m_pHLayout);m_pVLayout->addWidget(m_pColorBar);ui.centralWidget->setLayout(m_pVLayout);
m_pToolBar 工具栏类垂直布局了KToolButton类;
m_pCanvasParamsBar 属性框类列表布局了KColorBox(颜色选择框)、 KValueBox(属性设置框)、KCanvasScaleBox(画布比例框)。
其中 KValueBox采用了正则表达式,对用户输入数据进行判断。
//正则表达式QRegExp reg("[1-9][0-9]+$");QValidator* validator = new QRegExpValidator(reg, m_pParamEdit);m_pParamEdit->setValidator(validator);m_pVLayout->addWidget(m_pParamEdit);}
2. 基本图形绘制
pen画笔类
判断绘画类型,如果是画笔类,调用addPos,记录每一个路径点。
else if (flag == KGlobalData::KDrawFlag::PenFlag){m_isSelected = false;m_pCurrentShape = KShapeFactory::createShape(KGlobalData::getGlobalDataIntance()->getDrawFlag());if (m_pCurrentShape != NULL){qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();static_cast<KPen*>(m_pCurrentShape)->addPos(event->pos() / scale);}}
void KPen::addPos(QPoint pos){if (m_posVector.isEmpty()){m_startPoint = pos;m_endPoint = pos;}else{if (pos.x() < m_startPoint.x())m_startPoint.rx() = pos.x();if (pos.y() < m_startPoint.y())m_startPoint.ry() = pos.y();if (pos.x() > m_endPoint.x())m_endPoint.rx() = pos.x();if (pos.y() > m_endPoint.y())m_endPoint.ry() = pos.y();}m_posVector.append(pos);}
绘制画笔时,使用drawPath( )画出每一个点
void KPen::drawShape(QPaintDevice* parent){QPainter painter(parent);QPainterPath path;QVector<QPoint>::iterator pos = m_posVector.begin();path.moveTo(*pos);while (pos != m_posVector.end()){path.lineTo(*pos);pos++;}qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidthF(m_borderWidth);painter.setPen(pen);painter.drawPath(path);}
line直线类
记录起始点,并绘制线条
void KLine::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidth(m_borderWidth);painter.setPen(pen);painter.drawLine(getStartPoint(), getEndPoint());}
circle圆类
记录鼠标起始点,绘制椭圆(正圆)。
void KCircle::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidth(m_borderWidth);painter.setPen(pen);painter.setBrush(QColor("#" + m_fillColor));painter.drawEllipse(QRect(getStartPoint(), getEndPoint()));}
rect矩形
记录鼠标起始点,绘制图形。
void KRect::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidth(m_borderWidth);painter.setPen(pen);painter.setBrush(QColor("#" + m_fillColor));painter.drawRect(QRect(getStartPoint(), getEndPoint()));}
pent五边形类
记录起始点,配合我自己计算出的比例,算出五个顶点相对坐标,数组记录并绘图。

void KPent::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);// 绘制五边形int l = getEndPoint().x() - getStartPoint().x();int h = getEndPoint().y() - getStartPoint().y();int x1 = getStartPoint().x();int y1 = getStartPoint().y();int x2 = getEndPoint().x();int y2 = getEndPoint().y();QPoint p1(x1 + (l / 2), y1);QPoint p2(x1 + (0.206 * l), y2 );QPoint p3(x1 + (0.794 * l), y2 );QPoint p4(x1 + 0.05 * l, y1 + (h * 0.383));QPoint p5(x2 - 0.05 * l, y1 + (h * 0.383));m_polygon[0] = p1;m_polygon[1] = p4;m_polygon[2] = p2;m_polygon[3] = p3;m_polygon[4] = p5;QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidth(m_borderWidth);painter.setPen(pen);painter.setBrush(QColor("#" + m_fillColor));painter.drawPolygon(m_polygon,5);}
hexa六边形类
记录起始点,配合我自己计算出的比例,算出六个顶点相对坐标,数组记录并绘图。
void KHexa::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);// 绘制六边形int l = getEndPoint().x() - getStartPoint().x();int h = getEndPoint().y() - getStartPoint().y();int x1 = getStartPoint().x();int y1 = getStartPoint().y();int x2 = getEndPoint().x();int y2 = getEndPoint().y();//topQPoint p1(x1 + (l / 2), y1);//bottomQPoint p2(x2 - (l / 2), y2);//othersQPoint p3(x2 - 0.067 * l, y1 + (h * 0.25));QPoint p4(x2 - 0.067 * l, y1 + (h * 0.75));QPoint p5(x1 + 0.067 * l, y1 + (h * 0.75));QPoint p6(x1 + 0.067 * l, y1 + (h * 0.25));m_polygon[0] = p1;m_polygon[1] = p3;m_polygon[2] = p4;m_polygon[3] = p2;m_polygon[4] = p5;m_polygon[5] = p6;QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidth(m_borderWidth);painter.setPen(pen);painter.setBrush(QColor("#" + m_fillColor));painter.drawPolygon(m_polygon, 6);}
star 五角星类
记录起始点,配合我自己计算出的比例,算出10个顶点相对坐标,数组记录并绘图。
void KStar::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);int l = getEndPoint().x() - getStartPoint().x();int h = getEndPoint().y() - getStartPoint().y();int x1 = getStartPoint().x();int y1 = getStartPoint().y();int x2 = getEndPoint().x();int y2 = getEndPoint().y();//topQPoint p1(x1 + (l / 2), y1);QPoint p2(x1 + (l * 0.618), y1 + (h * 0.338));QPoint p3(x2 - (l * 0.05), y1 + (h * 0.338));QPoint p4(x2 - 0.31 * l, y2 - (h * 0.438));QPoint p5(x2 - 0.206 * l, y2 - (h * 0.1));QPoint p6(x1 + (l / 2), y2 - (h * 0.3));QPoint p7(x1 + 0.206 * l, y2 - (h * 0.1));QPoint p8(x1 + 0.31 * l, y2 - (h * 0.438));QPoint p9(x1 + (l * 0.05), y1 + (h * 0.338));QPoint p10(x2 - (l * 0.618), y1 + (h * 0.338));m_polygon[0] = p1;m_polygon[1] = p2;m_polygon[2] = p3;m_polygon[3] = p4;m_polygon[4] = p5;m_polygon[5] = p6;m_polygon[6] = p7;m_polygon[7] = p8;m_polygon[8] = p9;m_polygon[9] = p10;QPen pen;pen.setColor(QColor("#" + m_borderColor));pen.setWidth(m_borderWidth);painter.setPen(pen);painter.setBrush(QColor("#" + m_fillColor));painter.drawPolygon(m_polygon, 10);}
text文字类
在主画布调用该函数,设置lineeditor父窗口为主画布
else if (flag == KGlobalData::KDrawFlag::TextFlag){m_isSelected = false;m_pCurrentShape = KShapeFactory::createShape(KGlobalData::getGlobalDataIntance()->getDrawFlag());KText* temp = (KText*)m_pCurrentShape;temp->setParent(this);temp = NULL;delete temp;if (m_pCurrentShape != NULL){qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();m_pCurrentShape->setStartPoint(event->pos() / scale);}}
void KText::setParent(QWidget *parent){m_textLine->setParent(parent);}
对m_text判断,关闭编辑框,否则会形成二重叠加态。
KText::KText(){m_textLine = new QLineEdit;m_textLine->setFrame(false);m_textLine->setPlaceholderText("Please enter text");m_borderColor = "000000";}KText::~KText(){}void KText::drawShape(QPaintDevice* parent){QPainter painter(parent);qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();painter.scale(scale, scale);painter.setRenderHint(QPainter::Antialiasing);QPen pen;pen.setColor(QColor("#" + m_borderColor));painter.setPen(pen);QRectF r1(getStartPoint(), getEndPoint());setEndPoint(QPoint(getStartPoint().x() + 100, getStartPoint().y() + 50));if (m_text == ""){m_textLine->move(getStartPoint() * scale);m_text = m_textLine->text();painter.drawText(r1, m_text);m_textLine->show();}if (m_text != ""){m_textLine->close();painter.drawText(r1, m_text);}}
3. 信号与槽
详见注释。
void KSvgEditor::initConnection(){(void)connect(m_pMenuBar->m_pSaveFileAction, SIGNAL(triggered()), m_pSvgMainWin->m_pCanvas, SLOT(saveSvg())); //保存(void)connect(m_pCanvasParamsBar->m_pWidthBox->m_pParamEdit, SIGNAL(editingFinished()), this, SLOT(validateCanvasParams())); //设置画布宽度(void)connect(m_pCanvasParamsBar->m_pHeightBox->m_pParamEdit, SIGNAL(editingFinished()), this, SLOT(validateCanvasParams())); //设置画布高度(void)connect(m_pCanvasParamsBar->m_pColorBox, SIGNAL(pickedColor()), this, SLOT(validateCanvasParams())); //设置画布颜色(void)connect(m_pCanvasParamsBar->m_pfillColorBox, SIGNAL(pickedColor()), this, SLOT(fillColor())); //设置填充颜色(void)connect(m_pCanvasParamsBar->m_pBorderColorBox, SIGNAL(pickedColor()), this, SLOT(borderColor())); //设置边框颜色(pen,line颜色)(void)connect(m_pCanvasParamsBar->m_pBorderWidthBox->m_pParamEdit, SIGNAL(editingFinished()), this, SLOT(borderWidth())); //设置边框宽度(pen,line线宽)(void)connect(m_pCanvasParamsBar->m_pScaleBox->m_pParamEdit, SIGNAL(editingFinished()), this, SLOT(validateCanvasParams())); //设置缩放比例修改(void)connect(m_pSvgMainWin, SIGNAL(changeScale(qreal)), this, SLOT(setScale(qreal))); //设置缩放比例显示(void)connect(m_pToolBar->m_pZoomBtn, SIGNAL(showParam()), this, SLOT(closeParamsbar())); //属性栏选择性显示(void)connect(m_pSvgMainWin->m_pCanvas, SIGNAL(mouseChange()), this, SLOT(showItemParambar()));//属性栏选择性显示(void)connect(m_pSvgMainWin->m_pCanvas, SIGNAL(penChange()), this, SLOT(showLineParamsbar()));//属性栏选择性显示(void)connect(m_pSvgMainWin->m_pCanvas, SIGNAL(textChange()), this, SLOT(showTextParamsbar()));//属性栏选择性显示(void)connect(m_pSvgMainWin->m_pCanvas, SIGNAL(paramChange()), this, SLOT(showParamsbar()));//属性栏选择性显示}
4. 重写滚轮事件
通过重写滚轮事件,设置图形和画布的缩放。
void KSvgMainWindow::wheelEvent(QWheelEvent* event){KGlobalData::KDrawFlag flag = KGlobalData::getGlobalDataIntance()->getDrawFlag();qreal scale = KGlobalData::getGlobalDataIntance()->getCanvasScale();if (flag != KGlobalData::KDrawFlag::ZoomFlag){return;}if (event->delta() > 0) //若delta大于0,则表示滚轮向前(远离用户的方向),小于零则表明向后{scale += 0.05;int width = KGlobalData::getGlobalDataIntance()->getCanvasWidth();int height = KGlobalData::getGlobalDataIntance()->getCanvasHeight();m_pCanvas->resize(width * scale, height * scale);KGlobalData::getGlobalDataIntance()->setCanvasScale(scale);}else{scale -= 0.05;if (scale < 0.05)return;int width = KGlobalData::getGlobalDataIntance()->getCanvasWidth();int height = KGlobalData::getGlobalDataIntance()->getCanvasHeight();m_pCanvas->resize(width * scale, height * scale);KGlobalData::getGlobalDataIntance()->setCanvasScale(scale);}QScrollArea::wheelEvent(event);emit changeScale(scale);}
5. 删除图形
void KSvgMainWindow::keyPressEvent(QKeyEvent* event){if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ){for (QList<KShape*>::iterator it = m_pCanvas->m_pShapeList->begin(); it != m_pCanvas->m_pShapeList->end(); it++){if ((*it)->getShapeRect().contains(m_pCanvas->m_lastPos)){m_pCanvas->m_pShapeList->erase(it);break;}}}update();}
6. 单例模式析构,及QShapeList析构
单例模式析构,采取了嵌套类方式,自动释放堆区内存。
class KGlobalData{public:class KAutoDestory{public:KAutoDestory() {}~KAutoDestory(){if (s_globalDataObj != NULL){delete s_globalDataObj;s_globalDataObj = NULL;}}};static KGlobalData* getGlobalDataIntance();private:static KGlobalData* s_globalDataObj;static KAutoDestory m_autoDestory;};
#include "kglobaldata.h"KGlobalData* KGlobalData::s_globalDataObj = NULL;KGlobalData::KAutoDestory KGlobalData::m_autoDestory;
QShapeList析构
不只要释放QShapeList本身,还要释放其内部存储的数据(new 的各种图形)。
KSvgCanvas::~KSvgCanvas(){if (m_pShapeList != NULL){for (QList<KShape*>::iterator it = m_pShapeList->begin(); it != m_pShapeList->end(); it++){delete(*it);}}delete m_pShapeList;m_pShapeList = NULL;}
