Last modified 5 years ago Last modified on 11/01/2012 14:46:50

OhOUI : Offhand Object User Interface

Ou comment obtenir une interface graphique pour modifier les propriétés d'une instance, sans rien faire.

C'est une librairie Java initié par Stéphan et Nicolas et actuellement développé par Nicolas.

Première présentation faite au labo à la réunion Modelix du 7 Novembre 2005.

L'idée du projet est née de la puissance offerte par la librairie XStream, et de la volonté de proposer plus de convivialité et pouvoir manipuler les paramètres d'un objet de manière dynamique. S'ajoute à cela, le côté rébarbatif de la conception et surtout du développement d'une interface graphique pour paramétrer un programme.

Téléchargements

  • Une archive peut être téléchargée sur notre serveur d'intégration continue
  • OhOUI peut être ajouté en dépendance à un projet maven avec ces coordonnées :
    <dependency>
      <groupId>fr.cemagref</groupId>
      <artifactId>ohoui</artifactId>
      <version>0.1.1</version>
    </dependency>
    
  • les sources de la version de développement

Comment ça marche ?

Le fonctionnement est simple, vous avez quelquepart dans votre code un objet dont vous voulez faire modifier les propriétés à l'aide d'une interface graphique. Pour cela, vous n'avez rien à faire que de demander à OhOUI de le faire pour vous, et d'éventuellement ajouter quelques métadonnées pour configurer le processus de génération de l'interface graphique.

Pour un objet quelconque, OhOUI générera une boîte dialogue, ou un simple composant que vous pourrez intégrer dans votre programme, permettant de modifier chaque attribut de cet objet. Pour chaque attribut, un composant graphique sera générer en fonction du type déclaré de cet attribut. Ainsi un booléen produira une case à cocher, un fichier (de type java.io.File) produira un bouton permettant d'ouvrir une boîte de dialogue standard de choix de fichier, ... Bien sûr, le développeur pourra ajouter ses propres producteurs de composants graphiques pour modifier un objet de type particulier, ou modifier un comportement existant.

Un exemple (cet exemple est disponible dans les sources dans le répertoire racine), voici deux classes (la première contenant une instance de la deuxième) :

class MaClasse2 {
    private Integer i;
    @Description (name = "Un booléen", tooltip = "Utilisez la case à cocher")
    boolean b = true;
    private String s = "modifiez-moi";
    private MaClasse1 maClasse1 = new MaClasse1();
}    

class MaClasse1 {
    @Description (name = "L'âge du capitaine", tooltip = "")
    public double nombre = 5;
    File unFichier = new File("");
    @Description(name="La couleur du ciel ",tooltip = "Changez moi cette couleur")
    Color couleur = new Color(150,150,150);
}

Remarquez les annotations @Description (optionnelles) qui permettent d'ajouter une description (variable name) à un attribut un peu plus explicite que le nom de la variable. Cette annotation a également une variable tooltip qui est utilisée pour ajouter une info-bulle sur un élément (comme sur la deuxième capture)

À partir de là, pour obtenir une boîte de dialogue de configuration, les lignes suivantes suffisent :

MaClasse2 maClasse2;

OhOUIDialog dialog = OhOUI.getDialog(null,maClasse2);
// ajustement de la taille
dialog.pack();
// affichage de la boîte de dialogue
dialog.setVisible(true);

Pour obtenir la boîte de dialogue suivante

Détail des fonctionnalités

Instanciation à la volée

Si un attribut ne comporte pas d'objet (si il vaut null), le formulaire proposera alors d'instancier un nouvel objet et de l'affecter à l'attribut. Un nouveau composant graphique sera alors ajouté pour modifier ce nouvel objet.

Gestion des types polymorphes

En plus de pouvoir modifier les valeurs des attributs, il est également possible de modifier le type d'objet utilisé si d'autre types héritant du type déclaré de l'attribut sont disponibles. Ainsi avec un attribut de type List, il est possible de choisir l'implémentation utilisée : ArrayList, LinkedList, ...

Cette fonctionnalité est particulièrement intéressante pour modifier l'architecture d'un modèle. Il en effet intéressant de proposer plusieurs algorithmes pour résoudre un problème, et de pouvoir choisir quel algorithme utiliser pour une expérimentation pour par exemple choisir des scénarios à simuler. Grâce à OhOUI, il est possible de faire ce choix avec un bouton, plutôt que de taper des lignes de codes supplémentaires.

Vous comprendrez peut-être mieux avec cet exemple qui produit ce formulaire :

Le bouton à droite de l'attribut Process permet de choisir le type à instancier :

Après création de l'objet, le formulaire est mis à jour, et nous pouvons modifier le nouvel objet créé :

Il est toujours possible de modifier le type instancié avec le petit bouton comprenant deux flèches.

Fonctions avancées

Désactivation de l'introspection récursive

Dans certaines situations, l'introspection récursive devient gênante. Par exemple dans le cas d'une classe qui hériterait d'une classe qui comporte beaucoup d'attributs complexes, si ces attributs ne veulent pas être pris en compte. C'est particulièrement le cas, si vous développez un composant graphique qui hérite d'une classe du cadriciel Swing.

Dans ce cas, utilisez l'annotation @NoRecursive.

Par exemple :

import fr.cemagref.ohoui.annotations.NoRecursive;

@NoRecursive
public class MyPanel extends JPanel {
   int size;
   //...

Dans cet exemple, seul l'attribut size sera affiché à l'utilisateur. Et les attributs de la classe JPanel ne seront pas examinés (tout comme les autres super-classes).

Restriction de la recherche de types

La fonctionnalité de recherche des types disponibles dans le cas de polymorphisme, recherche des types candidats dans tout le classpath par défaut. Pour limiter cette recherche qui peut aussi gourmande qu'inutile, ajouter ces lignes avant de faire appel à OhOUI :

import fr.cemagref.commons.modulesloader.ModulesLoader;

// ...

ModulesLoader.addModulesJAR("rt.jar");
ModulesLoader.addModulesPackageForJar("rt.jar","java.util");
ModulesLoader.addModulesPackageForJar("rt.jar","java.lang");
ModulesLoader.addModulesPackageForJar("rt.jar","java.io");

Attachments