How to draw Bezier curves in QML?
-
Hello,
I need to draw Bezier (preferably, or at least other cubic) curves in QML, is it possible? And if yes, how?
I'm experienced with Qt C++, but I just have started discovering QML possibilities.This far I tried with QML's Pathview (AFAIK can't be displayed directly) and port of HTML5 canvas (which's really great, but I need whole area to be scalable, and since canvas is just a bitmap I'm not interested in it), but to no avail.
I can draw curves directly in C++, but I need them to dynamically move (each curve is connecting two boxes which can be d&d) - it seems a bit tricky, is there an easier option to achieve this?
-
I was also looking into realising some connected shapes logic with QtQuick some time ago. With standard QtQuick 1.x components it is not possible for sure. I think you have to extend QML with your own components.
See here: http://doc.troll.no/4.7/qml-extending.html
and here: http://doc.troll.no/4.7/qml-extending-tutorial-index.htmlGood luck, and let me know if you get it working;)
-
[quote author="moo1" date="1301956183"]Can you just use SVG as a source for the Image element? You shouldn't need any extension.[/quote]
I can't, because I need these lines to dynamically adjust their shapes while I'm moving boxes. :/
-
Hmmm... in theory even a border image would do. Compute start and end point, derive angle, rotate the arrow image, etc. Of course the arrow head needs to be fully inside the border.
-
I've made an extension for myself, which allow me to draw line, with cubic option.
You will need to create a qml plugin. And to something like that
:
@void Line::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{//setting drawing param
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);// Construct the main path
QPainterPath totalPath;
totalPath.moveTo(m_points.at(0)->x(),m_points.at(0)->y());
for (int i=1; i<m_points.size(); ++i)
{
totalPath.lineTo(m_points.at(i)->x(),m_points.at(i)->y());
}//drawing directly
painter->strokePath(totalPath, QPen(m_pencolor, m_penWidth));}@
For adding cubic you could look at the "path stroking exampe":http://doc.qt.nokia.com/latest/demos-pathstroke.html
And no you could not use an svg file because the svg is just render once at start.
-
Merinas,
I've made similar thing as you and it works literally halfway - when I move one anchor point only the left and upper areas are updated.
Doeas anyone have an idea how to fix it?Here is how it looks like:
http://student.agh.edu.pl/~wmaciej/nodes.png
my paint() fction:
@void Line::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
QPainterPath path;painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); QPointF middle1( (m_startingPoint.x() + m_endingPoint.x())/4, (m_startingPoint.y() + m_endingPoint.y())/2 ); QPointF middle2( 3*(m_startingPoint.x() + m_endingPoint.x())/4, (m_startingPoint.y() + m_endingPoint.y())/2 ); path.moveTo(m_startingPoint.x(), m_startingPoint.y()); path.cubicTo( middle1.x(), middle1.y(), middle2.x(), middle2.y(), m_endingPoint.x(), m_endingPoint.y() ); painter->strokePath( path, QPen(m_penColor, m_penWidth) );
// painter->setPen( QPen(Qt::red) );
// painter->drawRect( path.boundingRect().normalized() );
}@Whole code can be found "here":http://student.agh.edu.pl/~wmaciej/LineTest.zip.
-
After some experiments I think it's general QML-related problem, not generated by my implementation.
But it's behavior is very strange:If I connect starting and ending points of my curve to some points on two QML Rectangles it looks fine.
When I move the rectangles (with MouseArea's drag) Qt updates only the region from (window's) 0,0 to lower right point of moving rectangle, no matter where my line is pinned to. It means in the case the whole curve is placed above moving rect's lower right corner, everything updates as it should; otherwise (= when whole curve's bounding rect is not contained in mentioned area) only that part which's in is updated.What's more, when my curve is displayed wrongly and the window needs to be repainted - i.e. I change it's size or click on other window to lose focus - curve * magically * updates correctly.
Explixitly calling QDeclarativeView object to update itself doesn't help.
Does anyone have the idea what can I do? It's really important for me to have cubic lines available from QML..
@_Merinas_:
Yeah, it's a bit hard to explain what my particular problem is, so besides my story here is a gif:!http://student.agh.edu.pl/~wmaciej/QML-line.gif(my problem)!
Hope it's gonna help you understand what I mean.
-
In the beggining I thought you're talking about the OS, so I switched to Linux - but this error is also present there.
I found a brute-force workaround: automatically resize top window by 1px back and forth.
Pitiful and very CPU-eating, but works for now.Shold I report this as a bug?
-
Hi,
Does setting QGraphicsView::FullViewportUpdate on the QDeclarativeView work?
Does your Line element set a width and height? This is needed by QDeclarativeItem's "boundingRect":http://doc.qt.nokia.com/4.7/qgraphicsitem.html#boundingRect implementation (which determines what area needs to be repainted when update() is called for the element).
Regards,
Michael -
[quote author="Merinas" date="1302507353"]When the point of the curve move, Haven't you forget to call the update function ? [/quote]
No, I haven't forgot;
[quote author="mbrasser" date="1302567263"]Hi,
Does setting QGraphicsView::FullViewportUpdate on the QDeclarativeView work?
Does your Line element set a width and height? This is needed by QDeclarativeItem's "boundingRect":http://doc.qt.nokia.com/4.7/qgraphicsitem.html#boundingRect implementation (which determines what area needs to be repainted when update() is called for the element).
Regards,
Michael[/quote]Setting QGraphicsView::FullViewportUpdate on QDeclarativeView works fine - it's still CPU-eating, but it better solution than mine previous;
I didn't implement boundingRect() method at all, nor I set width and height. After doing this it's a bit better - the rectangle in which my line is updated is bigger than previously, but it differs - sometimes whole line is updated, sometimes not.Is there any particular order I should set new values in in paint() method? Now it looks like this:
@
void Line::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);QPointF middle1( (m_startingPoint.x() + m_endingPoint.x())/10, m_startingPoint.y() ); QPointF middle2( 9*(m_startingPoint.x() + m_endingPoint.x())/10, m_endingPoint.y() ); QPainterPath path; path.moveTo( m_startingPoint ); path.cubicTo( middle1, middle2, m_endingPoint ); rect = path.boundingRect(); setHeight( rect.height() ); setWidth( rect.width() ); painter->strokePath( path, QPen(m_penColor, m_penWidth) );
// painter->setPen( QPen(Qt::red) );
// painter->drawRect( boundingRect() );
}QRectF Line::boundingRect()
{ return rect; }
@Anyway - thank you, mbrasser, it's one step closer. :)
[EDIT:]
Testing goes on:
-
Calling prepareGeometryChange(); inside a paint() method wasn't best idea. ;)
-
As I see the problem is in these lines:
@ setHeight( rect.height() );
setWidth( rect.width() );@When I set width and height properly bigger, it works. Just don't know the correct equation for these values to work in every case.
-
-
@i think that is very easy to do .like below...just a simplest example!
import QtQuick 1.0
Rectangle {
id: rect;
width: 450;
height:800;
PathView {
id: pathView;
model: 300;
delegate: Rectangle {
id: dot;
width: 1; height: 1;
color: "black";
}
path: Path {
startX: 20; startY: 0
PathCubic {
x: 180; y: 0
control1X: -10; control1Y: 90
control2X: 210; control2Y: 90
}
}
}
}another version! perfect result!
import QtQuick 1.0
Rectangle {
id: rect;
width: 450;
height:800;
PathView {
id: conrPaV;
anchors.fill: parent;
model: 900;
delegate: Rectangle {
id: dot;
width: 1; height: 1;
color: "red";
}path: Path { id: ph; startX: 0.0; startY: conrPaV.height/2.0; PathQuad { x: 40.0; y: conrPaV.height/2.0; controlX: 20.0; controlY: ph.startY -60.0; } PathQuad { x: 80.0; y: conrPaV.height/2.0; controlX: 60.0; controlY: ph.startY +60.0; } } }
}
@