使用QT绘制一个多边形
目录
1. 概述
可以通过QT的重绘事件和鼠标事件来绘制多边形,最简单的办法就是在继承QWidget的窗体中重写paintEvent、mousePressEvent等事件处理函数。QT提供了图形绘制接口QPainter,通过该接口可以绘制多种图形,包括多边形。
2. 实现
2.1. 代码
新建一个基于QWidget的QT界面类GraphicsPainter,将其放置到想要显示的窗体中。该类的具体代码:
GraphicsPainter.h:
#ifndef GRAPHICSPAINTER_H #define GRAPHICSPAINTER_H #include <QWidget> class GraphicsPainter : public QWidget { Q_OBJECT public: explicit GraphicsPainter(QWidget *parent = nullptr); void SetDraw(bool bDraw); signals: void singalDrawOver(); public slots: protected: void paintEvent(QPaintEvent *); //绘制 void mousePressEvent(QMouseEvent *e); //按下 void mouseMoveEvent(QMouseEvent *e); //移动 void mouseReleaseEvent(QMouseEvent *e); //松开 void mouseDoubleClickEvent(QMouseEvent *event); //双击 bool bDraw; //是否处于绘制状态 bool bLeftClick; //是否已经开始左键点击,同时标识是否开始进行绘制 bool bMove; //是否处于绘制时的鼠标移动状态 QVector<QPointF> pointList; QPointF movePoint; }; #endif // GRAPHICSPAINTER_H
GraphicsPainter.cpp:
#include "graphicspainter.h" #include <QPainter> #include <QMouseEvent> #include <QDebug> GraphicsPainter::GraphicsPainter(QWidget *parent) : QWidget(parent) { //填充背景色 setAutoFillBackground(true); setBackgroundRole(QPalette::Base); bDraw = false; bLeftClick = false; bMove = false; setMouseTracking(true); } void GraphicsPainter::SetDraw(bool bDraw) { this->bDraw = bDraw; pointList.clear(); } //重新实现paintEvent void GraphicsPainter::paintEvent(QPaintEvent *) { QPainter painter(this); if(bDraw) { painter.setPen(QColor(255,0,0)); QVector<QLineF> lines; for(int i = 0; i<pointList.size()-1; i++) { QLineF line(QPointF(pointList[i].x(), pointList[i].y()), QPointF(pointList[i+1].x(), pointList[i+1].y())); lines.push_back(line); } if(bMove&&pointList.size()>0) { QLineF line(QPointF(pointList[pointList.size()-1].x(), pointList[pointList.size()-1].y()), movePoint); lines.push_back(line); } painter.drawLines(lines); } } //按下 void GraphicsPainter::mousePressEvent(QMouseEvent *e) { if(bDraw) { if(!bLeftClick) { pointList.clear(); bLeftClick = true; } } //qDebug()<<"Press"; } //移动 void GraphicsPainter::mouseMoveEvent(QMouseEvent *e) { if(bDraw&&bLeftClick) { movePoint = e->pos(); bMove = true; this->update(); } //qDebug()<<"Move"; } //松开 void GraphicsPainter::mouseReleaseEvent(QMouseEvent *e) { if(bDraw&&bLeftClick) { pointList.push_back(QPointF(e->x(), e->y())); bMove = false; this->update(); } //qDebug()<<"Release"; } //双击 void GraphicsPainter::mouseDoubleClickEvent(QMouseEvent *event) { if(bDraw) { bLeftClick = false; pointList.push_back(pointList[0]); this->update(); singalDrawOver(); } //qDebug()<<"DoubleClick"; }
2.2. 解析
在重新实现的重绘事件中,通过QPainter绘制了一系列线组成线串,最后会首尾相连形成多边形。这里的bMove标识是否处于绘制时的鼠标移动状态,只有鼠标左键点击后才会确定为真正的节点:
//重新实现paintEvent void GraphicsPainter::paintEvent(QPaintEvent *) { QPainter painter(this); if(bDraw) { painter.setPen(QColor(255,0,0)); QVector<QLineF> lines; for(int i = 0; i<pointList.size()-1; i++) { QLineF line(QPointF(pointList[i].x(), pointList[i].y()), QPointF(pointList[i+1].x(), pointList[i+1].y())); lines.push_back(line); } if(bMove&&pointList.size()>0) { QLineF line(QPointF(pointList[pointList.size()-1].x(), pointList[pointList.size()-1].y()), movePoint); lines.push_back(line); } painter.drawLines(lines); } }
鼠标按下事件中,主要是通过bLeftClick值来确定是否已经处于左键点击状态,同时还能标识是否开始进行绘制。一旦开始,就会把上次绘制的节点清除。
//按下 void GraphicsPainter::mousePressEvent(QMouseEvent *e) { if(bDraw) { if(!bLeftClick) { pointList.clear(); bLeftClick = true; } } //qDebug()<<"Press"; }
一旦鼠标松开,就可以确定一个节点,此时需要调用update()进行重绘:
//松开 void GraphicsPainter::mouseReleaseEvent(QMouseEvent *e) { if(bDraw&&bLeftClick) { pointList.push_back(QPointF(e->x(), e->y())); bMove = false; this->update(); } //qDebug()<<"Release"; }
当开始进行绘制后,移动鼠标就会处于绘制时的鼠标移动状态,这时就会确定bMove为true,重绘事件就会将该鼠标点绘制出来,从而达到待选节点的效果:
//移动 void GraphicsPainter::mouseMoveEvent(QMouseEvent *e) { if(bDraw&&bLeftClick) { movePoint = e->pos(); bMove = true; this->update(); } //qDebug()<<"Move"; }
鼠标双击后,将第一个点加入到当前多边形的节点中后,达到首尾相连的效果,此时就会结束绘制:
//双击 void GraphicsPainter::mouseDoubleClickEvent(QMouseEvent *event) { if(bDraw) { bLeftClick = false; pointList.push_back(pointList[0]); this->update(); singalDrawOver(); } //qDebug()<<"DoubleClick"; }
这里一定要注意,当进行双击操作时,首先会触发一次mousePressEvent,然后触发一次mouseReleaseEvent,接着才会触发一次mouseDoubleClickEvent,最后还会触发一次mouseReleaseEvent。所以这就是这里设置bLeftClick这个参数原因:当触发mouseDoubleClickEvent后,bLeftClick设置为false,第二次触发mouseReleaseEvent时内部就不会在做任何操作了。
3. 结果
最终运行的结果如下所示:
分类: QT