Draw a polygon using QT

Catalog

1. overview

You can draw polygons through QT redraw events and mouse events. The easiest way is to rewrite event handling functions such as paintEvent and mousePressEvent in the form that inherits QWidget. QT provides a graphics drawing interface QPainter, through which you can draw a variety of graphics, including polygons.

2. implementation

2.1. code

Create a new QT interface class GraphicsPainter based on QWidget and place it in the form you want to display. Specific code of this class:

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 *);     //Draw
    void mousePressEvent(QMouseEvent *e);       //Press down
    void mouseMoveEvent(QMouseEvent *e);        //move
    void mouseReleaseEvent(QMouseEvent *e);     //Release
    void mouseDoubleClickEvent(QMouseEvent *event);        //double-click


    bool bDraw;             //Whether it is in drawing state
    bool bLeftClick;            //Whether to start left click and mark whether to start drawing
    bool bMove;             //Whether it is in the mouse movement state when drawing

    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)
{
    //Fill background color
    setAutoFillBackground(true);
    setBackgroundRole(QPalette::Base);

    bDraw = false;
    bLeftClick = false;
    bMove = false;
    setMouseTracking(true);
}

void GraphicsPainter::SetDraw(bool bDraw)
{
    this->bDraw = bDraw;
    pointList.clear();
}

//Re implement 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);
    }
}

//Press down
void GraphicsPainter::mousePressEvent(QMouseEvent *e)
{
    if(bDraw)
    {
        if(!bLeftClick)
        {
            pointList.clear();
            bLeftClick = true;
        }
    }
    //qDebug()<<"Press";
}

//move
void GraphicsPainter::mouseMoveEvent(QMouseEvent *e)
{
    if(bDraw&&bLeftClick)
    {
        movePoint = e->pos();
        bMove = true;
        this->update();
    }
    //qDebug()<<"Move";
}

//Release
void GraphicsPainter::mouseReleaseEvent(QMouseEvent *e)
{
    if(bDraw&&bLeftClick)
    {
        pointList.push_back(QPointF(e->x(), e->y()));
        bMove = false;
        this->update();
    }
    //qDebug()<<"Release";
}

//double-click
void GraphicsPainter::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(bDraw)
    {
        bLeftClick = false;
        pointList.push_back(pointList[0]);
        this->update();
        singalDrawOver();
    }
    //qDebug()<<"DoubleClick";
}

2.2. analysis

In the re implementation of the redraw event, a series of lines are drawn through QPainter to form a string of lines, and finally a polygon will be formed end to end. The bMove flag here indicates whether it is in the mouse movement state when drawing. Only when the left mouse button is clicked can it be determined as a real node:

//Re implement 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);
    }
}

In the mouse down event, the left click value is mainly used to determine whether the mouse has been in the left click state, and also to identify whether to start drawing. Once started, the last painted node is cleared.

//Press down
void GraphicsPainter::mousePressEvent(QMouseEvent *e)
{
    if(bDraw)
    {
        if(!bLeftClick)
        {
            pointList.clear();
            bLeftClick = true;
        }
    }
    //qDebug()<<"Press";
}

Once you release the mouse, you can determine a node. At this time, you need to call update() to redraw:

//Release
void GraphicsPainter::mouseReleaseEvent(QMouseEvent *e)
{
    if(bDraw&&bLeftClick)
    {
        pointList.push_back(QPointF(e->x(), e->y()));
        bMove = false;
        this->update();
    }
    //qDebug()<<"Release";
}

When painting is started, the mouse will be in the mouse moving state when painting, and bMove will be determined to be true. The redraw event will draw the mouse point, so as to achieve the effect of the node to be selected:

//move
void GraphicsPainter::mouseMoveEvent(QMouseEvent *e)
{
    if(bDraw&&bLeftClick)
    {
        movePoint = e->pos();
        bMove = true;
        this->update();
    }
    //qDebug()<<"Move";
}

After double clicking, add the first point to the current polygon's node to achieve the end-to-end effect, and the drawing will end:

//double-click
void GraphicsPainter::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(bDraw)
    {
        bLeftClick = false;
        pointList.push_back(pointList[0]);
        this->update();
        singalDrawOver();
    }
    //qDebug()<<"DoubleClick";
}

It must be noted here that when double clicking, a mousePressEvent will be triggered first, then a mouserelease event, then a mouseDoubleClickEvent, and finally a mouserelease event. So that's why the parameter bLeftClick is set here: when mouseDoubleClickEvent is triggered, bLeftClick is set to false. When mouserelease event is triggered for the second time, no internal operation will be done.

3. results

The results of the final run are as follows:

Code address

Tags: C++ Qt

Posted on Thu, 05 Mar 2020 23:51:47 -0800 by woody79