Потребовалась мне тут на днях отрисовка сложных графиков в QML.
Увы, но возможностей существующих графиков не хватило — пришлось изобретать свои.

Проблема возникла с тем, что по умолчанию всё, что имеет отрицательные координаты x и y будет подвергнуто кастрации.
Да же если поставим:

setClip(false);
setFlag(QQuickItem::ItemClipsChildrenToShape, false);

И попробуем вывести круг:

void MyCircle::paint(QPainter * painter)
{
   QPainterPath path;
   path.addEllipse(-200, -200, 400, 400);

   painter->setPen(Qt::NoPen);
   painter->fillPath(path, QBrush(QColor("orange")));
}

Всё, что меньше (0, 0) будет обрезано:

Можно было бы задать размер по размеру основного окна, но мне нужно было чтобы итем холста имел конкретные размеры и положение, т.к. он на сцене будет не один.

Самое простое решение на данный момент — задать QPainter глобальную матрицу трансформации со смещением в противоположную сторону (что бы не высчитывать новые координаты при отрисовке примитивов). А компоненту задать соответственно в координатах X и Y это же значение смещения. Единственный минус — придётся делать обёртку над компонентом.
Вот так примерно:

painter->setWorldTransform(QTransform::fromTranslate(200, 200), true);
setPosition(QPoint(-200, -200));

И в QML соответственно обёртку сделать:

import QtQuick 2.12
import QtQuick.Window 2.12
import MyCircle 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("QQuickPaintedItem outside bounds")

    Rectangle {
        anchors.fill: parent
        color: "black"
    }

    Item {
        id: myCircleWrapper
        anchors.centerIn: parent
        width: 200
        height: 200

        MyCircle {
            id: myCircle
            width: parent.width
            height: parent.height
            clip: false
        }
    }
}

И результат:

Как сделать более правильно я, к сожалению, после нескольких дней раздумий и ковырянии исходников Qt не придумал…

Leave a Comment

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

You may also like