QGraphicsItem鼠标精准拾取(pick/select)研究
在QT场景视图中,一个2D图形项是一个QGraphicsItem,我们可以通过继承来定义我们自己的图形项。
主要有以下三个虚函数需要重点关注:
1) 边界矩形(必须实现)
virtual QRectF boundingRect() const = 0;
2) 图形形状(可选实现),该函数返回图形项的实际形状路径,常用于碰撞检测、命中测试等等,默认实现返回boundingRect的矩形形状(具体的图形项的形状是任意变化的,默认的矩形形状显然不能正确表示图形的实际形状,所以建议重写该函数)。需要注意的是,形状的轮廓线可能会根据画笔大小以及线型而有所不同,所以实际的形状也应该包括轮廓线的区域。
virtual QPainterPath shape() const;
3) 图形内容(必须实现)
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) = 0;
图形一般的表现形式有两种:封闭和非封闭,如直线、曲线等都是非封闭图形,而矩形、椭圆等为封闭图形,非封闭图形无法使用填充,实际的形状为线条所指定的路径区域,封闭图形可以使用填充,实际的形状包括线条以及封闭填充区域。
QT的QPainter类提供了绘制最常见图形(如矩形、椭圆、多边形、文本等)API,对于一些不规则形状的复杂图形,则提供了drawPath方法通过绘制路径来达到。
QPainterPath
QPainterPath 类(绘图路径)提供了一个容器,用于绘图操作,可以创建和重用图形形状。
绘图路径是由许多图形化的构建块组成的对象,例如:矩形、椭圆、直线和曲线。构建块可以加入在封闭的子路径中,例如:矩形或椭圆。封闭的路径的起点和终点是一致的,或者他们可以作为未封闭的子路径独立存在,如:直线和曲线。
与正常绘图相比,QPainterPath 的主要优点在于:复杂的图形只需创建一次,然后只需调用 QPainter::drawPath() 函数即可绘制多次。QPainterPath 提供了一组函数,可用于获取绘图路径及其元素的信息。除了可以使用 toReversed() 函数来改变元素的顺序外,还有几个函数将 QPainterPath 对象转换成一个多边形表示。
QPainterPathStroker
QPainterPath 可以被填充(fill)、描绘轮廓(outline)、裁剪(clip)。要为一个指定的绘图路径生成可填充的轮廓,可以使用 QPainterPathStroker 类。。
通过调用createStroke()函数,将给定的QPainterPath作为参数传递,将创建一个表示给定路径轮廓的新画家路径(outlinepath)。 然后可以填充新创建的画家路径用于绘制原始画家路径(path)的轮廓。
您可以使用以下函数控制轮廓的各种设计方面(画笔宽度,帽子样式,连接样式和点画线模式):
- setWidth()
- setCapStyle()
- setJoinStyle()
- setDashPattern()
setDashPattern()函数既可以接受Qt::PenStyle对象,也可以接受模式的vector表示作为参数。
此外,您可以使用setCurveThreshold()函数指定曲线的阈值,控制绘制曲线的粒度。默认阈值是经过良好调整的值(0.25),通常您不需要修改它。但是,您可以通过降低其值来使曲线的外观更平滑。
您还可以使用setMiterLimit()函数控制生成的轮廓的斜接限制。斜接限制描述了斜接连接可以延伸到每个连接的距离。限制以宽度为单位指定,因此像素化斜接限制将为miterlimit * width。仅当连接样式为Qt :: MiterJoin时才使用此值。
注意,createStroke()函数生成的painter路径只能用于概述给定的painter路径,否则可能会导致意外行为。生成的轮廓也需要默认设置的Qt :: WindingFill规则。
QT场景视图中要实现2D图形的精准拾取,就需要关注图形的shape而不是boundingRect,下面是一个测试例子,仅供参考:
新建ItemBase类,继承自QGraphicsItem,用于规定子Item的一些共同行为:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#ifndef ITEMBASE_H
#define ITEMBASE_H #include <QGraphicsItem> class QGraphicsSceneMouseEvent; virtual ~ItemBase() override; QRectF boundingRect() const override; void paint(QPainter *painter, protected: protected: private: }; #endif // ITEMBASE_H |
在ItemBase类中,我们重写了boundingRect以及paint函数,图形项的具体形状在子类中重写shape()来实现:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
QRectF ItemBase::boundingRect() const
{ // 实际图形形状的边界矩形 return shape().boundingRect(); } void ItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(widget); if (option->state & QStyle::State_Selected) { painter->setRenderHint(QPainter::Antialiasing, true); if (option->state & QStyle::State_HasFocus) { painter->setPen(QPen(Qt::yellow, )); } else { painter->setPen(Qt::white); } painter->drawRect(boundingRect()); } painter->setRenderHint(QPainter::Antialiasing, false); } |
以ItemPolyline为例进行说明:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#ifndef ITEMPOLYLINE_H
#define ITEMPOLYLINE_H #include "ItemBase.h" class ItemPolyline : public ItemBase virtual void paint(QPainter *painter, #endif // ITEMPOLYLINE_H #include "ItemPolyline.h" ItemPolyline::ItemPolyline(QSize size, QGraphicsItem *parent) } void ItemPolyline::paint(QPainter *painter, painter->save(); ItemBase::paint(painter, option, widget); QPainterPath ItemPolyline::shape() const |
ItemPolyline类中重写shape()函数,使用QPainterPath和QPainterPathStroker比较精准地获取了图形的轮廓形状,有利于鼠标对图形的精准拾取。注意:对于封闭形状,既要考虑其形状所围填充区域,又要考虑其边界轮廓的宽度区域。
除了Polyline外,我还做了Rectangle、Ellipse、Bezier、ClosedBezier以及line和lines等2D图形,以下是运行截图:

鼠标点击2D图形的有效区域(即Shape所规定的路径区域)会比较精准地选中图形,而其它空白区域则无法选中,仅供参考,欢迎交流!
QGraphicsItem鼠标精准拾取(pick/select)研究的更多相关文章
- QQuickPaintedItem鼠标精准拾取(pick/select)研究
QT C++在2D图形方面已经做的很完善了,在PC端(Windows.Linux和MaC)上都有很好的表现. QT中的QML特别适合于移动端应用的开发,QML中的一些基本形状类型并不是一一地与Qt C ...
- QGraphicsItem鼠标旋转控制研究
在QT场景视图中2D图形项Item的基类为QGraphicsItem,如果我们需要自定义Item则可以从其派生,然后重写boundingRect以及paint虚函数实现图形项的外边界定义以及内容绘制工 ...
- Micro LED巨量转移技术研究进展
近年来,Micro LED因其功耗低.响应快.寿命长.光效率高等特点,被视为继LCD.OLED之后的新一代显示面板技术.Micro LED的英文全名是Micro Light Emitting Diod ...
- OpenGL中的拾取模式( Picking)
1. Opengl中的渲染模式有三种:(1)渲染模式,默认的模式:(2)选择模式, (3)反馈模式.如下 GLint glRenderMode(GLenum mode) mode可以选取以下三种模式之 ...
- Selenium:利用select模块处理下拉框
在利用selenium进行UI自动化测试过程中,经常会遇到下拉框选项,这篇博客,就介绍下如何利用selenium的Select模块来对标准select下拉框进行操作... 首先导入Select模块: ...
- js实现鼠标拖动框选元素小狗
方法一: <html> <head></head> <style> body{padding:100px;} .fileDiv{float:left;w ...
- WebGL射线拾取模型——八叉树优化
经过前面2篇WebGL射线拾取模型的文章,相信大家对射线和模型面片相交的原理已经有所了解,那么今天我们再深入探究关于射线拾取的一个问题,那就是遍历场景中的所有与射线相交的模型的优化问题.首先我们来复习 ...
- 微软的鼠标 Microsoft mouse
微软是做软件出身的厂商, 所以微软开发的软件质量毋庸置疑,Windows操作系统还有诸如Office的办公软件拥有庞大的用户群. 微软家的Visual Studio也被号称宇宙最强IDE,我个人也每天 ...
- Selenium: 利用select模块操作下拉框
在利用selenium进行UI自动化测试过程中,经常会遇到下拉框选项,这篇博客,就介绍下如何利用selenium的Select模块来对标准select下拉框进行操作... 首先导入Select模块: ...
随机推荐
- 【入门篇一】HelloWorld演示(2)
一.传统使用 Spring 开发一个“HelloWorld”的 web 应用 1. 创建一个 web 项目并且导入相关 jar 包. 2. 创建一个 web.xml 3. 编写一个控制类(Contro ...
- 链接doc命令行的mysql的编码问题
好几次用doc命令行链接mysql数据库进行保存注册等内容,一直出错,要么插入数据库的是乱码问题,要么是没插进去,怎么回事? 在修改了代码(接收中文数据)的基础上(即在代码中用utf-8接收数据) 也 ...
- python的开发工具pycharm安装及激活
下面介绍一种较好用也常用的python开发工具Pycharm,此文包括安装及注册激活码 一:安装方法如下: 1:进入官网下载:https://www.jetbrains.com/ 2:下载Commun ...
- Push to origin/master was rejected
在IDEA中往码云上传项目的时候出现了如下的错误:Push to origin/master was rejected 因为我是把代码上传到一个新的仓库里面,所以第一次提交的时候和仓库里面的东西不同步 ...
- 【贪心】umi的函数
原题传送门 思路 这道题乍一看很难,然而实际在草纸上一模拟,结果就出来了. 分析:这道题实际上要么无解,要么有无数个解,因而题目只要求输出了一个解(明白这点题目就做出来一半了). 题中,规定所求z满足 ...
- 文件上传之靶场upload-labs (11-20)
第十一关 strrpos() 函数查找字符串在另一字符串中最后一次出现的位置 substr() 函数返回字符串的一部分 文件保存的方式是上传路径+随机时间+截取的文件后缀 其中上传路径可控,可以利用这 ...
- Mysql load data infile 命令格式
[1]Linux系统环境下 LOAD DATA INFILE /usr/LOCAL/lib/ubcsrvd/datacsv/201909_source.csv INTO TABLE np_cdr_20 ...
- 彩虹表(rainbow table)
前记 MD5的全称是Message-Digest Algorithm 5(信息-摘要算法): 特点是不可逆的,一般解密不了:那有没有想过,为什么各种工具网站都可以进行MD5解密呢?https://ww ...
- pytest_demo_实战1
1.根目录配置 pytest.ini [pytest] addopts = -p no:warnings 2.更改运行手势,系统配置 file -> setting -> Tools -& ...
- [cf 1264 C] Beautiful Mirrors with queries
题意: 你有$n$个魔镜,第$i$个魔镜有$p_{i}$的概率说你美. 从第1天开始,你会依次询问魔镜$1-n$你美不美. 若第$i$个魔镜说你美则你明天会继续询问第$i+1$个魔镜. 否则你明天会从 ...