QGraphicsScene 中的视觉像素完美选择

Posted

技术标签:

【中文标题】QGraphicsScene 中的视觉像素完美选择【英文标题】:Visual pixel-perfect selection in QGraphicsScene 【发布时间】:2014-02-14 12:55:30 【问题描述】:

我有一个QGraphicsScene,我希望用户在其中绘制/移动东西。目前我可以绘制所有我想要的形状(即[未]填充的矩形和椭圆、线条和三次贝塞尔曲线),导出QGraphics*Item

我也可以在这些项目上实现选择,但我想要某种像素完美的选择。例如,可以在单击曲线旁边的弯曲位置时选择曲线,即使鼠标不在实际线上也是如此。空矩形或椭圆也是如此,单击它们中间的孔也可以选择它们。

这是因为contains 的工作方式,它不符合我的需要:它基本上检查点是否在边界矩形中。 setBoundingRegionGranularity(1) 解决不了任何问题(以防万一)。

我还尝试直接检查该点是否包含在我的项目的 QPainterPath 中,但这给了我相同的结果。

我怎样才能对我的形状进行视觉选择?

目前我看到的唯一解决方案是为我拥有的每个形状重新实现我自己的 contains 函数,但这可能非常复杂,如果可能的话,我真的很想用 Qt 来完成。

我使用的是 Python 3.3 和 PyQt 5 (.1.1 IIRC),但这与 Qt 框架的关系比语言/绑定更重要,而且 C++ 中的答案也很好。

【问题讨论】:

【参考方案1】:

QGraphicsPathItem::shape 包含它正在显示的路径,包括其内部区域。您期望的行为更像QGraphicsPixmapItem。如果它的shapeModeQGraphicsPixmapItem::MaskShape(默认),它的形状将只包含不透明的点。您可能希望在像素图上绘制曲线并在场景中显示像素图并享受默认行为。您还可以重新定义QGraphicsPathItem::shape 并实现此行为。工作示例,C++(可以很容易地适应 Python):

class MyGraphicsPathItem : public QGraphicsPathItem 
public:
  MyGraphicsPathItem() 
  QPainterPath shape() const 
    QRectF rect = path().boundingRect();
    QImage canvas(rect.size().toSize(), QImage::Format_ARGB32);
    canvas.fill(qRgba(0, 0, 0, 0));
    QPainter painter(&canvas);
    painter.setPen(pen());
    painter.drawPath(path().translated(-rect.topLeft()));
    painter.end();
    QPainterPath result;
    result.addRegion(QPixmap::fromImage(canvas).mask());
    return result.translated(rect.topLeft());
  
;

用法:

MyGraphicsPathItem* item = new MyGraphicsPathItem();
item->setPath(path);
item->setFlag(QGraphicsItem::ItemIsSelectable);
item->setPen(QPen(Qt::green, 3));
scene->addItem(item);

请注意,此实现非常慢。谨慎使用。

【讨论】:

感谢您的回答。但是,使用 Pixmaps 会降低形状上的抗锯齿效果,我是否遗漏了什么? 您需要在用于创建像素图的画家中启用QPainter::Antialiasing 提示。如果使用像素图缩放,还应设置QGraphicsPixmapItem::setTransformationMode(Qt::SmoothTransformation)

以上是关于QGraphicsScene 中的视觉像素完美选择的主要内容,如果未能解决你的问题,请参考以下文章

调整 QGraphicsScene 大小时的事件

使用 Qt 绘制像素完美的圆

旋转像素完美碰撞检测

点标注像素级视觉任务Ground Truth

QGraphicsScene 放大和缩小

在 QGraphicsView 中获取 QGraphicsScene 的可见区域 [重复]