Qt 鼠标/触屏绘制平滑曲线(支持矢量/非矢量方式)

前言

Qt通过鼠标或者触屏,实时绘制平滑曲线,通常有两种方式实现:矢量绘图和非矢量绘图,这两种画线方式从实现上有些不同,其原理也不太一样,稍后会做详细介绍。而鼠标或者触屏画线也不大一样,通常如果只实现鼠标画线的话,那么只需要重新实现鼠标事件即可(mousePressEvent、mouseMoveEvent、mouseReleaseEvent),而要在触控屏上画线,如果需要支持多点画线的话,就必须处理QTouchEvent事件才行,但是如果触屏上只支持单点画线,那也可以直接实现鼠标事件,因为第一个触点的事件会同时进入到QTouchEvent和Mouse事件中。QTouchEvent中可以区分出多点时每个触点的id,通过id进行区分每个点的数据。

通常情况下,为了提升绘图效率,要实现这种绘图的功能,都是用QGraphics体系来完成,因为QGraphics刷新机制和QWidget不太一样,它可以做区域刷新,这样能保证效率更高,特别是针对一些分辨率较高的设备,就很明显了。具体这两个体系间的区别就不在这里进行描述。

所以,接下来为了演示矢量和非矢量画图方式,我们在QGraphics体系中实现一个简单的画板程序。注重画线效率,保证线条平滑无折线,无锯齿,支持多点画线。

效果图

先开看看非矢量绘图的效果:

再看矢量绘图效果:

二者区别

通过上面的两个图对比,相信大家已经看出了一些区别。我们再详细介绍一下这两者的区别。

非矢量绘图

  • 优点:速度快。非矢量绘图原理是直接在一张图片上进行绘制,其渲染速度很快,即便是画了很多线条, 也不会有卡顿的效果,擦除时同样很快。
  • 缺点:缩放失真。由于非矢量绘图是在图片上渲染,当缩放图片时,会导致线条模糊不清晰,如果只是小范围的缩放还能接受,无限缩放的话就会很明显了。

矢量绘图

  • 优点:无限缩放,不失真。矢量绘图是将点数据绘制生成一个单独的对象,当进行缩放的时候,会重新进行渲染,所以矢量绘图的方式不会导致图像失真。
  • 缺点:线条多时会卡顿,擦除尤其明显。由于矢量绘图是生成一个单独的对象,所以当画线多的情况下,会触发所有有交集的对象进行刷新,擦除的时候,会去计算线条之间的交集并做删减,这个过程会很慢,并且会将整个对象item进行刷新,所以卡顿明显(上述效果图就可以看出来了)。

通过以上两者的优缺点对比,根据实际需要进行选择实际的画线模式。

解决实时绘图折线问题

折线效果:

可以看到上述画线有很明显的折线,线条不平滑。

通常绘制这种线条,第一反应想到的是讲两个点直接连接起来行成一条直线,但是,由于两点之间距离比较大,特别是触控屏,点与点之间并不是很密集,因为上层应用在主线程渲染的时候,系统会自动丢弃一些数据点,即便是底层上报的点很多,上层应用接收到的点也会减少,所以不能直接用连接两点的方式来实现。

那么,该怎么解决呢?
绘制贝塞尔曲线。

在move的过程中实时生成贝塞尔曲线path,这样就能保证线条无折线。QPainterPath支持贝塞尔曲线绘制,参加以下函数:

void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)

Adds a quadratic Bezier curve between the current position and the given endPoint with the control point specified by c.
After the curve is added, the current point is updated to be at the end point of the curve.

注意该函数,第一个参数是控制点,该点就是上一个触控点,而第二个参数是前一个点和当前点的中点,也就是两个点坐标加起来除以2.

非矢量绘图实现方式

所谓的非矢量绘图,就是在一张图片上进行绘制,然后将图片渲染到QGraphicsItem的背景上面,前面我们已经提到,该方式渲染速度非常快,无论画多少线条都不会影响速度,而擦除功能只需要按照同样的方式绘制背景色即可。

但是该方式在缩放过后图片会有些模糊,如果只是小范围的缩放还好,无限缩放就需要用到矢量绘图的方式了。

矢量绘图实现方式

相比之下,矢量绘图就会稍微麻烦一点,所谓矢量绘图,就是将path曲线直接生成一个独立的对象,将该对象添加到scene中,这种模式下会有一个缺陷,就是当画线较多的情况下,刷新会比较慢,因为会导致整条曲线(只要有交集)刷新,从而导致卡顿的效果,并且在擦除时,需要实时计算擦除的path与实际线条path的交集,然后进行计算,减去擦除的path,这个过程是最耗时的,并且也会引发整个item刷新。前面写过文章介绍QGraphics体系的刷新机制,在这里

由于矢量绘图需要生成一条完整的path进行绘制,而触控点是在move事件中取到,如果实时生成贝塞尔曲线去绘制,那么当一直不松手的画一条线时,画到后面将会越来越慢,因为动态生成path后会重新将整条path进行渲染,随着线条越长,那么刷新区域就会越大,这就会导致刷新变慢而延迟变高。那么怎么解决这个问题呢?答案就是通过双缓冲的方式来实现绘制。

双缓冲绘图

上面介绍到,通过非矢量绘图的方式,速度会非常快,那么双缓冲绘图就是要结合非矢量来进行,其原理就是:在press事件中生成一条path,接着move中动态增加这条path,然后在临时层上进行非矢量绘图,这时候绘制的速度会非常快,最后在release事件中将完整的path绘制成矢量图,然后将临时层画线清空。基本原理就是这样。

双缓冲绘图方式,在绘制过程中是通过非矢量的方式在临时层进行,release后生成完整的矢量path,这种方式速度会非常快,并且直接绘制完整的一条path不会有锯齿。所以这是最佳选择。

代码太多,就不附代码了。

到此这篇关于Qt 鼠标/触屏绘制平滑曲线(支持矢量/非矢量方式)的文章就介绍到这了,更多相关Qt 绘制平滑曲线内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Qt图形图像开发之曲线图表模块QChart库坐标轴和数据不对应、密集的散点图无法显示问题解决方法

    QChart坐标轴和数据不对应问题描述: lineseries->append(4, 10); lineseries->append(5, 8); Chart->addSeries(lineseries); // 将 series 添加至图表中 axisX->setRange(0, 15);//设置X的显示范围 axisY->setRange(-20, 20); lineChart->setAxisX(axisX);//把轴添加到图表中 lineChart->se

  • Qt图形图像开发之曲线图表模块QChart库一个chart中显示两条曲线详细方法与实例

    首先要了解QChartView.QChart.QLineSeries.QValueAxis的实体之间的关系,例如一个QChartView中可以包含几个QValueAxis?这些可参考 Qt图形图像开发曲线图表模块QChart库基本用法.各个类之间的关系说明 每个chart可以包含多个QLineSeries数据系列,每个QLineSeries数据系列又包含了2个QValueAxis数值轴或QDateTimeAxis时间轴. 那么这个chart中的多个数据系列,一起显示在同一个chart中,会是什么

  • Qt图形图像开发之高性能曲线图模块QCustomplot库详细使用方法与实例(支持动、静曲线图)

    Qt曲线图模块QCustomPlot库介绍 QCustomPlot是一个小型的Qt画图标类,支持绘制静态曲线.动态曲线.多重坐标曲线,柱状图,蜡烛图等 前段时间用QChart模块画图,一条曲线上面放8000条数据就会卡的不行必须要换个其他的控件,后来找到了曲线图模块QCustomplot库 这个库性能非常好,画曲线图折线图柱状图动态静态,放大缩小,都很好用,10w条数据量无压力秒画出来一点也不卡 下载地址 https://www.qcustomplot.com/index.php/downloa

  • Qt图形图像开发之曲线图模块QCustomplot库生成静态、动态曲线详细教程图解

    Qt曲线图模块QCustomPlot库介绍 QCustomPlot是一个小型的Qt画图标类,支持绘制静态曲线.动态曲线.多重坐标曲线,柱状图,蜡烛图等.只需要在项目中加入头文件qcustomplot.h和qcustomplot.cpp文件,然后使一个widget提升为QCustomPlot类,即可使用. QCustomPlot官网:   http://www.qcustomplot.com/ QCustomPlot下载地址:   http://www.qcustomplot.com/index.

  • Qt图形图像开发之曲线图表库QtChart编译安装详细方法与使用实例

    Qt曲线图表库QtChart简介 Qt的线性绘图控件有大名鼎鼎的Qwt,ChartDirector,小巧玲珑的QCustomPlot,当然还有自家的QtChart.长久以来QtChart在Qt家族里一直是收费的模块,只有商业版才可以使用,但Qt5.7之后将开放其权限,可参见:Qt 5.7 亮瞎眼的更新.下面将介绍如何安装QtChart并进行简单的绘图. Qt曲线图表库QtChart下载 这里用git下载QtChart,参考Qt Charts 5.7.0 安装教程 Git地址:https://gi

  • Qt图形图像开发曲线图表模块QChart库缩放/平移详细方法与实例

    1.使用QChartView来缩放 (1)用鼠标框选一个矩形,把图放大到这个矩形 QChartView::setRubberBand(QChartView::RectangleRubberBand);//XY方向同时放大到鼠标画出的矩形大小(也可以设置为只放大X轴或Y轴) (2)setRubberBand函数同时也能使鼠标右键,具备缩小图的功能. 2.使用Qchart来平移和缩放 QChart::scroll(-10, 5);//整体平移(-10, 5),两个参数分别为Δx和Δy QChart:

  • Qt图形图像开发曲线图表模块QChart库基本用法、各个类之间的关系说明

    如何编译安装QChart请查看下面文章 Qt图形图像开发之曲线图表库QtChart编译安装详细方法与使用实例 使用Qt曲线图表模块Chart库首先要注意3点: (1)在.pro文件中添加:QT += charts. (2)用到QChart的文件中添加:QT_CHARTS_USE_NAMESPACE,或者:using namespace QtCharts; 在ui界面中拖入一个graphicsView控件,然后右击提升为QChartView类,写提升为的类:QtCharts::QChartView

  • Qt图形图像开发之曲线图表模块QChart库读取/设置X轴的显示区间

    设置初始的显示的区间,常用的有两种方法 (1)自动 lineseries = new QLineSeries();//声明折线数据集 lineseries->append(4, 10); //填充数据集 *lineseries << QPointF(13, 5) << QPointF(17, 6); lineChart = new QChart();//创建图表 lineChart->addSeries(lineseries); // 将 数据集 添加至图表中 line

  • Qt图形图像开发之Qt曲线图美化QChart QScatterSeries 空心点阵图,鼠标移动到上面显示数值,鼠标移开数值消失效果实例

    最近接到一个Qt QChart曲线图美化的需求,画一个折线图,关键点使用空心的圆点标识出来,鼠标移动到关键点上,显示出当前数值:鼠标移走数值消失. 效果图如下: 我们遇到这个需求的时候,第一时间就会想到使用 QLineSeries 画折线图. 首先初始化 QChart *chart = new QChart(); chart->legend()->setVisible(false); ui->chartView->setChart(chart); ui->chartView-

  • Qt 鼠标/触屏绘制平滑曲线(支持矢量/非矢量方式)

    前言 Qt通过鼠标或者触屏,实时绘制平滑曲线,通常有两种方式实现:矢量绘图和非矢量绘图,这两种画线方式从实现上有些不同,其原理也不太一样,稍后会做详细介绍.而鼠标或者触屏画线也不大一样,通常如果只实现鼠标画线的话,那么只需要重新实现鼠标事件即可(mousePressEvent.mouseMoveEvent.mouseReleaseEvent),而要在触控屏上画线,如果需要支持多点画线的话,就必须处理QTouchEvent事件才行,但是如果触屏上只支持单点画线,那也可以直接实现鼠标事件,因为第一个

  • Bootstrap幻灯片轮播图支持触屏左右手势滑动的实现方法

    最近ytkah在学习用bootstrap搭建网站,Bootstrap能自适应pc端和手机端,并且移动设备优先,适合现如今移动营销.bootstrap是封装好的框架,需要某些功能只需调用相应的组件就可以,但有些还是没加入,比如幻灯轮播触屏左右滑动手势就不支持,大家用的设备基本是触屏的了,能用滑动交互在小屏幕上体验会更好,那么如何实现呢?一个比较简单的方法是增加一个滑动手势js插件:hammer.js,网上有很多cdn调用地址,像//cdn.bootcss.com/hammer.js/2.0.8/h

  • Android触屏事件和MotionEvent详解

    Android屏幕操作 屏幕是用户和Android设备交互的主要媒介,屏幕分为触屏和非触屏.Android设备目前有四种类型:Android Phone,Android Tablet,Android Wear和Android TV.Android TV大都使用非触屏,其他三类设备则大都使用触屏.对非触屏设备,用户可以通过键盘鼠标或遥控器在屏幕上操作.对触屏设备,用户主要通过手指或触控笔等工具在屏幕上操作,当然也可以通过外接的键盘,鼠标和轨迹球等工具来操作. Android屏幕交互事件 用户在设备

  • JS实现移动端触屏拖拽功能

    1.html <div id="div1"></div> 2.css * { margin: 0; padding: 0; } html, body { width: 100%; height: 100%; } #div1 { width: 50px; height: 50px; background: cyan; position: absolute; } 3.js var div1 = document.querySelector('#div1'); //限

  • javascript实现移动端触屏拖拽功能

    本文实例为大家分享了javascript实现移动端触屏拖拽的具体代码,供大家参考,具体内容如下 HTML: <body> <div id="div1"> </div> </body> CSS: <style media="screen"> * { margin: 0; padding: 0; } html,body { width: 100%; height:100%; } #div1 { width: 5

  • Qt超时锁屏的实现示例

    概述 Qt实现超时锁屏的功能(工控机触摸屏),当手长时间不触摸屏幕的时候,程序超时会显示锁屏窗口. 效果 主窗口超时显示锁屏窗口: 系统窗口超时显示锁屏窗口: 实现思路 首先开启一个线程用于QTimer定时器计时,最开始进入软件开启定时器计时,超时则显示锁屏窗口:而手触摸屏幕会触发鼠标点击事件,则停止计时:而手离开屏幕会触发鼠标释放事件,则重新开始计时. 因为是多窗口的应用软件,所以需要监控全局鼠标事件,所以需要子类化QApplication类. 核心代码 监控全局鼠标事件的类为GlobalAp

  • html5手机触屏touch事件介绍

    HTML5中新添加了很多事件,但是由于他们的兼容问题不是很理想,应用实战性不是太强,所以在这里基本省略,咱们只分享应用广泛兼容不错的事件,日后随着兼容情况提升以后再陆续添加分享. 今天为大家介绍的事件主要是触摸事件: touchstart:触摸开始的时候触发 touchmove:手指在屏幕上滑动的时候触发 touchend:触摸结束的时候触发 而每个触摸事件都包括了三个触摸列表,每个列表里包含了对应的一系列触摸点(用来实现多点触控): touches:当前位于屏幕上的所有手指的列表. targe

  • js实现touch移动触屏滑动事件

    移动端触屏滑动的效果其实就是图片轮播,在PC的页面上很好实现,绑定click和mouseover等事件来完成.但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch事件能跟踪到屏幕滑动的每根手指. 以下是四种touch事件 touchstart: //手指放到屏幕上时触发 touchmove: //手指在屏幕上滑动式触发 touchend: //手指离开屏幕时触发 touchcancel: //系统取消touch事件的时候触发,这个好像比较少用 每个触摸事件被触发

  • 移动端触屏幻灯片图片切换插件idangerous swiper.js

    强大的移动端触屏幻灯片图片和HTML内容切换插件idangerous swiper,支持自定义左右切换还是上下切换,支持多个分组切换,支持下拉更新切换,支持TAB方式切换等十几种切换效果,支持众多的选项配置,如: speed:切换的速度(毫秒) autoplay:自动播放的速度 mode:切换模式 horizontal(横向) vertical(竖向) loop:是否循环播放true false 如此强大的配置功能,值得使用. 使用方法: 1.加载插件 <link rel="stylesh

  • 触屏中的JavaScript事件分析

    本文实例讲述了触屏中的JavaScript事件.分享给大家供大家参考.具体分析如下: 一.触摸事件 ontouchstart ontouchmove ontouchend ontouchcancel目前移动端浏览器均支持这4个触摸事件,包括IE.由于触屏也支持MouseEvent,因此他们的顺序是需要注意的:touchstart → mouseover → mousemove → mousedown → mouseup → click1 实例如下: /** * onTouchEvent */ v

随机推荐