欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用QT绘制一个多边形

程序员文章站 2022-03-25 17:52:02
QT绘制多边形的实例,通过这个实例学习了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绘制一个多边形