当前位置: 首页 > news >正文

Qt实现绘制自定义形状

先创建一个继承自QWidget的控件:

class MyPainterWidget:public QWidget

重写各种鼠标方法:

protected:void paintEvent(QPaintEvent *) override;void mousePressEvent(QMouseEvent *e) override;       //按下void mouseMoveEvent(QMouseEvent *e) override;        //移动void mouseReleaseEvent(QMouseEvent *e) override;     //松开void mouseDoubleClickEvent(QMouseEvent *event) override;

在构造函数中声明跟踪鼠标:

#include <QMouseEvent>
setMouseTracking(true);

定义两个标志位作为开始绘制和鼠标移动的标志:

bool m_bStartDraw = false;    //是否已经开始左键点击,同时标识是否开始进行绘制bool bMove = false;           //是否处于绘制时的鼠标移动状态

创建一个点集记录每次按下的坐标点:

QVector<QPointF> pointList;

在程序一开始的时候先清除点集:

MyPainterWidget::MyPainterWidget(QWidget *parent) : QWidget(parent)
{setMouseTracking(true);pointList.clear();
}

按下鼠标时将开始绘制标志位设为true:

// 按下
void MyPainterWidget::mousePressEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if(!m_bStartDraw){pointList.clear();m_bStartDraw = true;}}   
}

创建一个点用于获取鼠标移动时的当前位置:

QPointF movePoint;

重写移动事件:

// 移动
void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
{if(m_bStartDraw){movePoint = e->pos();this->update();//重新进入painEvent事件进行绘制// 先刷新再设为true, 防止第一点和(0,0)连在一块bMove = true;}
}

重写释放事件:

// 松开
void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if (m_bStartDraw){// 鼠标松开后的点需要添加到路径中pointList.push_back(QPointF(e->x(), e->y()));bMove = false;this->update();//刷新绘制}}
}

写一个表示结束绘制的功能函数:

void MyPainterWidget::endDraw()
{m_bStartDraw = false;//需要把第一个点连起来pointList.push_back(pointList[0]);this->update();
}

实现清除所有已绘的功能函数:

void MyPainterWidget::clearPath()
{pointList.clear();this->update();
}

主窗口:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QMenu>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();protected:// 右键菜单需要重写的类void contextMenuEvent(QContextMenuEvent* event) override;private:Ui::MainWindow *ui;QMenu* m_pMenu;
};
#endif // MAINWINDOW_H
/*使用方式左键点击,移动鼠标开始绘制,双击左键结束绘制,或者右键点击结束绘制*/#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMenu>
#include <QAction>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);m_pMenu = new QMenu(this);QAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);pAc1->setShortcut(QKeySequence("Ctrl+E"));QAction* pAc2 = new QAction(QString::fromLocal8Bit("清除"), this);pAc2->setShortcut(QKeySequence("Ctrl+D"));// 这是个假动作,为了让菜单消失,且不影响绘制路径QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);m_pMenu->addAction(pAc1);m_pMenu->addAction(pAc2);m_pMenu->addAction(pAc3);m_pMenu->setStyleSheet("QMenu{font:18px;}");connect(pAc1, &QAction::triggered, [=] {ui->graphicsPainter->endDraw();});connect(pAc2, &QAction::triggered, [=] {ui->graphicsPainter->clearPath();});
}MainWindow::~MainWindow()
{delete ui;
}// 右键菜单
void MainWindow::contextMenuEvent(QContextMenuEvent* event)
{m_pMenu->move(cursor().pos());m_pMenu->show();
}

完整代码:

#ifndef GRAPHICSPAINTER_H
#define GRAPHICSPAINTER_H#include <QWidget>class MyPainterWidget : public QWidget
{Q_OBJECTpublic:explicit MyPainterWidget(QWidget *parent = nullptr);void endDraw();void clearPath();protected:void paintEvent(QPaintEvent *) override;void mousePressEvent(QMouseEvent *e) override;       //按下void mouseMoveEvent(QMouseEvent *e) override;        //移动void mouseReleaseEvent(QMouseEvent *e) override;     //松开void mouseDoubleClickEvent(QMouseEvent *event) override;     //双击bool m_bStartDraw = false;    //是否已经开始左键点击,同时标识是否开始进行绘制bool bMove = false;           //是否处于绘制时的鼠标移动状态QVector<QPointF> pointList;QPointF movePoint;
};#endif // GRAPHICSPAINTER_H
#include "MyPainterWidget.h"
#include <QPainter>
#include <QMouseEvent>MyPainterWidget::MyPainterWidget(QWidget *parent) : QWidget(parent)
{setMouseTracking(true);pointList.clear();
}void MyPainterWidget::paintEvent(QPaintEvent *)
{QPainter painter(this);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 (m_bStartDraw){int size = pointList.size();if (bMove && size > 0){QLineF line(QPointF(pointList[pointList.size() - 1].x(), pointList[pointList.size() - 1].y()),movePoint);lines.push_back(line);}}painter.drawLines(lines);
}// 按下
void MyPainterWidget::mousePressEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if(!m_bStartDraw){pointList.clear();m_bStartDraw = true;}}   
}// 移动
void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
{if(m_bStartDraw){movePoint = e->pos();this->update();//重新进入painEvent事件进行绘制// 先刷新再设为true, 防止第一点和(0,0)连在一块bMove = true;}
}// 松开
void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){if (m_bStartDraw){// 鼠标松开后的点需要添加到路径中pointList.push_back(QPointF(e->x(), e->y()));bMove = false;this->update();//刷新绘制}}
}// 双击结束绘制
void MyPainterWidget::mouseDoubleClickEvent(QMouseEvent *event)
{endDraw();
}void MyPainterWidget::endDraw()
{m_bStartDraw = false;//需要把第一个点连起来pointList.push_back(pointList[0]);this->update();
}void MyPainterWidget::clearPath()
{pointList.clear();this->update();
}

相关文章:

  • 利用MATLAB进行矩阵运算(2)
  • 蓝牙运动耳机哪个好?蓝牙运动耳机排行榜前十名
  • 【Python3】【力扣题】349. 两个数组的交集
  • flink的集成测试
  • Redis-主从与哨兵架构
  • 孩子学习过程中一些代码记录
  • LLMLingua:集成LlamaIndex,对提示进行压缩,提供大语言模型的高效推理
  • RabbitMQ之发送者(生产者)可靠性
  • 【运维面试100问】(六)buffer和cache的区别
  • 在CentOS 7.9上搭建高性能的FastDFS+Nginx文件服务器集群并实现外部远程访问
  • 加载minio中存储的静态文件html,不显示样式与js
  • 基于51单片机超声波测距汽车避障系统
  • IBM X3650M4安装ESXI6.5卡在/lsl_mr3.v00
  • 泛型边界的问题
  • leetcode - 2232. Minimize Result by Adding Parentheses to Expression
  • SegmentFault for Android 3.0 发布
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Angular6错误 Service: No provider for Renderer2
  • bearychat的java client
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • JavaScript HTML DOM
  • php ci框架整合银盛支付
  • 关于for循环的简单归纳
  • 基于 Babel 的 npm 包最小化设置
  • 入门级的git使用指北
  • 通过git安装npm私有模块
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • ​520就是要宠粉,你的心头书我买单
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (2)MFC+openGL单文档框架glFrame
  • (20050108)又读《平凡的世界》
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (八十八)VFL语言初步 - 实现布局
  • (二)PySpark3:SparkSQL编程
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (转)JAVA中的堆栈
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET Core 版本不支持的问题
  • .NET Framework杂记
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET Remoting学习笔记(三)信道
  • .net 托管代码与非托管代码
  • .Net6使用WebSocket与前端进行通信
  • .NET处理HTTP请求
  • .NET业务框架的构建
  • @RestControllerAdvice异常统一处理类失效原因
  • [.net]官方水晶报表的使用以演示下载
  • [ActionScript][AS3]小小笔记
  • [codevs 1515]跳 【解题报告】
  • [EFI]DELL XPS13 9360电脑 Hackintosh 黑苹果efi引导文件
  • [IOI2007 D1T1]Miners 矿工配餐