使用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. 结果
最终运行的结果如下所示: