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模块: ...
随机推荐
- 201871010107-公海瑜《面向对象程序设计(java)》第七周学习总结
201871010107-公海瑜<面向对象程序设计(java)>第七周学习总结 项目 内容 这个作业属于哪个课程 ...
- day5_configparser模块
第一种情况:# 配置文件baidu.ini和当前文件在同一级目录: import configparser conf_read = configparser.ConfigParser() conf_r ...
- python json解析字符串出错该如何排查问题
每天写一点,总有一天我这条咸鱼能变得更咸 python中对于字符串转json格式有专门的json库可以操作 #!/usr/bin/env python # -*- coding: utf-8 -*- ...
- 【Spring IoC】IoC介绍(一)
IoC(Inversion of Control)的职责:原先由程序员主动通过new实例化对象这个事情,现在交由Spring负责,即由IoC容器负责. Spring 容器是 Spring 框架的核心. ...
- .NET三种异步模式(APM、EAP、TAP)
APM模式: .net 1.0时期就提出的一种异步模式,并且基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法. .net中有很多类实现了该模式(比如HttpWebReque ...
- Excel-图表制作
柱形图:通常使用柱形图比较数据间的数量关系 折线图:使用折线图来反映数据间的趋势关系 饼图:使用饼图来表示数据间的分配关系 对图表进行刷选 再图表设计下的快速布局可以选择各种样式 迷你图 对某列单 ...
- .NET开发中 springMVC+NHibernate注入失败的几个常见错误
1.spring程序集没引用,这个一定要引用,还有就是如果有Redis,还需引用ServiceStack 2.webConfig没配置对,这个没对一般会报错 3.也许Global.asax文件没引入全 ...
- 8.7 NOIP模拟测试14 旋转子段+走格子+ 柱状图
T1 旋转子段 30% 暴力枚举起点和长度,暴力判断,o(n3) 不知道为什么我拿了40分... 60% 每一个点都有一个固定的旋转中心可以转成固定点,枚举旋转点和长度. 100% 用一个vecto ...
- [LeetCode] 917. Reverse Only Letters 只翻转字母
Given a string S, return the "reversed" string where all characters that are not a letter ...
- HDU 4005 The war(边双连通)
题意 给定一张 \(n\) 个点 \(m\) 条边的无向连通图,加入一条边,使得图中权值最小的桥权值最大,如果能使图中没有桥则输出 \(-1\). 思路 先对原图边双缩点,然后变成了一棵树.在 ...