使用QT绘制一个多边形

news2024/10/7 14:31:37

目录

  • 1. 概述
  • 2. 实现2.1. 代码2.2. 解析
  • 3. 结果

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

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

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开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

易基因|脂多糖诱导的仔猪肝脏损伤模型中m6A RNA甲基化介导了NOD1/NF-kB信号激活

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 2022年9月30日&#xff0c;南京农业大学动物科技学院钟翔教授团队在《ANTIOXIDANTS-BASEL》杂志发表题为“m6A RNA Methylation Mediates NOD1/NF-kB Signaling Activation in the Liver…

AlmaLinux 9上安装Kubernetes 1.25集群

AlmaLinux 9上安装Kubernetes 1.25集群 0. 确认Linux版本 uname -a1. 禁用swap sudo swapoff -a2. 禁用防火墙 sudo systemctl stop firewalld sudo systemctl disable firewalld3. 将SELinux设置为permissive模式 sudo setenforce 0 sudo sed -i s/^SELINUXenforcing$/SE…

Postgres 史上最垃圾的高可用软件之 - CLup

1. Clup 简介 CLup最大的特色功能是高可用。目前已存在几个开源的高可用软件: keepalived: 是一个较简单的高可用软件&#xff0c;其最早是于用LVS负载均衡软件&#xff0c;现在也常常用于ngnix的高可用&#xff0c;也可以用于数据库领域&#xff0c;但需要自己定制切换脚本才…

Oracle 11g DataGuard 搭建笔记(Windows Server 2016)

0.目录 目录 0.目录 1.需求 2.开发环境 3.DataGuard主从库参数环境规划 4.网络环境 5.主库-DataGuard配置 5.1查询及启用强制记录日志 5.3查询及启用归档 5.4主库参数配置 5.4.1查看db_unique_name及修改 5.4.2修改参数log_archive_config 5.4.3修改参数log_archive_dest_1 5.4…

部署前端报错404 hash 以及history模式下面前端、后端如何配置

问题描述&#xff1a;前端 本地页面 正常展示 、部署后刷新浏览器如上&#xff1a; vue-router&#xff08;前端路由&#xff09;有两种模式&#xff0c;hash模式和history模式 原理的区别&#xff08;原理&#xff09; 1、hash ——即地址栏URL中的#符号。 hash 虽然出现URL…

Sealos 安装报错问题解决

sealos 是以 kubernetes 为内核的云操作系统发行版,看其他人通过sealos安装k8s集群十分丝滑,但自己实践的时候为什么报错频繁呢? 官网介绍: sealos.io1 先决条件 每个集群节点应该有不同的主机名。 主机名不要带下划线。所有节点的时间同步。在 Kubernetes 集群的第一个节点…

数组中出现次数超过一半的数字、替换空格、重建二叉树

1、数组中出现次数超过一半的数字 本题考点&#xff1a; 数组使用&#xff0c;简单算法的设计 牛客链接 题目描述&#xff1a; 给一个长度为 n 的数组&#xff0c;数组中有一个数字出现的次数超过数组长度的一半&#xff0c;请找出这个数字。 例如输入一个长度为9的数组[1,2,…

企业如何利用 Serverless 快速扩展业务系统?

2022 年 9 月 24 日&#xff0c;阿里云用户组&#xff08;AUG&#xff09;第 12 期活动在厦门举办。活动现场&#xff0c;阿里云高级技术专家史明伟&#xff08;花名&#xff1a;世如&#xff09;向参会企业代表分享了《未来已来——从技术升级到降本提效》。本文根据演讲内容整…

引擎入门 | Unity UI简介–第1部分(8)

本期我们继续为大家进行Unity UI简介&#xff08;第一部分&#xff09;的后续教程 本篇内容 17.9-Slice缩放 18.准备按钮图像 19.设置按钮图像 20.为按钮设置自定义字体 文章末尾可免费获取教程源代码 本篇Unity UI简介&#xff08;第一部分&#xff09;篇幅较长&#x…

Spring源码深度解析:八、bean的获取② - getSingleton

一、前言 文章目录&#xff1a;Spring源码分析&#xff1a;文章目录 在Spring源码分析七 &#xff1a;bean的加载① - doGetBean 文章中&#xff0c;我们介绍了Spring对获取bean的过程&#xff0c;但是并没有详细解释Bean是如何创建的&#xff0c;本文就来分析Spring是如何创…

Mybatis 源码分析

mybatis 的一些总结 XMLConfigBuilder mybatis 的配置文件解析的能力是交给了XMLCconfigBuilder 去解析的 public SqlSessionFactory build(Reader reader, String environment, Properties properties) {try {XMLConfigBuilder parser new XMLConfigBuilder(reader, envir…

JDK内置命令工具

JDK内置命令工具 jps 作用 查看java进程的pid和全路径主类名和jvm参数 使用 -l : 输出所有正在运行java进程的pid 和主类名-v &#xff1a;输出正在运行java进程的pid和主类名和运行参数 jstack 作用 查看某个java进程当前的堆栈信息&#xff0c; 也就是当前进程中的线程…

NIO与BIO服务器端对比

本文利用NIO实现一个重复回复&#xff0c;客户端发送什么信息&#xff0c;客户端就会收到什么信息。 主要是理解NIO与BIO的区别。客户端采用telnet进行测试&#xff0c;以下连接是Telnet安装的方法。 Telnet的简单使用_武汉小喽啰的博客-CSDN博客_telnet 注意&#xff01;&a…

POSIX信号量

文章目录概念信号量函数基于环形队列的生产消费模型概念 信号量是一个计数器&#xff0c;用来描述临界资源数量的计数器。 每个执行流要进入临界资源时&#xff0c;要先申请信号量&#xff0c;出临界资源时&#xff0c;要释放信号量。 信号量的PV操作 P操作&#xff1a;申请…

万字长文总结分布式事务,总有一款适合你

导语&#xff1a;本文参考网络相关文章&#xff0c;主要总结了XA, 2PC, 3PC, 本地事务状态表, 可靠消息队列, 最大努力通知, TCC, SAGA等分布式事务的特点和适用场景&#xff0c;为大家选择分布式事务提供一些参考。 概述 分布式事务是指事务的参与者、支持事务的服务器、资源…

宝刀未老!阿里P8老兵耗时三年总结出这份Java项目实战文档

文档特点&#xff1a; 为了方便小伙伴们能更好地阅读&#xff0c;我已经提前给大家整理好了学习路线和知识结构 本书综合讲解Java程序设计中的核心技术&#xff0c;全书一共设计为22章&#xff0c;章节结构如下。 需要获取的小伙伴可以直接转发关注后私信&#xff08;学习&…

[Python]Django 配置

文章目录&#x1f349; pycharm中打开Django项目并配置虚拟环境运行项目&#x1f348; 打开项目后pycharm自动识别配置项目运行环境&#x1f34d; 指定项目运行的端口号&#x1f348; 自行配置项目的运行环境&#x1f34d; 配置项目的python解释器&#x1f34d; 配置Django项目…

本地demo服务器搭建计划——(三)rabbitmq配置中心config配置自动刷新

本章内容主要使用Spring Cloud Config来启动一个配置中心服务&#xff0c;通过Spring Cloud Bus消息总线&#xff08;依赖rabbitmq&#xff09;和Git仓库&#xff08;Gitee&#xff09;Webhook钩子函数来实现配置的自动更新&#xff08;push新的配置到gitee仓库时触发&#xff…

【英语口语】单词如何正确发音?

1. 发音基础介绍 音素&#xff1a;元音 辅音 单词&#xff1a;重音 失去爆破 浊化 三单 过去式过去分词 句子&#xff1a;语调 重音 弱读 连读 缩读 段落&#xff1a;意群 元音字母&#xff1a; A、E、I、O、U 2. 音节的定义 英语单词在发音的时候&#xff0c;不是一个字…

GD32F4(9):GD32f4出现上电不工作,必须按复位程序才能跑起来

GD32&#xff1a;上电不工作&#xff0c;需要按一下复位按键程序才能跑起来 文章目录GD32&#xff1a;上电不工作&#xff0c;需要按一下复位按键程序才能跑起来1.问题描述2. 我的调试思路2.1 第一步&#xff0c;排除电源问题2.2 第二步&#xff0c;排除复位电路的问题2.3 第三…