Потребовалась мне тут на днях отрисовка сложных графиков в 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 не придумал…