Bonsoir...

QtQuick c'est le futur, dans Qt7 cela aura remplacé QtWidgets, alors j'ai décidé d'être un pionnier (sisi) et de l'utiliser pour du bon gros desktop. Ouais j'aime souffrir.

Je suis donc en train de développer un éditeur de propriétés pour QML en projet personnel. L'objectif est le même que celui du QtPropertyBrowser framework.

Backend
------------

Je met un point d'honneur à ce que le backend, c'est à dire la définition des propriétés éditables, soit utilisable et en C++, et en QML. Je souhaite laisser ce choix.

Un rapide tour d'horizon :

- Un objet CProperty contient un identifiant unique, maintient une référence vers l'objet à éditer, le nom de la propriété concernée et son type. Selon ce type, une subclass peut exister, contenant des attributs utiles (par exemple pour une IntProperty, l'objet contiendra des attributs maximum et minimum).

- PropertyManager gère une liste de CProperty. Cette liste est exposée côté QML au moyen de QQmlListProperty. Il contient également une map <CProperty *, QVariant> : c'est lui qui gère les affectations de valeurs aux "c"propriétés.

- Pour des raisons pratiques, un CProperty connaît également son PropertyManager. Un appel à CProperty::write(QVariant) appelle la méthode correspondante de PropertyManager.

Voilà pour la partie logique. Peut-être un peu naïve, sans aucun doute optimisable.

Front
--------

La partie graphique réside essentiellement dans la classe FactoryManager, là-encore une classe C++ enregistrée vers QML. Elle contient une QQmlListProperty de EditorFactory. Cette dernière classe contient deux attributs : un type de propriété et un QQmlComponent pour permettre à l'utilisateur d'éditer la dite propriété.

Un EditorFactory n'est définissable que depuis QML : en effet impossible d'instancier un control QML depuis le C++. De ce côté-là, la séparation back/front me satisfait (vous aussi ?).

Application
-----------------

La partie casse-c...embêtante. Cette fois cela se passe exclusivement côté QML. J'ai un TreeView et je voudrais qu'il exploite correctement les informations ci-dessus pour afficher un bel éditeur de propriétés.

Première remarque : m****, il me faut un model. PropertyManager le gère donc : à chaque ajout de propriété, un QStandardItem est ajouté au model. Mais quelles données y associer ? L'identifiant unique, le type, le nom et la valeur actuelle de la propriété.

Ainsi dans la première colonne, le nom est affiché.

Pour la deuxième colonne, c'est du bricolage : son delegate est celui associé au bon EditorFactory. En gros cela donne :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 
PropertyManager {
  id: propertyManager
 
  IntProperty {
    // <implicit> type: PropertyManager.Int
    target: unItem
    name: "x" 
  }
 
  onValueChanged { // arguments : (PropertyElement p, var value)
    p.target[p.name] = value // Met à jour la propriété concernée. Moche n'est-ce-pas ?
  }
}
 
FactoryManager {
  id: factoryManager
 
  EditorFactory {
    type: PropertyManager.Int
    delegate: SpinBox {
      value: propertyData.target[propertyData.name] // Encore moche.
      minimumValue: propertyData.minimum
 
      onValueChanged: propertyData.write(value)
    }
  }
}
 
// Deuxième colonne
TableViewColumn {
  role: "value"
 
  delegate: Loader {
    sourceComponent: factoryManager.suitableEditor(model["type"]) // La magie de la gestion des modèles par QML
    property PropertyElement propertyData : propertyManager.getProperty(model["propertyId"]) // Fournit les infos complètes de la CProperty à l'EditorFactory
  }
}
Et cela fonctionne plutôt bien. Mais qu'est ce que c'est crade (remarquez, on trouve du beau dans les sources de QtQuickControls) : la GUI utilise le model et a quand même besoin que le PropertyManager lui fournisse d'autres informations pour que tout fonctionne. PropertyManager met à jour la valeur de la propriété et le model dans la foulée.

J'ai essayé d'enregistrer CProperty * en tant que metatype pour qu'il soit accessible depuis le model et avoir un seul rôle :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
property PropertyElement propertyData : model["propertyPtr"]
Seulement voilà, QML fait que le pointeur est casté en double...sisi. Magnifique. Et en plus cela fait un binding loop. Bref, à oublier.


Le mot de la fin
---------------------

Je suis ouvert à toutes critiques, en d'autres termes j'en ai sacrément besoin Critiques, conseils, descentes en flamme...tout ce que vous voulez. J'espère que mes explications vous permettront de comprendre...

Merci à tous