Qtで指定領域を除外して描画する

QPainter::setClipRect、setClipPathを使用すると、指定した領域に限定して描画することができます。逆に、指定した領域を除外して描画するにはどうしたら良いか、Twitterで尋ねたら@task_jpさんが教えてくださいました

このテクニックの肝は、QPainterPath::subtractedを使用するというところです。

void MyCentralWidget::paintEvent(QPaintEvent *)
{
    QPainter pr(this);

    QPainterPath entire_path;
    entire_path.addRect(rect());

    QPainterPath exclude_path;
    exclude_path.addEllipse(width() / 4, height() / 4, width() / 2, height() / 2);

    QPainterPath clip_path = entire_path.subtracted(exclude_path);

    pr.setClipPath(clip_path);

    for (int i = 0; i < 100; i++) {
        int x0 = rand() % width();
        int y0 = rand() % height();
        int x1 = rand() % width();
        int y1 = rand() % height();
        QRect r(x0, y0, x1 - x0, y1 - y0);
        pr.setPen(QColor(rand() % 256, rand() % 256, rand() % 256));
        pr.drawEllipse(r);
    }
}
最初に、描画領域全体の矩形のパスを作っておき、次に、除外したい領域のパスを作り、subtracted(引き算)してから、setClipPathします。