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绘制一个多边形的更多相关文章

  1. IOS 中openGL使用教程2(openGL ES 入门篇 | 绘制一个多边形)

    在上一篇我们学习了如何搭建IOS下openGL的开发环境,接下来我们来学习如何绘制一个多边形. 在2.0之前,es的渲染采用的是固定管线,何为固定管线,就是一套固定的模板流程,局部坐标变换 -> ...

  2. iOS-----openGL--openGL ES iOS 入门篇2--->绘制一个多边形

    在上一篇我们学习了如何搭建IOS下openGL的开发环境,接下来我们来学习如何绘制一个多边形. 在2.0之前,es的渲染采用的是固定管线,何为固定管线,就是一套固定的模板流程,局部坐标变换 -> ...

  3. Qt使用一个事件队列对所有发出的事件进行维护(QObject的event()函数相当于dispatch函数),用EventLabel 继承QLabel作为例子(简单明了) good

    事件(event)是由系统或者 Qt 本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事 ...

  4. MFC 用gdi绘制填充多边形区域

    MFC 用gdi绘制填充多边形区域 这里的代码是实现一个三角形的绘制,并用刷子填充颜色 在OnPaint()函数里面 运用的是给定的三角形的三个点,很多个点可以绘制多边形 CBrush br(RGB( ...

  5. Opentk教程系列-1绘制一个三角形

    本系列教程翻译自Neo Kabuto's Blog.已经取得作者授权. 本文原文地址http://neokabuto.blogspot.com/2013/02/opentk-tutorial-1-op ...

  6. OpenTK教程-1绘制一个三角形

    OpenTK的官方文档是真心的少,他们把怎么去安装OpenTK说的很清楚,但是也就仅限于此,这有一篇learn opentk in 15的教程(链接已经失效,译者注),但是并不完美.你可以在15分钟内 ...

  7. Qt 学习之路 2(24):Qt 绘制系统简介

    Qt 学习之路 2(24):Qt 绘制系统简介 豆子 2012年10月30日 Qt 学习之路 2 77条评论 Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于Q ...

  8. [原译]WPF绘制圆角多边形

    原文:[原译]WPF绘制圆角多边形 介绍 最近,我发现我需要个圆角多边形.而且是需要在运行时从用户界面来绘制.WPF有多边形.但是不支持圆角.我搜索了一下.也没找到可行的现成例子.于是就自己做吧.本文 ...

  9. Qt 模拟一个导航定位系统

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://www.cnblogs.com/lihuidashen/p/115397 ...

随机推荐

  1. String Distance and Transform Process

    http://acm.hdu.edu.cn/showproblem.php?pid=1516 Problem Description String Distance is a non-negative ...

  2. spring cloud解决eureka的client注册时默认使用hostname而不是ip

    eureka的client注册到server时默认是使用hostname而不是ip.这样的话使用feign client通过eureka进行服务间相互调用时也会使用hostname进行调用,从而调用失 ...

  3. 变得“不正经”的CES,竟然越来越好玩了

    在所有科技界的展会中,国人最熟悉的当属CES.作为科技行业的风向指示标,CES一直在扮演着重要的潮流指引者角色.不过,现在的CES似乎变得越来越"不正经"了!原本CES是国际消费类 ...

  4. Web Service概述 及 应用案例

    Web Service的定义  W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计.Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用 ...

  5. Xen入门系列三【Xen 管理工具 xm】

    xm命令是管理Xen的最基本的工具,可以通过xm --help 来获得帮助. 1. 列出所有正在运行的虚拟操作系统 # xm list PS[1]:可缩写为 xm li 2. 启动虚拟机 # 通过配置 ...

  6. sql server 数据库连接方式分析、详解

    本文链接:https://blog.csdn.net/wang379275614/article/details/7859398 一.OLEDB方式连接Sql身份验证模式:Provider=" ...

  7. 蓝桥杯-PREV3-带分数

    有人管蓝桥杯叫暴力杯,现在感觉还是挺贴切的.看到这题首先想到让i从1到n循环,首先判断i中无重复数字,再怎样判断能否用剩下的数构成n - i的假分数.之后看了题解.发现思路错了. 总结两点: 1.蓝桥 ...

  8. ArrayList查找和添加元素问题

    问题描述: 如上图所示,如果依靠迭代器在List中查找元素并添加元素,会报错:java.util.ConcurrentModificationException原因是在添加元素后,List本身发生了变 ...

  9. 数据库中慎用float数据类型(转载)

    数据库中慎用float数据类型   大多数编程语言都支持float或者double的数据类型.而数据库中也有相同关键字的数据类型,因此很多开发人员也自然而然地在需要浮点数的地方使用float作为字段类 ...

  10. TCP并发、GIL全局锁、多线程讨论

    TCP实现并发 #client客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while T ...