如何在Qt QGraphicsScene中剪辑未闭合的路径

时间:2012-01-06 15:06:10

标签: python qt pyqt pyside

QGraphicsView QGraphicsScene,我需要在由scene定义的rect的有限区域内绘制未关闭的路径(可能包含线条或贝塞尔曲线)。

使用QPainterPath.intersected(path)函数剪切关闭路径的方法很简单,但如果path 未关闭,那么intersected关闭它(从开头到开始点添加一行)。

以下是说明我的问题的简化代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import functools
import sys
from PySide.QtCore import *
from PySide.QtGui import *

def path_through_points(points):
    path = QPainterPath()
    path.moveTo(*points[0])
    for x, y in points[1:]:
        path.lineTo(x, y)
    return path

def path_through_points_workaround(points):
    return path_through_points(points + list(reversed(points)))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    scene = QGraphicsScene()
    view = QGraphicsView(scene)
    rect = QRectF(0, 0, 300, 300)

    clip = QPainterPath()
    clip.addRect(rect)

    points = [(50, 50), (100, 100), (500, 300)]

    def test_draw(path):
        scene.clear()
        scene.addRect(rect)
        scene.addPath(path)

    unclosed_path = path_through_points(points)
    closed_path = path_through_points_workaround(points)

    QTimer.singleShot(0, functools.partial(test_draw, unclosed_path))
    QTimer.singleShot(2000, functools.partial(test_draw, unclosed_path.intersected(clip)))
    QTimer.singleShot(4000, functools.partial(test_draw, closed_path.intersected(clip)))

    view.resize(640, 480)
    view.show()
    sys.exit(app.exec_())

它绘制生成的路径:

  1. 没有裁剪。
  2. 使用剪辑(路径关闭而非剪辑) - 这对我来说是不可接受的。
  3. 最后,我想得到的结果(但是通过解决方法达到了目的)。
  4. 解决方法:通过以path顺序绘制来关闭reversed。但是我的path可能包含许多行/ beziers,因此它无效,并且使用双倍行反抗锯齿看起来很糟糕。

    所以问题是如何在不改变路径生成函数逻辑的情况下在QGraphicsScene中剪切未闭合的路径或行?

    更新

    现在我正在使用以下功能:

    def clipped_path(path, min_x, min_y, max_x, max_y):
        """ Returns clipped path, supports unclosed paths of any kind
        (lines, beziers)
    
        NOTE: Resulting path can loose antialiasing
        """
        path.connectPath(path.toReversed())
        clip = QPainterPath()
        clip.addRect(QRectF(min_x, min_y, max_x, max_y))
        return path.intersected(clip)
    

    更新2

    建议使用@Hello W的更好方法:

    class ClippedItemMixin(object):
        def __init__(self, min_x, min_y, max_x, max_y):
            self._clip_path = QtGui.QPainterPath()
            self._clip_path.addRect(QtCore.QRectF(min_x, min_y, max_x, max_y))
            super(ClippedItemMixin, self).__init__()
    
        def paint(self, painter, *args, **kwargs):
            painter.setClipPath(self._clip_path)
            super(ClippedItemMixin, self).paint(painter, *args, **kwargs)
    
    
    class ClippedPathItem(ClippedItemMixin, QtGui.QGraphicsPathItem):
       pass
    

    现在它看起来更好,因为抗锯齿效果正常。

1 个答案:

答案 0 :(得分:1)

如何从QGraphicsPathItem继承子类,然后重新实现它的paint方法并调用painter.setClipRect()