IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Création dynamique d'une courbe et interactions en QML
à l'aide du composant Canvas, un billet de Jiyuu

Le , par Jiyuu

0PARTAGES

Bonjour,

Dans un précédent billet, nous avions vu comment créer une courbe en QML depuis une liste de points connus.

Je vous propose maintenant de voir comment créer une courbe dynamiquement, c'est-à-dire en exploitant, par exemple, une liste de coordonnées depuis une base de données ou d'un calcul.

En nous inspirant du premier billet, nous allons créer la fenêtre, le canvas et les différents éléments qui nous permettront de créer notre courbe ou d'interagir avec celle-ci.
Voici ce que cela donnerait :


import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2


Window {
visible: true
width: 800; height: 500
x: 100 ; y: 100
title: "Create curve with QML"


Rectangle{
id: root
anchors.fill: parent

ColumnLayout {
id: grid
anchors.fill: parent


RowLayout {
id: control
Layout.fillWidth: true
implicitHeight: 25
Button {
text: "Trace"
}

Button {
text: "Efface"
}

Slider {
id: slider
value: 0
maximumValue: 20
}

Item {
Layout.fillWidth: true
}

Label {
id: posiX
}

Label {
id: posiY
}

Label {
id: posiX2
}
}

Rectangle {
id: area
Layout.fillHeight: true
Layout.fillWidth: true
color: "lightgray"
Canvas {
id: canvas
anchors.fill: parent
transform: Rotation { origin.x: area.x; origin.y: area.height/2; angle: 180; axis { x: 1; y: 0; z: 0 }}
property int origX: 0
property int origY: 0
property int maxX: width - origX
property int maxY: height - origY

property alias pointCurve: pointCurve

/* c'est ici que ça commence à devenir intéressant. Comme précédemment nous allons créer au démarrage de l'application nos axes, mais nous n'irons pas plus loin.*/

onPaint: {
getContext("2d")

/* getContext("2d") est nécessaire pour indiquer dans quel type de context nous nous trouvons.
Ici on déclare donc un Context2D (http://doc.qt.io/qt-5/qml-qtquick-context2d-members.html) qui a notamment deux méthodes qui nous intéresseront tout particulièrement :
- beginPath()
- closePath()

Entre ces deux méthodes, vous pouvez créer comme bon vous semble différents chemins et y appliquer un style unique (couleur, épaisseur du trait...) .
Pour appliquer d'autres styles il faudra redéclarer un nouveau Path (chemin en anglais).*/

/* Trace Axes */
context.beginPath()
context.lineWidth = 2
context.moveTo(origX, origY) // permet de se déplacer sans tracer de points
context.lineTo(maxX, origY) // permet de tracer une ligne
context.moveTo(origX, origY)
context.lineTo(origX, maxY)
context.strokeStyle = Qt.rgba(0,0,0);
context.stroke()
context.closePath()
}

ListModel{id: pointCurve}


}
}
}
}
}

À ce stade vous devriez avoir quelque chose qui ressemble à ceci :
189665

Nous allons maintenant créer notre courbe.

Nous allons tout d'abord compléter nos composants Button et Slider afin de permettre l'interaction avec notre Canvas. Commençons par remplir notre ListModel des points à tracer :
Button {
text: "Trace"
onClicked: {
for (var i=0; i<=20; i++){
pointCurve.append({"x":i*20, "y":Math.pow(i,2)})
}
canvas.traceCurve() // nous verrons cette fonction un peu plus bas.
}
}

Puis la gestion de l'effacement de notre courbier :
Button {
text: "Efface"
onClicked: {
slider.value = 0
canvas.clear() // Comme pour canvas.traceCurve() nous verrons bientôt cette fonction.
}
}

Et enfin notre Slider qui nous permettra d'afficher un curseur :
Slider {
id: slider
value: 0
maximumValue: 20
onValueChanged: {
if (value !== 0)canvas.point(root.valueX*20, Math.pow(root.valueX,2))
canvas.traceCurve()
}
}

Et voici enfin le moment tant attendu : le traçage de la courbe.

Pour cela nous allons implémenter la fonction suivante :
function traceCurve() {
if (context){
context.beginPath() // comme précédemment nous créons un nouveau Path
context.lineWidth = 1
for (var i = 0; i < pointCurve.count; i++) { // Pour chaque élément de notre ListModel, nous créons une nouvelle ligne
var posiX = origX + pointCurve.get(i).x
var posiY = origY + pointCurve.get(i).y
context.lineTo(posiX, posiY)
}
context.moveTo(origX, origY)
context.strokeStyle = Qt.rgba(0,0,1);
context.stroke() // Nous appliquons le style voulu
context.closePath() // Nous fermons notre chemin
}

requestPaint() // et nous lançons la requête de rendu


Le principe pour tracer le curseur (fonction point () utilisée dans le Slider) est sensiblement le même.
Pour effacer le contenu de notre Canvas il suffit d'effacer le contenu de notre ListModel, faire un reset du context et redonner l'ordre de tracer les nouveaux éléments : c'est à dire rien du tout.
function clear(){
if (context){
pointCurve.clear()
context.reset()
requestPaint()
}
}


Voici ce que donne le code complet :

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2


Window {
visible: true
width: 800; height: 500
x: 100 ; y: 100
title: "Create curve with QML"


Rectangle{
id: root
anchors.fill: parent

property alias valueX: slider.value

ColumnLayout {
id: grid
anchors.fill: parent


RowLayout {
id: control
Layout.fillWidth: true
implicitHeight: 25
Button {
text: "Trace"
onClicked: {
for (var i=0; i<=20; i++){
pointCurve.append({"x":i*20, "y":Math.pow(i,2)})
}
canvas.traceCurve()
}
}
Button {
text: "Efface"
onClicked: {
slider.value = 0
canvas.clear()
}
}
Slider {
id: slider
value: 0
maximumValue: 20
onValueChanged: {
if (value !== 0)canvas.point(root.valueX*20, Math.pow(root.valueX,2))
canvas.traceCurve()
}
}
Item {
Layout.fillWidth: true
}

Label {
id: posiX
text: "x : " + (root.valueX*20).toFixed(2)
}
Label {
id: posiY
text: "y : " + Math.pow(root.valueX,2).toFixed(2)
}
Label {
id: posiX2
}
}

Rectangle {
id: area
Layout.fillHeight: true
Layout.fillWidth: true
color: "lightgray"
Canvas {
id: canvas
anchors.fill: parent
transform: Rotation { origin.x: area.x; origin.y: area.height/2; angle: 180; axis { x: 1; y: 0; z: 0 }}
property int origX: 0
property int origY: 0
property int maxX: width - origX
property int maxY: height - origY

property alias pointCurve: pointCurve



function clear(){
if (context){
pointCurve.clear()
context.reset()
requestPaint()
}
}

function point(q, h){
context.reset()
context.beginPath()
context.lineWidth = 1
context.moveTo(origX, h+origY)
context.lineTo(maxX, h+origY)
context.moveTo(q+origX, origY)
context.lineTo(q+origX, maxY)
context.strokeStyle = Qt.rgba(1,0,0);
context.stroke()
context.closePath()
requestPaint()
}

function traceCurve() {
if (context){
context.beginPath()
context.lineWidth = 1
for (var i = 0; i < pointCurve.count; i++) {
var posiX = origX + pointCurve.get(i).x
var posiY = origY + pointCurve.get(i).y
context.lineTo(posiX, posiY)
}
context.moveTo(origX, origY)
context.strokeStyle = Qt.rgba(0,0,1);
context.stroke()
context.closePath()
}

requestPaint()
}

onPaint: {
getContext("2d")

/* Trace Axes */
context.beginPath()
context.lineWidth = 2
context.moveTo(origX, origY)
context.lineTo(maxX, origY)
context.moveTo(origX, origY)
context.lineTo(origX, maxY)
context.strokeStyle = Qt.rgba(0,0,0);
context.stroke()
context.closePath()
}

ListModel{id: pointCurve}
}
}
}
}
}


Vous avez maintenant en main de quoi réaliser de belles courbes dynamiquement, alimentées par vos calculs les plus fous ou votre super base de données 8-)

Vous avez lu gratuitement 3 133 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !