首页 > 其他分享 >Qt实现画图板

Qt实现画图板

时间:2024-08-23 14:38:58浏览次数:9  
标签:Qt 实现 曲线 贝塞尔 CustomItem 画图板 散点 newPoint 鼠标

Qt实现画板

基于QGraphicsView实现绘画曲线注意点_qgraphicsview绘制曲线图-CSDN博客

Qt桌面白板工具其一(解决曲线不平滑的问题——贝塞尔曲线)_qt贝塞尔曲线-CSDN博客

先实现一个最简单的不考虑任何优化的曲线画板

我们知道鼠标移动时,会在其移动轨迹上留下一系列的点,我们可以将这些点用直线连起来的方式,实现曲线的绘画。

虽然说这样子连起来的曲线在鼠标移动过快的情况下会出现不平滑的现象,但现在我们主要是把能绘画的程序做出来,而非将其做成很好的地步。毕竟万事开头难,这里主要是为了让我们对如何搭建绘画曲线的程序有一个初步的认知。

我们可以让QGraphicsScene​通过处理鼠标事件,然后为我们收集到关于这条曲线的一组散点,然后交给自定义的Item,对这组散点进行模拟绘画。

关于散点的处理,可以是简单地将这些散点用直线连接起来,也可以是经过数值分析之后,使用插值或者其他数值分析方法得出来的模拟图。

我们这里只讨论最简单的处理方式,也就是简单地将散点连接起来,然后进行绘制。

最终取得的结果如下:

最终的绘画结果大概是这样的,虽然能够将曲线绘画出来,但是缺少了平滑性,这远远没有达到我的预期。画直线还好,一旦散点不再是单纯的直线,那么就会出现线不连续,这种现象一般是不现实的,我们更进一步的目的是优化使用这些散点进行绘图的算法,这需要使用到数值分析之类的知识。

void CustomItem::pointMove(const QPointF& newPoint)
{
    maxX = newPoint.x() > maxX? newPoint.x() : maxX;
    minX = newPoint.x() < minX? newPoint.x() : minX;
    maxY = newPoint.y() > maxY? newPoint.y() : maxY;
    minY = newPoint.y() < minY? newPoint.y() : minY;
    points.append(newPoint);
    scene()->update();
}

CustomItem所在的场景需要通过检测鼠标移动事件,将轨迹散点交给CustomItem。

然后CustomItem在paint()中使用这些记录好的散点进行绘图操作。一旦场景的移动事件完毕,这个CustomItem的形状就固定了。

void CustomItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    if (points.size() == 1) {
        painter->drawPoint(points.front());
    }
    else {
        auto lastPoint = points.begin();
        for (auto newPoint = ++lastPoint; newPoint != points.end(); lastPoint = newPoint, ++newPoint) {
            painter->drawLine(*lastPoint, *newPoint);
        }
    }
}

具体的草稿代码可以查看:Aderversa/SimpleDrawCurves (github.com)

贝塞尔曲线学习

这里博主学习了其他人的博客:贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现-CSDN博客

如何将贝塞尔曲线的算法应用到画板中?

我们前面已经通过检测鼠标事件,收集到一堆的点。假设这些点有N个,那么贝塞尔曲线如何利用这些点呢?

  1. 程序推导出N-1阶贝塞尔曲线的公式,然后利用这个公式将曲线的所有点都画出来。

暂时只想出这种方法,但是如果程序需要自己推导这个公式其算法的复杂度将会是很高的,并且我们Qt不像Python那样有numpy来辅助你来完成这些数值分析工作。所以这种方法被我否决了。

我们能不能只利用二阶或者三阶的贝赛尔曲线公式来解决?如果可以,需要怎样做?

他人的解决方案

这里参考了别人的一篇文章:Qt桌面白板工具其一(解决曲线不平滑的问题——贝塞尔曲线)_qt贝塞尔曲线-CSDN博客

这里面主要描述了画板的两种实现方法:

(1)第一种是利用GraphicsView框架,通过采集点然后点间连线的方式形成图形项呈现在屏幕上。

但是这样做有一个问题,当我们要实现“橡皮擦”功能时,情况将会变得异常复杂,因为我们橡皮擦所过之处,会碰到一些图元如果是通过点来绘制的,那么他需要看看自己内部的点集合有没有与橡皮擦相交,如果点非常多,那么每次擦除都需要进行很大开销的查找操作。

(2)利用QImage间接绘制窗口

通过重写QWidget的paintEvent(),将鼠标事件映射到QImage中。这样其实是考虑了撤销的问题,撤销需要记录上一步的画面,与其记住繁杂的路径点位,不如直接记住上一次的QImage,并且限定10次。

这里文章的博主采用了第二种解决方案。我们暂且不论刚开始我们所做东西的优劣,这里应关注的是他如何使用贝塞尔曲线:

假设我们在鼠标移动的过程中有A、B、C、D、E、F、G这6个点。如何画出平滑的曲线呢?

我们取B点和C点的中点为B1。

作为第一条贝塞尔曲线的终点,B点为控制点:

接下来,算出C和D的终点C1,以C点为控制点,继续绘制:

当我们荣有一系列的点集时,从第二个点开始,该点和下一个点之间计算一个新的中点(直接相加除以2),然后添加进点集队列中。

这样,我们除了第一个点之外的其他实际点,都将作为控制点成为参数,而第一个点和我们手动计算出的中点,反而成为实际点与曲线相连。

制作好这个点集之后呢?该怎样绘制贝塞尔曲线,看不到代码实现我还是没有理解。

代码实现

直接把该文章的算法drawBezier()​移植过来用,最终效果如上所示。感觉没那么尖锐了,但仍然存在不足,通过调整QPen的Style可能有一定程度上的缓解。

标签:Qt,实现,曲线,贝塞尔,CustomItem,画图板,散点,newPoint,鼠标
From: https://www.cnblogs.com/Aderversa/p/18375933

相关文章

  • Go实现一个五子棋功能
    参考https://juejin.cn/post/6847902215575699464packagemainimport( "fmt" "math/rand" "strconv" "strings" "time")typehanduintconst( NilHandhand=iota//空白 BlackHand//黑手 Wh......
  • 【Qt】Qt窗口 | QDialog 对话框
    文章目录一.对话框二.对话框的分类1.非模态对话框2.模态对话框3.混合属性对话框三.自定义对话框1.代码实现2.ui文件实现四.内置对话框1.QMessageBox消息对话框2.QColorDialog颜色对话框3.QFileDialog文件对话框4.QFontDialog字体对话框5.QInputDialo......
  • 利用Spring Boot实现微服务的API网关统一认证
    利用SpringBoot实现微服务的API网关统一认证大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在微服务架构中,API网关是服务对外的统一入口,它负责请求路由、负载均衡、认证授权等。统一认证是确保只有合法用户才能访问服务的关键环节。SpringBoot结合......
  • java+vue计算机毕设建筑项目管理系统的设计与实现【源码+开题+论文】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着建筑行业的快速发展,项目管理的复杂性和规模性日益凸显。传统的手工或基于简单软件的项目管理方式已难以满足现代建筑企业高效、精准、透明的管理......
  • 分享一个基于ChatGPT实现基于Convars布局思路的实现过程
    一、思路在AI的大背景,应用层算法已经不是问题,那么程序员的差距主要在认知思维模式和创新上面。目前AI的局限主要却决于沟通的效率,这是双方的问题,AI可能理解能力不足,或者提问者表达能力不足。这里我以PDFsharp实现Grid布局模式分享一下基于GPT实现的过程。因为PDFsharp只提供了XG......
  • Qt5.14.2 多边形与多边形求交集
    利用Qt5.14.2中自带的QPolygonF类的intersected()函数求两个多边形的交集多边形。inlineQList<QPolygonF>getPolygonIntersectedWithPolygon(QPolygonFpolygon1,QPolygonFpolygon2){QList<QPolygonF>outval;//此处求出的intersection可能包含多个子......
  • springboot+vue高校疫情防控系统的设计与实现【程序+论文+开题】-计算机毕业设计
    系统程序文件列表开题报告内容研究背景近年来,全球公共卫生安全面临着前所未有的挑战,尤其是新冠疫情的爆发,对各行各业,尤其是教育领域产生了深远影响。高校作为人员密集、流动性大的场所,其疫情防控工作尤为重要且复杂。传统的人工管理方式已难以满足当前高效、精准、全面的疫......
  • java+vue计算机毕设流浪动物救助系统的设计与实现【源码+开题+论文】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景:随着城市化进程的加速,流浪动物问题日益凸显,成为社会各界关注的焦点。大量流浪动物不仅在城市中四处游荡,影响市容市貌,还可能携带病菌,对公共卫生安全构......
  • js 实现代码雨效果
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title&g......
  • 在Java中实现通过TCP方式发送和接收Socket消息,包含在多线程状态下的实现
    导言:公司的代码,本来客户端client是前端的unity发送请求的,后面自己写的时候需要在本地进行测试,所以也用Java实现了前端,就写出来记录一下。本文主要展示客户端client跟服务端server基础代码,里面的一些业务逻辑没有进行展示正文1.创建client端首先我们需要创建一个client端进......