Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction aux composants JTable, JTree et JGraph

Introduction aux composants JTable, JTree et JGraph

Support de cours concernant les composants JTable, JTree et JGraph qui permettent la visualisation d'informations avec le langage Java. Le support décrit comment modifier le rendu de l'affichage et le composant Editor (celui qui est utilisé pour effectuer une édition) et comment exploiter les différents modèles : modèle du composant et modèle de sélection notamment.

Mickael BARON

November 28, 2006
Tweet

More Decks by Mickael BARON

Other Decks in Programming

Transcript

  1. Java pour le développement de
    clients lourds
    Mickaël BARON - 2006 (Révision Août 2010)
    mailto:[email protected] ou mailto:[email protected]
    mickael-baron.fr
    mickaelbaron
    Visualisation d’informations : JTree, JTable et
    JGraph

    View full-size slide

  2. 2
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Creative Commons
    Contrat Paternité
    Partage des Conditions Initiales à l'Identique
    2.0 France
    http://creativecommons.org/licenses/by-sa/2.0/fr
    Licence

    View full-size slide

  3. 3
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    3
    À propos de l’auteur …
    † Mickaël BARON
    † Ingénieur de Recherche au LIAS
    † https://www.lias-lab.fr
    † Equipe : Ingénierie des Données et des Modèles
    † Responsable des plateformes logicielles, « coach » technique
    † Ancien responsable Java de Developpez.com (2011-2021)
    † Communauté Francophone dédiée au développement informatique
    † https://java.developpez.com
    † 4 millions de visiteurs uniques et 12 millions de pages vues par mois
    † 750 00 membres, 2000 forums et jusqu'à 5000 messages par jour
    mickael-baron.fr
    mickaelbaron

    View full-size slide

  4. 4
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : objets graphiques adaptés
    † Cette partie s’intéresse à présenter des composants en Java
    permettant la visualisation et la manipulation d’informations
    de grande quantité
    † Les informations peuvent être présentées sous forme de
    tableau, d’arbre ou de graphe
    † L’API Java Swing propose nativement deux composants
    complexes pour la visualisation d’informations
    † Tableau avec JTable
    † Arbre avec JTree
    † La représentation sous forme de graphe n’est pas encore
    proposée par Sun et nous utiliserons la bibliothèque
    † Graphe avec JGraph

    View full-size slide

  5. 5
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : objets graphiques adaptés
    Composant
    JTable
    Composant
    JTree
    Composant
    JGraph

    View full-size slide

  6. 6
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : objets graphiques adaptés
    † L’objectif principale de cette partie est de vous montrer
    comment paramétrer ces composants
    † Modification du rendu des informations
    † Modification du rendu d’édition
    † Ajout et suppression dynamique d’éléments
    † Manipulation des modèles (contenu et de sélection)
    † Technique de prévisualisation et zoom
    † Impression et génération d’images
    † Ressources
    † JTree : java.sun.com/docs/books/tutorial/uiswing/components/tree.hml
    † JTable : java.sun.com/docs/books/tutorial/uiswing/components/table.html
    † JGraph : www.jgraph.com
    Nous présenterons dans
    cette partie les choses à
    faire et à ne pas faire

    View full-size slide

  7. 7
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    M
    Visualisation d’informations : objets graphiques adaptés
    † Les composants complexes et d’autres composants respectent
    le modèle d’architecture MVC (Model View Controller)
    † L’implémentation proposée par Java/Swing se rapproche plus
    du Document/Vue ou Model/View (le contrôleur étant associé
    à la vue)
    † Principe de l’architecture
    † Le modèle est l’élément principale du composant
    † La ou les vue(s) du composant sont abonnées au modèle
    † La modèle notifie ses vues suite à des modifications
    La partie Document
    (En Java le vue et le
    contrôleur ne sont pas
    dissociés)
    La partie Modèle
    (Notification des vues
    après modification)
    V
    C

    View full-size slide

  8. 8
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : présentation générale
    † Avec le composant JTable vous pouvez afficher les données
    sous forme de table et éditer les données à partir des cellules
    † Un composant JTable doit être ajouté à un container
    JScollPane et non à un simple JPanel
    Les cellules sont éditables
    On peut ajouter des composants
    autre que des JLabel
    Les données par colonne
    sont typées et formatées
    JTable myTable = new JTable(...);
    JScrollPane myScrollPane = new JScrollPane(myTable);
    JScrollPane myScrollPane = new JScrollPane();
    myScrollPane.add(myTable);
    Affiche la JTable
    avec des
    ascenseurs si
    besoin
    La JTable n’est
    pas visible

    View full-size slide

  9. 9
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    † Le modèle JTable doit implémenter l’interface TableModel
    † Deux implémentations existent pour faciliter l’utilisation du
    modèle TableModel (méthodes supplémentaires)
    † La classe abstraite AbstractTableModel
    † La classe DefaultTableModel
    † Le fonctionnement du modèle dépend de l’implémentation
    des méthodes (ou redéfinition)
    † int getRowCount() : retourne le nombre de ligne
    † int getColumnCount() : retourne le nom de colonne
    † Object getValueAt(int row, int column) : retourne l’objet pour la cellule
    † setValueAt(Object, int row, int co) : nouvelle valeur de la cellule
    JTable : création du modèle
    Méthode abstraites dans la
    classe AbstractTableModel
    Vue
    JTable
    Modèle
    TableModel

    View full-size slide

  10. 10
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : création du modèle
    † Le fonctionnement du modèle dépend de l’implémentation
    des méthodes (suite)
    † Class getColumnClass(int cc) : type de la colonne
    † boolean isCellEditable(int r, int l) : indique si la cellule est modifiable
    † String getColumnName(int coIn) : nom de la colonne pour coIn
    † addTableModelListener(TableModelListener) : ajoute un écouteur qui
    est notifié à chaque fois que le modèle est modifié
    † Des méthodes (issues des sous-classes de TableModel) n’ont
    pas à être redéfinies et peuvent être utilisées
    † fireTableDataChanged() : notifie toutes les vues de modifications
    † fireTableRowsUpdated(int fr, int lr) : notifie entre les lignes fr et lr
    † L’interface TableModelListener contient une méthode
    † tableChanged(TableModelEvent e) : appelée à la suite de chaque
    modification du modèle

    View full-size slide

  11. 11
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : création du modèle
    † Exemple : une première JTable et son modèle
    public class MyTableModel extends AbstractTableModel {
    private String[] columnNames = ...
    private Object[][] data = ...
    public int getColumnCount() {return columnNames.length;}
    public int getRowCount() {return data.length;}
    public String getColumnName(int col) {return columnNames[col];}
    public Object getValueAt(int row, int col) {return data[row][col];}
    public Class getColumnClass(int c) {return getValueAt(0,c).getClass();}
    public boolean isCellEditable(int row, int col) {return (col < 2);}
    public void setValueAt(Object value, int row, int col) {
    data[row][col] = value;
    fireTableCellUpdated(row,col)
    }
    }
    public class MyTableDemo implements TableModelListener {
    public MyTableDemo() {
    JTable myTable = new JTable(new MyTableModel());
    myTable.getModel().addTableModelListener();
    ...
    }
    public void tableChanged(TableModelEvent e) {
    System.out.println("Coucou");
    }
    }
    Préférez ce mode de
    construction d’une
    JTable avec un modèle
    explicite
    Notification explicite
    des modifications
    aux vues
    Optimisation des notifications en
    choisissant le bon fire

    View full-size slide

  12. 12
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors et Renderers
    † Une JTable (JTree et JGraph fonctionnent un principe
    commun) dispose de classes spécifiques pour effectuer
    † un rendu des cellules appelée classe Renderer
    † une édition des données des cellules appelée classe Editor
    † Un objet Editor est appelé quand l’utilisateur effectue
    une action sur la cellule (sous condition que la cellule soit éditable)
    † Un objet Renderer est une vue sans réaction directe qui
    retourne une visualisation de la données de la cellule
    L’objet Editor associé à cette colonne
    affiche un JComboBox pour l’édition
    d’une chaîne de caractères
    L’objet Renderer
    utilisé pour cette
    cellule affiche un
    JLabel

    View full-size slide

  13. 13
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors et Renderers
    † Principe d’appel des objets Editor et Renderer
    Utilisateur déplace la fenêtre
    et sélectionne les cellules
    1
    Les renderers affiche les données
    du modèle getValueAt(…)
    Utilisateur clique sur
    une cellule éditable
    L’objet Editor est appelé. La
    valeur courante de la cellule est
    retournée à l’objet Editor
    2
    Utilisateur termine
    l’édition
    L’objet Editor retourne
    la nouvelle valeur qui
    est retournée au
    modèle
    setValueAt(…)
    3

    View full-size slide

  14. 14
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors et Renderers
    † Il existe par défaut des objets Editor et Renderer définis
    dans la JTable
    † Rappelons que getColumnClass() retourne le type de l’objet
    de la cellule
    † Selon le type de données se trouvant dans le modèle (indi-
    qué par getColumnClass()) les objets Editor et Renderer
    retournent des composants prédéfinis
    † Composant retourné par l’objet Renderer
    † Boolean : JCheckBox
    † Number, Double et Float : JLabel aligné à droite
    † ImageIcon : JLabel aligné au centre
    † Composant retourné par l’objet Editor
    † Boolean : JCheckBox
    † Autre : JTextField

    View full-size slide

  15. 15
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors et Renderers
    † Possibilité de modifier les objets Renderer et Editor de
    manière à paramétrer la visualisation et l’édition
    † La JTable propose plusieurs manières de modifier ces objets
    † Un Renderer et/ou Editor par type d’objet (Class)
    † Un Renderer et/ou Editor par colonne
    † Si vous souhaitez associer un Renderer et un Editor pour
    toutes les colonnes qui ont le même type utiliser la première
    solution
    † Si vous souhaitez effectuer un Renderer et un Editor ponctu-
    elle pour une colonne utilisez la seconde solution
    † Quelle que soit la solution les Renderer/Editor sont les
    mêmes. Seuls la liaison entre les Renderer/Editor et la
    JTable change
    † Nous présenterons les deux solutions …

    View full-size slide

  16. 16
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors et Renderers
    † Première solution : un Renderer/Editor par type d’objet
    † setDefaultRenderer(Class, TableCellRenderer) : associe un Renderer
    au type défini par le paramètre Class
    † setDefaultEditor(Class, TableCellEditor) : associe un Editor à un type
    † Toutes les colonnes dont le type est associé à un Renderer/Editor a
    une visualisation et/ou édition personnalisée
    † Deuxième solution : un Renderer/Editor par colonne
    † Extraire le modèle de colonne TableColumnModel getcolumnModel()
    † A partir du TablecolumnModel choisir la colonne qui vous intéresse à
    paramétrer : TableColumn getColumn(int)
    † Modifier le Renderer/Editor
    † setCellEditor(TableCellEditor) : associe l’Editor à la colonne
    † setCellRenderer(TableCellRenderer) : lie le Renderer à la colonne
    Si vous mixez les deux solutions c’est le
    Renderer/Editor par la colonne qui prend le dessus

    View full-size slide

  17. 17
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors et Renderers
    † Exemple : associer les Renderer/Editor à une JTable
    public class JTableDirectRenderer1 extends JFrame {
    public MyTableDemo() {
    ...
    JTable myTable = new JTable(new MyDefaultTableModel());
    myTable.setDefaultEditor(Integer.class, new MyAbstractCellEditor());
    myTable.setDefaultEditor(Boolean.class, new MyAbstractCellEditorBoolean());
    myTable.setDefaultRenderer(Boolean.class, new MyAbstractCellRenderer());
    TableColumnModel myColumnModel = myTable.getColumnModel();
    TableColumn myTableColumn = myColumnModel.getColumn(0);
    myTableColumn.setCellEditor(new MySecondAbstractCellEditor());
    myTableColumn.setCellRenderer(new TableCellRenderer() {
    public Component getTableCellRendererComponent(JTable, ...) {
    return new JButton((String)arg1);
    }
    });
    }
    }
    Modification des Editors pour les colonne
    dont la classe est de type Integer et
    Boolean
    Modification du
    Renderer pur la
    colonne Boolean
    Modification des Renderer/Editor
    pour la colonne 0

    View full-size slide

  18. 18
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Renderers
    † Un Renderer doit implémenter l’interface TableCellRenderer
    † Cette interface possède une méthode unique qui retourne le
    composant à afficher dans la cellule
    † Component getTableCellRendererComponent(JTable table, Object v,
    boolean isSelected, boolean hasFocus, int row, int column)
    † JTable table : référence de la JTable associé au Renderer
    † Object v : valeur à afficher du modèle obtenue par getValueAt(…)
    † boolean isSelected : la cellule est-elle sélectionnée ?
    † boolean hasFocus : la cellule a-t-elle le focus ?
    † int row : numéro de ligne de la cellule considérée
    † int column : numéro de colonne de la cellule considérée
    † Il faut donc retourner un objet graphique Component qui sera utilisé
    pour effectuer le rendu de la cellule
    Le composant de retour n’a pas de « réaction »
    il est utilisé pour effectuer un rendu = image

    View full-size slide

  19. 19
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Renderers
    † Exemple : un Renderer personnalisé pour les types Boolean
    public class MyAbstractCellRenderer implements TableCellRenderer {
    private JToggleButton vraie = new JToggleButton();
    public Component getTableCellRendererComponent(JTable arg0, Object arg1,
    boolean arg2, boolean arg3, int arg4, int arg5) {
    Boolean myBool = (Boolean )arg1;
    vraie.setSelected(myBool.booleanValue());
    return vraie;
    }
    }
    Le composant chargé du rendu est
    construit à la construction de la classe
    Récupère la valeur qui doit être
    affichée (getValueAt(…) du
    modèle)
    Modifie la valeur du composant et le
    retourne au Renderer pour affichage
    Le composant
    JCheckBox a été
    remplacé par un
    JToogleButton
    Le Renderer
    initial

    View full-size slide

  20. 20
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors
    † Un Editor doit implémenter l’interface TableCellEditor qui
    hérite également de l’interface CellEditor utilisée par tous les
    objets ayant un Editor : JTree, JTable, JListBox, …
    † Cette interface possède entre autre une méthode qui retourne
    le composant à afficher pour l’édition
    † Component getTableCellEditorComponent(JTable table, Object value,
    boolean isSelected, int row, int column)
    † JTable table : référence de la JTable associé à l’Editor
    † Object value : valeur de la cellule (pas uniquement un String)
    † boolean isSelected : la cellule est-elle sélectionnée
    † int row : numéro de ligne de la cellule
    † int column : numéro de la colonne
    † Pour éviter d’implémenter toutes les méthodes de l’interface
    CellEditor vous pouvez utiliser la classe AbstractCellEditor

    View full-size slide

  21. 21
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors
    † Si la classe AbstractCellEditor est utilisée en place de
    CellEditor certaines méthodes ont un comportement prédéfini
    † stopCellEditing() : déclenche l’arrêt de l’Editor
    † cancelCellEditing() : déclenche l’annulation de l’Editor
    † addCellEditorListener(CellEditorListener) : ajoute un écouteur d’édition
    † …
    † Cependant vous devrez fournir obligatoirement une
    implémentation de la méthode
    † Object getCellEditorValue() : la valeur que l’utilisateur vient de saisir
    (méthode setValueAt(…) du modèle est alors appelée)
    † Principe de codage
    † Implémentez getTableCellEditorComponent(…) pour retourner le
    composant d’édition
    † La validation du composant d’édition doit appeler stopCellEditing()
    † Implémentez getCellEditorValue()

    View full-size slide

  22. 22
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : Editors
    † Exemple : un Editor personnalisé pour les types Boolean
    public class MyAbstractCellEditorBoolean extends AbstractCellEditor implements
    TableCellEditor {
    private JToggleButton myButton = new JToggleButton();
    public MyAbstractCellEditorBoolean() {
    myButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e){
    MyAbstractCellEditorBoolean.this.fireEditingStopped();
    }
    });
    }
    public Object getCellEditorValue() {
    return new Boolean(myButton.isSelected());
    }
    public Component getTableCellEditorComponent(JTable arg0, Object arg1,
    boolean arg2, int arg3, int arg4) {
    Boolean myBool = (Boolean )arg1;
    myButton.setSelected(myBool.booleanValue());
    return myButton;
    }
    }
    L’action du bouton permet
    de valider la valeur qui vient
    d’être saisie
    Cette méthode retourne au
    modèle la nouvelle valeur
    (setValueAt(…) du modèle)
    L’initialisation du composant
    qui se charge de l’édition

    View full-size slide

  23. 23
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : modèle de sélection
    † Le modèle de sélection permet de gérer les aspects liés à la
    sélection de lignes ou de colonnes (une ou plusieurs …)
    † Un modèle de sélection doit implémenter l’interface appelée
    ListSelectionModel
    † Possibilité de modifier un modèle de sélection pour toutes les
    lignes et un modèle de sélection pour toutes les colonnes
    † JTable#setSelectionModel(ListSelectionModel) : modifie le modèle de
    sélection pour les lignes
    † TableColumnModel#setSelectionModel(ListSelectionModel) : modifie le
    modèle de sélection pour toutes les colonnes
    † Pour écouter le changement de sélection de lignes ou de
    colonnes ajoutez un écouteur sur le modèle de sélection
    † ListSelectionModel#addListSelectionListener(ListSelectionListener) :
    ajoute un écouteur de sélection

    View full-size slide

  24. 24
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : modèle de sélection
    † La définition explicite du modèle de sélection n’est utile que
    si vous souhaitez effectuer des traitements pointus sur les
    sélections
    † Pour le reste des aspects liés à la sélection utilisez les
    méthodes de la classe JTable qui pointent directement sur le
    modèle de sélection
    † setSelectionMode(int) : choix du modèle de sélection
    † SINGLE_SELECTION : une seule cellule peut-être sélectionnée
    † MULTIPLE_INTERVAL_SELECTION : plusieurs cellules sélection-
    nées à des moments différents
    † SINGLE_INTERVAL_SELECTION : plusieurs cellules sélectionnées
    en même temps
    † int getSelectedColumn() : indice de la colonne sélectionnée
    † int getSelectedRow() : indice de la ligne sélectionnée
    † clearSelection() : supprime la sélection actuelle

    View full-size slide

  25. 25
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : modèle de sélection
    † Trois différents modes de sélection
    Mode de sélection à
    SINGLE_SELECTION
    Mode de sélection à
    SINGLE_INTERVAL_SELECTION
    Mode de sélection à
    MULTIPLE_INTERVAL_SELECTION

    View full-size slide

  26. 26
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : modèle de sélection
    † Exemple : accès aux informations de la sélection courante
    public class JTableDirectRenderer2 extends JFrame {
    ...
    public JTableExemple() {
    ...
    myTable.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    System.out.println("Ligne:" + myTable.getSelectedRow());
    System.out.println("Colonne:" + myTable.getSelectedColumn());
    }
    });
    ...
    } ...
    Sortie « console »
    Réaction au clic sur la
    JTable
    Méthodes liées à la sélection disponibles
    directement dans la classe JTable

    View full-size slide

  27. 27
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : ajout et suppression dynamique
    † L’ajout et la suppression dynamique de ligne se fait en ajou-
    tant ou en supprimant des éléments au contenu sémantique
    de la JTable
    † Rappelons que la méthode getRowCount() et getValueAt(…)
    sont appelées pour « peupler » la table
    † Une solution est d’ajouter au modèle deux méthodes
    † addRow(Object p, int pRow) : ajoute l’objet p à la ligne pRow
    † removeRow(int pRow) : supprime la ligne pRow
    † Le modèle n’est pas à même de connaître la ligne d’ajout ou
    la ligne à supprimer tout dépend de la ligne sélectionnée
    † Ajout : ligne suivante de celle sélectionnée ou dernière ligne
    † Suppression : ligne en cours de sélection
    † A chaque ajout ou suppression d’une ligne n’oubliez pas de
    notifier la vue des modifications apportées au modèle

    View full-size slide

  28. 28
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : ajout et suppression dynamique
    † Exemple : ajout et suppression de ligne dans une JTable
    public class MyDefaultSecondTableModel extends AbstractTableModel {
    private ArrayList colonneName = new ArrayList();
    private ArrayList colonneLastName = new ArrayList();
    ...
    public void addNewRow(int ligne) {
    int addline = getRowCount();
    if (ligne != -1)
    addline = ligne +1;
    colonneName.add(addline, "Name");
    colonneLastName.add(addline, "First Name");
    ...
    this.fireTableStructureChanged();
    }
    public void removeNewRow(int ligne) {
    if (getRowCount() == 0 || ligne < 0)
    return;
    colonneName.remove(ligne);
    colonneLastName.remove(ligne);
    ...
    this.fireTableStructureChanged();
    }
    ...
    }
    Transformer les tableaux en
    ArrayList pour l’ajout
    dynamique des objets
    Une méthode pour
    ajouter des lignes
    Une méthode pour
    supprimer des
    lignes
    Notification à
    l’ensemble des vues
    pour avertir que le
    modèle a changé

    View full-size slide

  29. 29
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : ajout et suppression dynamique
    † Exemple (suite) : ajout et sup. de ligne dans une JTable
    public class JTableDirectRenderer3 extends JFrame {
    ...
    public JTableExemple() {
    JButton myAddButton = new JButton("Ajouter");
    myAddButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
    MyDefaultTableModel refModel = (MyDefaultTableModel)myTable.getModel();
    refModel.addNewRow(myTable.getSelectedRow());
    }
    });
    JButton myRemoveButton = new JButton("Supprimer");
    myRemoveButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
    MyDefaultTableModel refModel = (MyDefaultTableModel)myTable.getModel();
    refModel.removeNewRow(myTable.getSelectedRow());
    }
    });
    } ...
    Identifie le modèle
    du composant JTable
    Récupère l’indice de
    la lige sélectionnée
    Deux boutons pour ajouter
    ou supprimer des lignes

    View full-size slide

  30. 30
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTable : bilan
    JTable
    TableModel
    1
    ListSelectionModel
    1
    TableCellEditor
    TableCellRenderer
    1 .. >= Colonne 1 .. >= Colonne
    † Un composant JTable est une vue paramétrable qui permet
    d’afficher et modifier des données d’une table
    Paramétrage de
    l’affichage des
    données
    Modification des
    données
    Données du
    composant
    Sélection des
    données
    Grâce au pattern MVC de Java il est possible de
    brancher un modèle existant à une autre vue
    (voir le composant JGraph pour un exemple)
    TableModelListener
    0..n
    CellEditorListener
    0..n
    ListSelectionListener
    0..n
    Ecouteur pour avertir que
    l’édition est annulée ou validée
    Ecouteur pour
    avertir que le
    modèle a changé
    Ecouteur pour avertir
    que la sélection a
    changé

    View full-size slide

  31. 31
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : présentation générale
    † Avec le composant JTree vous pouvez afficher les données
    sous forme d’arbre, plier/déplier des nœuds et les éditer
    † Un composant JTree doit être ajouté à un container
    JScollPane et non à un simple JPanel
    Un nœud père qui contient
    quatre nœuds fils
    Le nœud racine, il est
    unique et ne possède pas
    de parent
    Un nœud feuille et fils du
    nœud « colors »
    Des icônes pour
    représenter l’état des
    nœuds
    JTree myTree = new JTree(...);
    JScrollPane myScrollPane = new JScrollPane(myTree);
    JScrollPane myScrollPane = new JScrollPane();
    myScrollPane.add(myTree);
    Affiche le
    JTree avec
    des
    ascenseurs si
    besoin
    Le JTree n’est pas visible dans ce cas là

    View full-size slide

  32. 32
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : gestion des noeuds
    † L’interface MutableTreeNode (hérite de TreeNode) fournit un
    service de gestion et de manipulation des données de l’arbre
    † Un MutableTreeNode modélise un nœud de l’arbre. La classe
    DefaultMutableTreeNode est une implémentation par défaut
    † add(MutableTreeNode p) : ajoute p comme dernier enfant noeud
    † int getChildCount() : retourne le nombre d’enfant du nœud
    † TreeNode getParent() : retourne le nœud parent
    † TreeNode getChildAt(int p) : retourne l’enfant de l’indice p
    † insert(MutableTreeNode child, int index) : ajout l’enfant à la position
    indice
    † remove(MutableTreeNode child) : supprime le nœud child
    † isLeaf() : le nœud est une feuille ou pas, …

    View full-size slide

  33. 33
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : gestion des noeuds
    † Chaque nœud peut contenir un objet utilisateur
    † setUserObject(Object object) : modifie l’objet du nœud
    † Object getUserObject() : récupère l’objet du nœud
    † Un objet DefaultMutableTreeNode peut être construit à partir
    d’un objet utilisateur : DefaultMutableTreeNode(Object user)
    † Par défaut, le texte affiché pour chaque nœud correspond à
    l’objet utilisateur retourné par sa méthode toString() (étudié
    plus en détail dans le Render/Editor du JTree)
    † Par comparaison avec la JTable l’objet utilisateur est l’objet
    retourné par getValueAt() du modèle
    † Un composant JTree affiche l’objet DefaultMutableTreeNode
    qui correspond au nœud racine appelé « root »

    View full-size slide

  34. 34
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : gestion des noeuds
    † Exemple : manipulation d’un objet DefaultMutableTreeNode
    public JTreeExample1() {
    DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Père de tous");
    DefaultMutableTreeNode childNode = new DefaultMutableTreeNode("Enfant Raoul");
    rootNode.add(childNode);
    childNode = new DefaultMutableTreeNode("Enfant Gasper");
    rootNode.add(childNode);
    childNode = new DefaultMutableTreeNode("Enfant Leon");
    rootNode.add(childNode);
    DefaultMutableTreeNode childChildNode = new DefaultMutableTreeNode("Petit Leon");
    childNode.add(childChildNode);
    childChildNode = new DefaultMutableTreeNode("Petit Leon second");
    childNode.add(childChildNode);
    System.out.println("Nombre d'enfants : " + rootNode.getChildCount());
    System.out.println("Nombre d'enfants ayant des petits enfants : " +
    rootNode.getSiblingCount());
    System.out.println("Objet du noeud racine : " + rootNode.getUserObject());
    rootNode.setUserObject("Père de tous M");
    JTree myJTree = new JTree(rootNode);
    JScrollPane myScrollPane = new JScrollPane(myJTree);
    this.getContentPane().add(myScrollPane());
    ...
    }
    }
    Ajout de nœuds dans le
    nœud racine
    Les nœuds sont
    construits avec un objet
    utilisateur de type
    String

    View full-size slide

  35. 35
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : création du modèle
    † Le modèle d’un JTree propose un ensemble de fonction-
    nalités pour manipuler les nœuds de l’arbre
    † Le point de départ du modèle est le nœud « root ». En effet
    un modèle pour un JTree est construit avec le nœud racine
    † L’interface TreeModel s’occupe de décrire le modèle de
    l’arbre. DefaultTreeModel est une implémentation par défaut
    † DefaultTreeModel(TreeNode p) : modèle avec un nœud racine
    † Object getChild(Object parent, int index) : retourne l’enfant de l’indice
    index du parent parent
    † int getchildCount(Object parent) : nombre d’enfants de parent
    † Object getRoot() : retourne le nœud racine de l’arbre
    † boolean isLeaf(Object node) : détermine node est une feuille
    Les objets en paramètre et en retour ne sont pas des
    MutableTreeNode. Vous pouvez proposez votre structure
    en implémentant votre propre modèle (TreeModel)

    View full-size slide

  36. 36
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : création du modèle
    † Les méthodes du modèle sont utilisées de la même manière
    que celles du modèle de la JTable
    † Principe de fonctionnement
    † la méthode getChildCount(…) détermine le nombre d’enfant du nœud
    † la méthode getChild(…) pour le même parent sera appelée autant de
    fois que la valeur retournée par getChildCount(…)
    † En plus des méthodes d’interrogation des nœuds il est
    possible d’écouter les modifications du modèle
    † addTreeModelListener(TreeModelListener l) : ajouter un écouteur
    † treeNodesChanged(TreeNodeEvent) : un nœud a été changé (le
    contenu)
    † treeStructureChanged(TreeNodeEvent) : un nœud a été déplacé
    † …
    Les méthodes d’ajout et de
    suppression seront vues plus loin

    View full-size slide

  37. 37
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : création du modèle
    † Exemple : ne montrer que les enfants du nœud racine
    public MyTreeModel extends DefaultTreeModel {
    public MyTreeModel(MutableTreeNode p) {
    super(p);
    }
    public Object getChild(Object arg0, int arg1) {
    return ((DefaultMutableTreeNode) arg0).getChildAt(arg1);
    }
    public int getChildCount(Object arg0) {
    if (arg0 != root)
    return 0;
    DefaultMutableTreeNode myTreeNode = (DefaultMutableTreeNode) arg0;
    return myTreeNode.getChildCount();
    }
    public boolean isLeaf(Object arg0) {
    if (arg0 == root)
    return false;
    }
    return true;
    }
    }
    JTree myTree = new JTree(new MyTreeModel(root));
    JScrollPane myScrollPane = new JScrollPane(myTable);
    ...
    Ne pas oublier de donner le
    nœud racine au modèle
    Pour chaque nœud on
    compte le nombre
    d’enfants
    Détermine si le nœud
    est une feuille ou pas

    View full-size slide

  38. 38
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Editors et Renderers
    † Un JTree dispose de classes spécifiques pour effectuer
    † Un rendu des noeuds appelée classe Renderer
    † Une édition des données des noeuds appelée classe Editor
    † Un objet Editor est appelé quand l’utilisateur effectue une
    action d’édition sur le noeud (sous condition que le nœud soit
    éditable)
    † Un objet Renderer est une vue sans réaction directe qui
    retourne une visualisation du nœud (objet utilisateur)
    L’objet Renderer
    utilisé par défaut est
    un JLabel
    L’objet Editor utilisé
    par défaut est un
    JTextField

    View full-size slide

  39. 39
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Editors et Renderers
    † Principe d’appel des objets Editor et Renderer
    Utilisateur déplace la fenêtre
    et sélectionne un noeud
    Le Renderer affiche les données
    de chaque MutableTreeNode
    Utilisateur clique sur un
    noeud éditable
    L’objet Editor est appelé. La
    valeur courante du noeud est
    retournée à l’objet Editor.
    Utilisateur termine
    l’édition
    L’objet Editor retourne
    la nouvelle valeur qui
    est transmise au
    MutableTreeNode
    éditée
    3
    1
    2

    View full-size slide

  40. 40
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Editors et Renderers
    † Le composant JTree ne manipule pas de ligne ni de colonne
    comme un composant JTable
    † A la différence du composant JTable les objets Renderer et
    Editor sont applicables à tous les nœuds de l’arbre
    † JTree#setCellRenderer(TreeCellRenderer) : modifie un objet Renderer
    † JTree#setCellEditor(TreeCellEditor) : modifie un objet Editor
    public class JTreeExample3 extends JFrame {
    public MyJTree() {
    ...
    JTree myTree = new JTree(new MyDefaultTreeModel());
    JScrollPane myScrollPane = new JScrollPane(myTree);
    myTree.setCellRenderer(new MyTreeCellRenderer());
    myTree.setCellEditor(new MyTreeCellEditor());
    ...
    }
    }
    Modification de l’Editor de l’objet
    myTree
    Modification du Renderer de
    l’objet myTree

    View full-size slide

  41. 41
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Renderers
    † Un Renderer doit implémenter l’interface TreeCellRenderer
    † Cette interface possède une méthode unique qui retourne le
    composant à afficher dans la cellule
    † Component getTreeCellRendererComponent(JTree tree, Object v,
    boolean isSel, boolean exp, boolean leaf, int row, boolean hFocus)
    † JTree tree : référence de la JTree associé au Renderer
    † Object v : le nœud en cours de rendu
    † boolean isSel : le nœud est-il sélectionné ?
    † boolean exp : le nœud est-il déplié ?
    † boolean leaf : le nœud est-il une feuille
    † int row : le numéro d’indice de l’enfant
    † boolean hFocus : le composant à la focus
    † Il faut donc retourner un objet graphique Component qui sera utilisé
    pour effectuer le rendu du noeud
    Le composant de
    retour n’a pas de
    « réaction » il est
    utilisé pour effectuer
    un rendu = image

    View full-size slide

  42. 42
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Renderers
    † Exemple : un Renderer personnalisé
    public class MyDefaultTreeCellRenderer implements TreeCellRenderer {
    public Component getTreeCellRendererComponent(JTree tree, Object value,
    boolean selected, boolean expanded, boolean leaf, int row, boolean
    hasFocus) {
    JLabel myLabel = new JLabel();
    JLabel labelExpanded = new JLabel();
    if (value instanceof DefaultMutableTreeNode) {
    DefaultMutableTreeNode myNode = (DefaultMutableTreeNode)value;
    String infoText = "- ";
    if (selected)
    infoText += "S ";
    if (leaf)
    myLabel.setIcon(new ImageIcon("middle.gif"));
    else
    myLabel.setIcon(new ImageIcon("pig.gif"));
    if (expanded)
    labelExpanded.setIcon(new ImageIcon("exp.gif"));
    else
    labelExpanded.setIcon(new ImageIcon("nexp.gif"));
    infoText += " L :" + row + " - ";
    infoText += (String)myNode.getUserObject();
    myLabel.setText(infoText);
    }
    JPanel myPanel = new JPanel(new BorderLayout());
    myPanel.add(BorderLayout.WEST,labelExpanded);
    myPanel.add(BorderLayout.CENTER,myLabel);
    return myPanel;
    }
    L’objet envoyé au Renderer est un
    objet de type MutableTreeNode
    Nous retournons ici un
    composant JPanel (par défaut il
    s’agit d’un composant JLabel)

    View full-size slide

  43. 43
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Editors
    † Un Editor doit implémenter l’interface TreeCellEditor qui
    hérite également de l’interface CellEditor
    † Cette interface possède entre autre une méthode qui
    retourne le composant à afficher pour l’édition
    † Component getTreeCellEditorComponent(JTree tree, Object value,
    boolean isSelected, boolean expanded, boolean leaf, int row)
    † JTree tree : référence de la JTree associé à l’Editor
    † Object value : objet MutableTreeNode en cours d’édition
    † boolean isSelected : le noeud est-il sélectionné ?
    † boolean expanded : le nœud est-il déplié ?
    † boolean leaf : le nœud est-il une feuille ?
    † int row : le numéro d’indice de l’enfant
    † Pour éviter d’implémenter toutes les méthodes de l’interface
    CellEditor vous pouvez utiliser la classe
    AbstractCellEditor

    View full-size slide

  44. 44
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Editors
    † Si la classe AbstractCellEditor est utilisée en place de
    CellEditor certaines méthodes ont un comportement prédéfini
    † stopCellEditing() : déclenche l’arrêt de l’Editor
    † cancelCellEditing() : déclenche l’annulation de l’Editor
    † addCellEditorListener(CellEditorListener) : ajoute un écouteur d’édition
    † …
    † Cependant vous devrez fournir obligatoirement une implémen-
    tation de la méthode
    † Object getCellEditorValue() : retourne la valeur que l’utilisateur vient de
    saisir (la méthode setUserObject(…) du nœud est alors appelée)
    † Principe de codage
    † Implémentez getTreeCellEditorComponent(…) pour retourner le
    composant d’édition
    † La validation du composant d’édition doit appeler stopCellEditing()
    † Implémentez getCellEditorValue()

    View full-size slide

  45. 45
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : Editors
    † Exemple : un Editor personnalisé
    public class MyDefaultTreeCellEditor extends AbstractCellEditor
    implements TreeCellEditor, ActionListener {
    private JPanel myPanel;
    private JTextField myText;
    public MyDefaultTreeCellEditor() {
    myPanel = new JPanel();
    JLabel myLabel = new JLabel("Edition :");
    myText = new JTextField(10);
    myText.addActionListener(this);
    myPanel.setLayout(new BorderLayout());
    myPanel.add(BorderLayout.WEST, myLabel);
    myPanel.add(BorderLayout.CENTER, myText);
    }
    public Component getTreeCellEditorComponent(JTree tree, Object value,
    boolean isSelected, boolean expanded, boolean leaf, int row) {
    if (value instanceof DefaultMutableTreeNode) {
    DefaultMutableTreeNode ob = (DefaultMutableTreeNode)value;
    myText.setText((String)ob.getUserObject());
    }
    return myPanel;
    }
    public Object getCellEditorValue() {
    return myText.getText();
    }
    public void actionPerformed(ActionEvent arg0) {
    this.stopCellEditing();
    }
    }
    La méthode qui renvoie la
    nouvelle valeur de
    l’utilisateur au nœud édité
    setUserObject(…)
    La valeur éditée
    est celle de
    l’objet utilisateur

    View full-size slide

  46. 46
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : modèle de sélection
    † Le modèle de sélection permet de gérer les aspects liés à la
    sélection de nœuds (un ou plusieurs)
    † Un modèle de sélection doit implémenter l’interface appelée
    TreeSelectionModel
    † Possibilité de modifier ou de récupérer un modèle de sélection
    d’un composant JTree
    † setSelectionModel(TreeSelectionModel) : modifie le modèle de
    sélection
    † TreeSelectionModel getSelectionModel() : récupère le modèle de
    sélection
    † Pour écouter le changement de sélection de nœuds ajoutez
    un écouteur sur le modèle de sélection
    † addTreeSelectionListener(TreeSelectionListener) : ajoute un écouteur
    de sélection

    View full-size slide

  47. 47
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : modèle de sélection
    † La modification du modèle de sélection n’est utile que si vous
    effectuer des traitements pointus sur les sélections
    † Curieusement certaines méthodes proposées directement par
    la classe JTable ne se retrouvent pas dans la classe JTree
    † setSelectionMode(int) : choix du modèle de sélection
    † SINGLE_TREE_SELECTION : un seul noeud sélectionné
    † CONTIGUOUS_TREE_SELECTION : plusieurs noeuds sélectionnés
    directement liés (lien de voisinage)
    † DISCONTIGUOUS_TREE_SELECTION : plusieurs nœuds sélection-
    nés indirectement liés
    † TreePath getSelectionPath() : retourne le chemin du nœud sélectionné
    † TreePath[] getSelectionPaths() : retourne les chemins des nœuds
    sélectionnés
    Méthodes disponibles à la fois dans la
    classe JTree et TreeSelectionModel

    View full-size slide

  48. 48
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : modèle de sélection
    † Trois différents modes de sélection
    Mode de sélection à
    SINGLE_TREE_SELECTION
    Mode de sélection à
    CONTIGUOUS_TREE_SELECTION
    Mode de sélection à
    DISCONTIGOUS_TREE_SELECTION

    View full-size slide

  49. 49
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : modèle de sélection
    † Les méthodes qui permettent de récupérer le ou les nœuds
    sélectionné(s) retournent un objet TreePath
    † Un objet TreePath est une sorte de chemin des objets de la
    racine jusqu’aux objets du nœud sélectionné
    † Les objets sont normalement des MutableTreeNode
    † Exemples : « Père de tous », « Enfant Leon » et « Petit Leon »
    Nœud feuille à l’indice 2
    Nœud père à l’indice 1
    Nœud racine à l’indice 0

    View full-size slide

  50. 50
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : modèle de sélection
    † La classe TreePath possède des méthodes qui permettent
    d’extraire du ou des chemins sélectionné(s) les nœuds
    intéressants
    † Object getLastPathComponent() : objet correspondant au dernier
    nœud sélectionné (normalement de type MutableTreeNode)
    † Object getPathComponent(int elem) : objet du nœud à l’indice elem.
    La tête du chemin correspond à l’indice zéro
    † TreePath getParentPath() : nouveau chemin excepter le dernier nœud
    † int getPathCount() : nombre de nœuds inclus dans ce chemin
    † …
    Les objets récupérés peuvent
    être « castés » en une classe de
    type MutableTreeNode

    View full-size slide

  51. 51
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : modèle de sélection
    † Exemple : accès aux informations de la sélection courante
    ...
    myJTree.addTreeSelectionListener(new TreeSelectionListener(){
    public void valueChanged(TreeSelectionEvent tse) {
    TreePath myPath = myJTree.getSelectionPath();
    DefaultMutableTreeNode myMutable =
    (DefaultMutableTreeNode)myPath.getPathComponent(0);
    System.out.println("Racine" + myMutable);
    System.out.println("Sélection" +
    (DefaultMutableTreeNode)myPath.getLastPathComponent());
    }
    });
    ...

    View full-size slide

  52. 52
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : ajout et suppression dynamique
    † Pour ajouter ou supprimer des nœuds dans un JTree, il suffit
    de manipuler les nœuds parents en ajoutant ou supprimant
    des nœuds enfants (par défaut la structure est de type
    MutableTreeNode)
    † add(MutableTreeNode child) : ajoute le nœud child en dernière position
    † insert(MutableTreeNode child, int childIndex) : ajoute le nœud child à
    la position childIndex
    † remove(int child) : supprime le nœud à l’indice child
    † remove(MutableTreeNode child) : supprime le nœud child
    † La classe DefaultTreeModel propose des méthodes qui réalise
    la même chose
    † insertNodeInto(MutableTreeNode child, MutableTreeNode par, int ind) :
    ajoute le nœud child à l’indice ind au nœud par
    † removeNodeFromParent(MutableTreeNode c) : supprime le nœud c

    View full-size slide

  53. 53
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : ajout et suppression dynamique
    † Etapes pour ajouter ou supprimer un nœud
    † Connaître le nœud parent dans lequel ce nœud va être ajouté (sélec-
    tion ou au début/fin d’un nœud particulier)
    † Extraction de l’objet TreePath le futur nœud parent
    † Ajouter ou supprimer au futur nœud parent le nouveau sous nœud
    † Mettre à jour le modèle pour qu’il puisse notifier la ou les vues des
    changements effectués
    † Déplier complètement l’arborescence du nouveau noeud (par
    défaut les nouveaux nœuds ne sont pas dépliés)
    † JTree#scrollPathToVisible(TreePath p) : déplier un chemin
    † Avertir le modèle d’un éventuel changement (ajout, suppression,
    modification d’objet, …)
    † DefaultTreeModel#reload() : recharge le modèle
    † DefaultTreeModel#reload(TreeNode node) : recharge le modèle
    par le dessous du nœud node

    View full-size slide

  54. 54
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : ajout et suppression dynamique
    † Exemple : ajouter, supprimer et tout supprimer …
    ...
    JButton add = new JButton("Ajouter");
    add.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    TreePath myPath = myJTree.getSelectionPath();
    DefaultMutableTreeNode myParent =
    (DefaultMutableTreeNode)myPath.getLastPathComponent();
    DefaultMutableTreeNode mySon = new DefaultMutableTreeNode("Coucou");
    myParent.add(mySon);
    myJTree.scrollPathToVisible(new TreePath(mySon.getPath()));
    ((DefaultTreeModel)myJTree.getModel()).reload(myParent);
    }
    });
    JButton remove = new JButton("Supprimer");
    remove.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    TreePath myPath = myJTree.getSelectionPath();
    DefaultMutableTreeNode myParent=
    (DefaultMutableTreeNode)(myPath.getParentPath().getLastPathComponent());
    DefaultMutableTreeNode mySon=
    (DefaultMutableTreeNode)myPath.getLastPathComponent();
    myParent.remove(mySon);
    ((DefaultTreeModel)myJTree.getModel()).reload(myParent);
    }
    });

    View full-size slide

  55. 55
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : ajout et suppression dynamique
    † Exemple (suite) : ajouter, supprimer et tout supprimer …
    ...
    JButton removeAll = new JButton("Tout supprimer");
    removeAll.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    ((DefaultMutableTreeNode)myJTree.getModel().getRoot()).removeAllChildren();
    ((DefaultTreeModel)myJTree.getModel()).reload();
    }
    });
    Tous les enfants ont
    été supprimés du
    nœud racine
    Mise à jour du modèle
    après modification

    View full-size slide

  56. 56
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JTree : bilan
    JTree
    TreeModel
    1
    TreeSelectionModel
    1
    TreeCellEditor
    TreeCellRenderer
    1
    † Un composant JTree est une vue paramétrable qui permet
    d’afficher et modifier des données d’un arbre
    Paramétrage de
    l’affichage des
    données
    Modification des
    données
    Données du
    composant
    Sélection des
    données
    Grâce au pattern MVC de Java il est possible de
    brancher un modèle existant à une autre vue
    (voir le composant JGraph pour un exemple)
    TreeModelListener
    0..n
    CellEditorListener
    0..n
    TreeSelectionListener
    0..n
    Ecouteur pour avertir que
    l’édition est annulée ou validée
    Ecouteur pour
    avertir que le
    modèle a changé
    Ecouteur pour avertir
    que la sélection a
    changé
    1

    View full-size slide

  57. 57
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : présentation générale
    † Un graphe est un cas particulier d’arbre où les nœuds
    peuvent posséder plusieurs parents disjoints ou pas
    † L’API Swing ne propose pas par défaut de composant
    permettant de représenter des graphes
    † Utilisation de l’API externe JGraph
    † Site : www.jgraph.com
    † Elle fonctionne suivant un principe commun aux composants
    JTable et JTree dans le sens où elle se fonde sur l’architecture
    MVC
    † De nombreux outils utilisent cette bibliothèque et dont la
    licence est libre d’utilisation sous condition de fournir les
    sources
    † Documentation (Tutorial) payante mais JavaDoc ainsi qu’un
    Forum sont disponibles gratuitement

    View full-size slide

  58. 58
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : présentation générale

    View full-size slide

  59. 59
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : présentation générale

    View full-size slide

  60. 60
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : présentation générale
    † Avec le composant JGraph vous pouvez afficher les données
    sous forme de graphe
    † Démonstration : www.jgraph.com
    Un lien « edge »
    avec du texte
    Un lien « edge »
    sans texte
    Une cellule « cell »
    avec un couleur et
    du texte
    Un groupe « group »
    qui regroupe 2
    cellules et un lien
    Un port
    « port » de
    connexion
    pour le lien
    ou point
    d’attache

    View full-size slide

  61. 61
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : présentation générale
    † L’API de JGraph propose de nombreuses caractéristiques
    † Déplacement, re-dimensionnement et sélection des objets
    † Agrandissement/Réduction de la vue du graphe
    † Grille avec modification du pas
    † Courbe de Bezier et Spline pour les liens, …
    † Des caractéristiques sont manquantes (présentées dans ce cours)
    † Aperçu avec positionnement manuel sur le graphe
    † Impression évoluée avec plusieurs pages
    † Un composant JGraph doit être ajouté à un container
    JScollPane et non à un simple JPanel
    JGraph myGraph = new JGraph();
    JScrollPane myScrollPane = new JScrollPane(myGraph);
    JScrollPane myScrollPane = new JScrollPane();
    myScrollPane.add(myGraph);
    Affiche le
    JGraph avec
    des ascenseurs
    si besoin
    Le JGraph n’est pas visible dans ce cas là

    View full-size slide

  62. 62
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Tout composant dans un JGraph est considéré comme un
    objet de type GraphCell
    † Nous distinguons trois types d’objets
    † Cellule ou groupe (la donnée à afficher ou les objets à regrouper)
    † Lien (objet graphique qui relie deux cellules)
    † Port (objet graphique qui sert d’ancre entre une cellule à un lien)

    View full-size slide

  63. 63
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Un objet de type GraphCell a également le comportement
    d’un objet MutableTreeNode et plus spécifiquement de type
    DefaultMutableTreeNode (utilisé dans JTree)
    † Utilisation des fonctionnalités de la classe MutableTreeNode
    † Une cellule peut contenir un sous ensemble de point d’attache (Port) et
    peut-être un enfant d’un groupe
    † Un groupe peut avoir comme enfants des cellules, des liens (Edge)
    et/ou des sous-groupes. Un groupe peut donc être un enfant d’un
    groupe
    † Un lien peut-être un enfant d’un groupe
    † Un point d’attache peut-être un enfant d’une cellule (petit fils d’un
    groupe)
    † Les aspects liés aux connexions des liens (quels sont les ports
    connectés) ne sont pas modélisés par les
    MutableTreeNode

    View full-size slide

  64. 64
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Relation entre un lien et les cellules A et B
    Une cellule B qui
    contient un point
    d’ancrage b
    Une cellule A qui
    contient un point
    d’ancrage a
    La racine est
    obligatoirement
    un groupe
    Un port contient une
    référence à son parent
    (cellule) MutableTreeNode
    Un port contient également une
    référence à l’ensemble de liens
    connectés à ce port HashSet
    Un lien entre la
    cellule A et B Une cellule a accès à
    l’ensemble de ses sous
    enfants (port)
    MutableTreeNode
    Un lien a un accès au référence
    du port a et du port b

    View full-size slide

  65. 65
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † La structure proposée par JGraph permet un accès directe
    aux objets d’un graphe
    † L’accès à une cellule, un groupe, un lien ou un port donne la
    possibilité d’extraire n’importe quelle référence d’un objet du
    graphe
    † Différentes possibilités d’extraction de référence
    † Lien : accès aux références du port source et cible et éventuellement
    du groupe
    † Port : accès à la référence de la cellule et de l’ensemble des liens
    † Cellule : accès aux références des ports et éventuellement du groupe
    † Groupe : accès aux références des cellules et des liens

    View full-size slide

  66. 66
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Un groupe ou une cellule doivent être construits à partir d’un
    objet de type DefaultGraphCell
    † Outre les méthodes fournies par DefautMutableTreeNode la
    classe DefaultGraphCell propose uniquement des méthodes
    pour modifier des attributs des objets (cellule, port et lien)
    † AttributeMap getAttributes() : retourne les propriétés d’une cellule
    † setAttributes(AttributeMap attributes) : modifie les attributs
    † La modification et l’interrogation des attributs propre à
    JGraph se font différents des autres composants Swing

    View full-size slide

  67. 67
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Tous les attributs sont stockés dans un objet de type
    AttributeMap qui est une table de hachage HashTable
    † Rappelons que pour accéder à une valeur d’une HashTable il
    faut y accéder à l’aide d’une clé
    Clé key1
    pour
    accéder à la
    valeur val1
    † L’ensemble des clés des attributs des objets JGraph sont
    définies dans la classe GraphConstants
    † Pour chaque clé un accesseur et un modifieur ont été définies
    dans la classe GraphConstants

    View full-size slide

  68. 68
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Création d’une nouvelle cellule avec association d’un attribut
    // Création d’une cellule
    DefaultGraphCell myCell = new DefaultGraphCell();
    // Création d’une HashTable pour contenir les attributs.
    Map myHashTable = new HastTable();
    // Modification de l’attribut position et taille
    myHashTable.put(GraphConstants.BOUNDS, new Rectangle2D.Double(120, 25, 25, 25));
    // Même chose en passant par le modifieur
    GraphConstants.setBounds(map, new Rectangle2D.Double(120, 25, 25, 25));
    // Associer les nouveaux attributs (pour l’instant un seul) à la cellule
    myCell.setAttributes(new AttributeMap(myHashTable));
    Préférez l’utilisation des modifieurs et des
    accesseurs puisqu’elles typent les
    paramètres et les valeurs de retour

    View full-size slide

  69. 69
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : gestion des cellules
    † Modification d’un attribut d’une cellule
    // Création d’une HashTable pour contenir les attributs.
    Map myHashTable = myCell.getAttributes();
    // Modification de l’attribut Bounds en passant par le modifieur
    GraphConstants.setBounds(map, new Rectangle2D.Double(120, 25,25,25));
    // Associer les nouveaux attributs (pour l’instant un seul) à la cellule
    myCell.setAttributes(new AttributeMap(myHashTable));
    † Interrogation d’un attribut d’une cellule
    // Création d’une HashTable pour contenir les attributs.
    Map myHashTable = myCell.getAttributes();
    // Même chose en passant le modifieur
    Rectangle2D myRectangle = GraphConstants.getBounds(map);
    // Afficher les informations
    System.out.println(myRectangle.getX());
    System.out.println(myRectangle.getY());
    System.out.println(myRectangle.getWidth());
    System.out.println(myRectangle.getHeight());

    View full-size slide

  70. 70
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : DefaultPort
    † La gestion des points d’ancrage est réalisé par un objet de
    type DefaultPort
    † Un objet DefaultPort, s’il est associé à une cellule, permet de
    connaître son objet parent : une cellule
    † Un objet DefaultPort, s’il est relié à un ou des liens, permet
    d’accéder aux différents liens
    † La classe DefaultPort possède plusieurs méthodes
    † Set getEdges() : retourne les liens associés à ce point d’ancrage
    † addEdge(Object edge) : curieusement cette méthode ne donne pas
    l’effet désiré (voir plus loin pour l’ajout de lien)

    View full-size slide

  71. 71
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : DefaultPort
    † Exemple : ajout de deux points d’ancrage à une cellule
    // Création de la cellule
    DefaultGraphCell myCell = new DefaultGraphCell("Coucou");
    // Création des deux ports ou points d’ancrage
    DefaultPort myFirstPort = new DefaultPort();
    DefaultPort mySecondPort = new DefaultPort();
    // Ajout des points d’ancrage à la cellule
    myCell.add(myFirstPort);
    myCell.add(mySecondPort);
    L’aspect graphique sera vu dans la suite.
    On pourra définir la forme et
    l’emplacement des points d’ancrage

    View full-size slide

  72. 72
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : DefaultEdge
    † Les liens entre des cellules sont réalisés par l’intermédiaire
    d’un objet de type DefaultEdge
    † Un lien est connecté aux cellules par l’intermédiaire de leur
    point d’ancrage
    † L’API de la classe DefaultEdge permet
    † Object getSource() : le point d’ancrage source
    † Object getTarget() : le point d’ancrage cible
    † Il est possible de modifier les caractéristiques d’un lien en
    modifiant par exemple la forme du trait de liaison
    † La classe GraphConstants fournit des clés pour modifier la
    forme du point de départ et d’arrivée

    View full-size slide

  73. 73
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : DefaultEdge
    † Exemple : connexion d’un lien à deux cellules
    // Création de la cellule
    DefaultGraphCell myCell = new DefaultGraphCell("Coucou");
    // Création des deux ports ou points d’ancrage
    DefaultPort myFirstPort = new DefaultPort();
    DefaultPort mySecondPort = new DefaultPort();
    // Ajout des points d’ancrage à la cellule
    myCell.add(myFirstPort);
    myCell.add(mySecondPort);
    // Création d’un objet lien
    DefaultEdge myEdge = new DefaultEdge();
    // Associer lien aux points d’ancrage
    myGraph.getGraphLayoutCache().insertEdge(myEdge,
    myFirstPort, mySecondPort);
    Sera vu plus tard dans
    la partie des vues
    Création d’un lien entre les
    points d’ancrage myFirstPort
    et mySecondPort

    View full-size slide

  74. 74
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : DefaultEdge
    † Exemple : modification des attributs d’un lien
    ...
    // Création d’un objet lien
    DefaultEdge myEdge = new DefaultEdge();
    // Modification des attributs du lien
    myHashTable = myEdge.getAttributes();
    GraphConstants.setLineBegin(myHashTable, GraphConstants.ARROW_CIRCLE);
    GraphConstants.setLineEnd(myHashTable, GraphConstants.ARROW_DIAMOND);
    myEdge.setAttributes(new AttributeMap(myHashTable));
    // Ajout du noeud
    myGraph.getGraphLayoutCache().insertEdge(myEdge, myFirstPort, mySecondPort);
    Le début et la fin du
    lien ont été modifié
    La cellule contient un
    port qui est centré
    L’apparence du lien a
    été modifiée

    View full-size slide

  75. 75
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : modèle
    † Un modèle d’un composant JGraph doit implémenter
    l’interface GraphModel
    † On utilisera la classe DefaultGraphModel qui propose une
    implémentation par défaut
    † Un modèle DefaultGraphModel offre une API pour interroger
    les entités du graphe
    † List getRoots() : récupère l’ensemble des objets racines
    † int getRootCount() : donne le nombre total d’objets racines
    † Object getRootAt(int index) : récupère l’objet racine à l’indice index
    † Nombreuses méthodes statiques
    † …

    View full-size slide

  76. 76
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : modèle
    † Exemple : extrait les objets racines du modèle
    // Création de la cellule
    DefaultGraphCell myCell = new DefaultGraphCell("Coucou");
    // Création des deux ports ou points d’ancrage
    DefaultPort myFirstPort = new DefaultPort();
    DefaultPort mySecondPort = new DefaultPort();
    // Ajout des points d’ancrage à la cellule
    myCell.add(myFirstPort);
    myCell.add(mySecondPort);
    // Création d’un objet lien
    DefaultEdge myEdge = new DefaultEdge();
    // Associer lien aux points d’ancrage
    myGraph.getGraphLayoutCache().insertEdge(myEdge, myFirstPort,mySecondPort);
    for (int i = 0; i < myGraph.getModel().getRootCount(); i++) {
    System.out.println(myGraph.getModel().getRootAt(i).getClass());
    }
    Les objets DefaultPort
    ne sont pas des objets
    racines du graphe

    View full-size slide

  77. 77
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † La gestion de la vue sous JGraph est différente des autres
    composants Swing
    † Il est possible d’associer pour chaque objet de type GraphCell
    une vue et par conséquent un « Renderer » et un « Editor »
    spécifiques
    † Le composant JTree n’autorise qu’une seule vue et par
    conséquent un seul « Renderer » et « Editor »
    † Le composant JTable peut autoriser une vue par colonne ou
    une vue par type de données
    † L’ensemble des vues d’un composant JGraph permet d’obtenir
    la visualisation complète du graphe

    View full-size slide

  78. 78
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † L’objet de type GraphLayoutCache permet de réaliser la
    relation ou « mapping » entre le modèle et les vues
    † La classe GraphLayoutCache fournit également de
    nombreuses méthodes permettant d’ajouter notamment des
    cellules, des liens, …
    † insert(Object cell) : ajoute une cellule dans le graphe
    † insertEdge(Object edge, Object source, Object target) : ajoute un lien
    edge aux points d’ancrage source et target
    † insertGroup(Object group, Object[] children) : ajoute un groupe à
    partir des sous éléments children

    View full-size slide

  79. 79
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † L’objet GraphLayoutCache est associé à l’objet JGraph et
    peut-être récupéré ou créé
    † GraphLayoutCache JGraph#getGraphLayoutCache() : retourne l’objet
    GraphLayoutCache contenu dans l’objet JGraph
    † JGraph#setGraphLayoutCache(GraphLayoutCache p) : modifie l’objet
    GraphLayoutCache du JGraph
    † L’intérêt de modifier l’objet de type GraphLayoutCache est de
    pouvoir changer très rapidement de type de représentation
    pour un graphe donné
    Il faut absolument passer par
    l’objet GraphLayoutCache pour
    modifier les éléments d’un graphe

    View full-size slide

  80. 80
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † Exemple : création de cellules et de liens (rappel)
    ...
    DefaultGraphCell myFirst = new DefaultGraphCell("Debut");
    DefaultGraphCell mySecond = new DefaultGraphCell("Fin");
    // Ajoute les cellules dans le modèles et associe deux vues
    myGraph.getGraphLayoutCache().insert(myFirst);
    myGraph.getGraphLayoutCache().insert(mySecond);
    DefaultPort myFirstPort = new DefaultPort();
    DefaultPort mySecondPort = new DefaultPort();
    // Ajoute les ports aux cellules
    myFirst.add(myFirstPort);
    mySecond.add(mySecondPort);
    DefaultEdge myEdge = new DefaultEdge();
    // Ajoute un lien
    myGraph.getGraphLayoutCache().insert(myEdge, myFirstPort, mySecondPort);
    Ajout de deux cellules : dans
    le modèle et deux vues
    Ajout d’un lien : dans le
    modèle et une vue

    View full-size slide

  81. 81
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † Une vue permet de spécifier différents objets et attributs qui
    caractérisent les aspects graphiques d’un élément (cellule, …)
    † Objet « Renderer »
    † Objet « Editor »
    † Taille, …
    † Les vues définissent une couche supplémentaire permettant
    de paramétrer les objets « Renderer »
    † Toute les vues doivent se comporter comme un objet de type
    AbstractCellView
    † Les trois types d’objet d’un graphe ont chacun une classe
    prédéfinie pour représenter leur vue :
    † Port : PortView
    † Lien : EdgeView
    † Cellule ou groupe : VertexView
    Le contenu à afficher en terme de
    composant (JLabel, …) est obtenu
    par le l’objet renderer

    View full-size slide

  82. 82
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † Chaque objet de type AbstractCellView possède son propre
    objet « Renderer » et possède un objet « Editor » commun
    Association
    Implémentation
    Implémentation

    View full-size slide

  83. 83
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : VertexView
    † La classe VertexView permet de créer des vues pour les
    cellules ou les groupes
    † Différentes méthodes sont définies et doivent être redéfinies
    pour avoir un comportement spécifique pour une cellule ou
    un groupe
    † Rectangle2D getBounds() : retourne la position et la taille de la cellule
    † …
    † Exemple : changer la taille d’une cellule
    public class MyVertexView extends VertexView {
    public Rectangle2D getBounds() {
    Rectangle2D temp = super.getBounds();
    return new Rectangle2D.Double(temp.getX(), temp.getY(), 100, 100);
    }
    ...
    }
    La méthode qui permet de déterminer la
    position et la taille à tout instant
    Par défaut la taille d’une
    cellule est ajusté selon le
    contenu

    View full-size slide

  84. 84
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : EdgeView
    † La classe EdgeView permet de créer des vues pour les liens
    † Différentes méthodes ont été définies pour reflétées
    l’apparence d’un lien
    † Point2D getLabelPosition() : modifie l’emplacement du JLabel qui sert
    à afficher une légende au lien
    † CellView getSource() : retourne la vue de la cellule source
    † CellView getTarget() : retourne la vue de la cellule cible
    † boolean isLoop() : retourne vraie si le lien est une boucle (la source
    et la cible sont les mêmes)
    † …

    View full-size slide

  85. 85
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : EdgeView
    † Exemple : changer la position du texte d’un lien
    public class MyEdgeView extends EdgeView {
    ...
    public MyEdgeView(Object cell) {
    super(cell);
    }
    public Point2D getLabelPosition() {
    return new Point2D(10,10);
    }
    }
    Avant : le texte est centré
    sur la longueur du lien
    Après : le texte est placé
    à une position fixe
    L’origine est situé sur le
    départ du lien (côté point
    d’ancrage source)
    Une autre façon est de
    modifier la valeur de la clé
    LABELPOSITION d’un lien

    View full-size slide

  86. 86
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : EdgeView
    † Un objet EdgeView permet également de créer sur la longueur
    du lien des points de cassures
    † La classe fournit un ensemble de méthodes permettant de
    manipuler et interroger les points de cassures
    † addPoint(int ind, Point2D p) : ajoute un nouveau point de cassure
    † Point2D getPoint(int ind) : retourne le point à l’indice ind
    † static double getLength(CellView v) : retourne la longueur d’un lien

    View full-size slide

  87. 87
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : EdgeView
    † L’ajout de point de cassures de manière interactive se fait à
    l’aide de la sous classe EdgeView.EdgeHandle
    † Elle contient des méthodes pour la gestion des événements
    liés à la souris (mouseDragged, mousePressed, …)
    † Pour ajouter un objet de manipulation (EdgeHandle) il faut
    redéfinir la méthode
    † CellHandle getHandle(GraphContext c) : retourne l’objet permettant de
    manipuler les points de cassure
    † Exemple : désactiver la création de points de cassure
    public CellHandle getHandle(GraphContext context) {
    return null;
    }

    View full-size slide

  88. 88
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : EdgeView
    † L’API JGraph fournit par défaut deux formes pour les liens
    † Une forme est composée d’un ensemble de points de cassure
    disposée suivant une manière précise
    † Possibilité de fournir explicitement de nouvelles formes en se
    basant sur l’interface Edge.Routing
    † int getPreferredLineStyle(EdgeView edge) : style pour le lien
    † List route(EdgeView edge) : ensemble des points de cassure
    † La relation entre lien et objet Edge.Routing est faite par la
    modification de la clé ROUTING
    Forme appelée
    ROUTING_SIMPLE
    Forme appelée
    ROUTING_DEFAULT

    View full-size slide

  89. 89
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : EdgeView
    † Exemple : forcer une forme pour un lien
    public class MyEdgeRouting extends Edge.Routing {
    public List route(EdgeView edge) {
    List newPoints = new ArrayList();
    Point2D from, to = ...;
    double frombisX = from.getX();
    double frombisY = from.getY() + 50;
    double tobisX = to.getX();
    double tobisY = frombisY;
    newPoints[1] = new Point(frombisX, frombisY);
    newPoints[2] = new Point(tobisX, tobisY);
    ...
    }
    ...
    // Ajoute les ports aux cellules
    myFirst.add(myFirstPort);
    mySecond.add(mySecondPort);
    DefaultEdge myEdge = new DefaultEdge();
    GraphConstants.setRooting(myEdge.getAttributes(), new MyEdgeRouting());
    Hauteur
    constante
    Largeur et
    hauteur
    variables

    View full-size slide

  90. 90
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : PortView
    † La classe PortView permet de donner une représentation aux
    points d’ancrage
    † Le composant JGraph peut décider d’afficher ou pas les points
    d’ancrage
    † JGraph#setPortsVisible(boolean) : affiche ou pas les point d’ancrage
    † Différentes méthodes ont été définies pour modifier
    l’apparence d’un point d’ancrage
    † Point2D getLocation() : cette méthode permet de retourner la position
    du point d’ancrage
    † …

    View full-size slide

  91. 91
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : PortView
    † Exemple : changer les points d’ancrage d’une cellule
    public class MyPortView extends PortView {
    ...
    public Point2D getLocation(EdgeView edge, Point2D nearest) {
    CellView vertex = getParentView();
    Point2D pos = null;
    if (vertex != null) {
    Rectangle2D r = vertex.getBounds();
    double highOrLow = 0;
    if (((DefaultGraphCell)vertex.getCell()).getChildAt(0) == cell) {
    highOrLow = r.getMinY();
    } else {
    highOrLow = r.getMaxY();
    }
    if (r != null)
    return new Point2D.Double(r.getCenterX(), highOrLow);
    }
    return pos;
    }
    }
    Avant : deux cellules,
    deux liens et quatre ports
    sont confondus
    Après : deux cellules, deux
    liens et quatre ports séparés

    View full-size slide

  92. 92
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † La gestion de l’ensemble des vues d’un composant JGraph se
    fait dans un objet de type CellViewFactory
    † Une implémentation de l’interface CellViewFactory par défaut
    existe et s’appelle DefaultCellViewFactory
    † Un objet CellViewFactory ne fait rien d’autre que d’envoyer
    les vues suivant les objets concernés
    † Le regroupement des vues du graphe se fait par
    l’intermédiaire de
    † CellView createView(GraphModel myModel, Object cell) : elle permet
    de retourner une vue par rapport à son objet modèle cell

    View full-size slide

  93. 93
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † Exemple : associer des nouvelles vues aux éléments d’un
    JGraph
    public MyCellViewFactory extends DefaultCellViewFactory {
    public CellView createView(GraphModel model, Object cell) {
    if (model.isPort(cell)) {
    return new MyPortView(cell);
    } else if (model.isEdge(cell)) {
    return new MyEdgeView(cell);
    } else
    return new MyVertexView(cell);
    }
    }
    Suivant le type d’objet (cellule, lien et
    port) une vue est proposée Ne pas oublier de transmettre
    l’objet modèle à la vue
    Possibilité de définir plus d’une vue
    par type d’objet (lien, port, …)

    View full-size slide

  94. 94
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † Pour associer un objet CellViewFactory à l’objet JGraph
    courant il faut modifier l’objet GraphLayoutCache
    † GraphLayoutCache#setFactory(CellViewFactory rf) : modifie la gestion
    courante des vues
    † Possibilité de changer de CellViewFactory pour donner
    rapidement un autre type de représentation pour votre graphe
    † Exemple : association d’un objet CellViewFactory à un JGraph
    myGraph.getGraphLayoutCache().setFactory(new DefaultCellViewFactory() {
    public CellView createView(GraphModel model, Object cell) {
    if (model.isPort(cell)) {
    return new MyPortView(cell);
    } else if (model.isEdge(cell)) {
    ...
    }
    ...
    }
    });
    Pensez à proposer pour
    tous les types d’objet
    GraphCell une vue associée

    View full-size slide

  95. 95
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : vues
    † Exemple (suite) : associer un CellViewFactory à un JGraph
    myGraph.getGraphLayoutCache().setFactory(new DefaultCellViewFactory() {
    public CellView createView(GraphModel model, Object cell) {
    if (model.isPort(cell)) {
    return new MyPortView(cell);
    } ...
    }});
    class MyVertexView extends VertexView {
    public MyVertexView(Object cell) { super(cell) }
    public Rectangle2D getBounds() {
    Rectangle2D temp = super.getBounds();
    return new Rectangle2D.Double(temp.getX(), temp.getY(), 100, 100);
    }
    }
    class MyPortView extends PortView {
    ...
    }
    class MyEdgeView extends EdgeView {
    ...
    }
    ...
    Suivant le type d’objet (cellule, lien
    et port) on propose une vue
    associée

    View full-size slide

  96. 96
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : paramétrage de la vue
    † Possibilité de paramétrer de manière globale l’apparence d’un
    objet JGraph et les différents objets qui le composent
    † Grille
    † setGridVisible(boolean f) : affiche ou pas la grille
    † setGridSize(double n) : définit le pas de la grille
    † setGridEnabled(boolean f) : active ou pas la grille
    † setGridColor(Color c) : couleur de la grille
    † Apparence
    † setAntiAliased(boolean b) : active ou pas l’effet de lissage
    † setScale(double n) : agrandit ou réduit la taille du graphe
    Grille visible et activée
    avec un pas de 6

    View full-size slide

  97. 97
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : paramétrage de la vue
    † Edition et manipulation des éléments du graphe
    † setBendable(boolean b) : active ou pas l’ajout de points de cassure
    † setConnectable(boolean b) : autorise ou pas la connexion de lien
    † setEditable(boolean b) : autorise ou pas l’édition (Editor)
    † setEditClickCount(int count) : définit le nombre de click pour l’édition
    † setMoveable(boolean f) : autorise le déplacement
    † setPortsVisible(boolean f) : affiche ou pas les ports de connexion
    † setSelectionEnabled(boolean f) : active ou pas la sélection
    † setSizeable(boolean f) : active ou pas le redimensionnement
    Ces méthodes modifient de façon globales
    les paramètres des éléments. Il est
    également possible de modifier les
    paramètres de manière ponctuelle

    View full-size slide

  98. 98
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Renderers et Editors
    † Les objets AbstractCellView permettent de configurer les
    attributs graphiques des éléments d’un graphe (position,
    couleur, …) mais ne permettent pas directement de créer un
    nouveau « contenu »
    † L’API JGraph permet de paramétrer pour les éléments (cellule,
    groupe, lien et point d’ancrage)
    † Le rendu : le composant qui représente graphique un élément du
    graphe
    † L’édition : le composant permettant d’éditer des valeurs d’un élément
    † Un objet « Editor » est appelé quand l’utilisateur effectue une
    action « d’édition » sur un élément (sous condition que l’élément
    soit éditable)
    † Un objet « Renderer » est une vue sans réaction directe qui
    retourne une visualisation d’un élément

    View full-size slide

  99. 99
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Renderers et Editors
    Le « renderer » de la
    cellule a permis
    d’afficher un rectangle
    plein coloré par un
    dégradé
    L’« editor » de la cellule a permis
    d’afficher un JTextField pour
    l’édition du contenu de la cellule
    Le « renderer » du lien a
    permis d’afficher une
    flèche et le texte à
    afficher est vide
    L’« editor » du lien a permis
    d’afficher un JTextField pour
    l’édition du contenu du lien

    View full-size slide

  100. 100
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Renderers
    † Deux solutions sont envisageables pour modifier l’objet rendu
    d’une cellule, groupe, lien ou point d’ancrage
    † Redéfinir la méthode Component getRendererComponent(…) issu
    directement de la classe mère des vues AbstractCellView
    † Redéfinir la méthode CellViewRenderer getRenderer(…) définie pour
    chaque vue
    † La première solution prend le dessus sur la seconde solution
    † La seconde est à envisager si vous souhaitez spécialiser les
    renderers déjà existant :
    † VertexRenderer : pour les cellules ou les groupes
    † PortRenderer : pour les points d’ancrages
    † EdgeRenderer : pour les liens
    Nous nous limiterons
    à présenter la
    première solution

    View full-size slide

  101. 101
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Renderers
    † La méthode à redéfinir (dans la cas de la seconde solution)
    pour modifier le renderer est semblable à celle traitée pour la
    JTable ou le JTree
    † Component getRendererComponent(JGraph myGraph, boolean
    selected, boolean focus, boolean preview)
    † JGraph mygraph : référence à la vue du graphe
    † boolean selected : l’élément est-il sélectionné ?
    † boolean focus : l’élément a-t-il le focus ?
    † boolean preview : l’élément est-il une preview (pour le fantôme) ?
    L’accès à l’objet
    DefaultGraphCell est obtenu
    par l’attribut protégé cell
    Dans le cas d’une
    JTable ou d’un JTree
    la méthode
    associée propose en
    plus un objet
    « utilisateur »

    View full-size slide

  102. 102
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Vertex Renderer
    † Exemple : modifier le renderer d’une cellule
    private class MyVertexView extends VertexView {
    public Component getRendererComponent(JGraph graph, boolean selected,
    boolean focus, boolean preview) {
    JPanel myVertexPanel = new JPanel();
    myVertexPanel.setLayout(new BoxLayout(myVertexPanel,
    BoxLayout.Y_AXIS));
    JLabel myLabelImage = new JLabel(new ImageIcon("image.gif"));
    myLabelImage.setBorder(defaultBorder);
    JLabel myLabelName = new JLabel(cell.toString());
    JLabel myLabelOrdonnancement = new JLabel(" HELLO ");
    myLabelOrd.setAlignmentX(Component.CENTER_ALIGNMENT);
    myLabelOrd.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
    myVertexPanel.add(myLabelImage);
    myVertexPanel.add(Box.createRigidArea(new Dimension(0,
    15)));
    myVertexPanel.add(myLabelName);
    myVertexPanel.add(Box.createRigidArea(new Dimension(0,
    15)));
    myVertexPanel.add(myLabelOrdonnancement);
    return myVertexPanel;
    }
    Redéfinition de la
    méthode
    Trois JLabel avec un
    Border pour le dernier
    Un JPanel
    englobant
    L’objet « utilisateur » est
    obtenu par l’attribut
    protégé cell

    View full-size slide

  103. 103
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Port Renderer
    † Exemple : modifier le renderer d’un point d’ancrage
    public class MyPortView extends PortView {
    public Rectangle2D getBounds() {
    Rectangle2D myBounds = super.getBounds();
    myBounds.setRect(myBounds.getX(), myBounds.getY(),60,60);
    return myBounds;
    }
    public Component getRendererComponent(JGraph graph, boolean selected,
    boolean focus, boolean preview) {
    JComponent myCompo = new JComponent() {
    public void paint(Graphics g) {
    Dimension d = this.getSize();
    g.setColor(Color.BLACK);
    super.paint(g);
    g.draw3DRect(0,0,10,10,true);
    g.drawString(" Port",10,10);
    }
    };
    return myCompo;
    }
    ...
    }
    Pour agrandir la
    taille du Renderer

    View full-size slide

  104. 104
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Renderers
    † La seconde solution peut être utilisée pour proposer un
    renderer spécifique nécessitant l’utilisation de Java2D
    † Principe de cette solution
    † Définition d’une nouvelle classe qui hérite directement d’un renderer
    spécifique (VertexRenderer, EdgeRenderer, PortRenderer) ou qui
    implémente l’interface CellViewRenderer
    † Implémentation ou redéfinition des méthodes jugées nécessaires
    † Exemple : redéfinition de la méthode paint
    public CellViewRenderer getRenderer() {
    return new MyVertexRenderer();
    }
    class MyVertexRenderer extends VertexRenderer {
    public void paint(Graphics g) {
    super.paint(g);
    ...
    }
    }
    Redéfinition de la
    méthode paint(…)
    Ne redéfinissez pas la méthode
    getRendererComponent si vous
    choisissez cette solution
    Classe interne

    View full-size slide

  105. 105
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : comportement des vues
    † Toutes les vues (VertexView, EdgeView et PortView) peuvent
    définir des comportements locales suite aux réactions de la
    souris
    † Les comportements sont définis par l’interface CellHandle
    † mouseDragged(MouseEvent e) : déplacement avec bouton enfoncé
    † mouseMoved(MouseEvent e) : déplacement
    † mousePressed(MouseEvent e) : bouton pressé
    † mouseReleased(MouseEvent e) : bouton relaché
    † overlay(Graphics g) : dessin du fantôme
    † paint(Graphics g) : dessin de l’après
    † L’association d’un objet CellHandle avec une vue se fait en
    redéfinissant la méthode
    † CellHandle getHandle(GraphContext r) : retourne un objet CellHandle
    où r permet de connaître l’objet JGraph, …

    View full-size slide

  106. 106
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : comportement des vues
    † Les vues définissent par défaut des comportements
    † VertexView : pour le redimensionnement d’une cellule
    † EdgeView : pour le déplacement d’un lien à un port
    † PortView : aucun
    † Dans quel cas a-t-on besoin de redéfinir le CellHandle d’une
    vue
    † Pour une cellule, réagir aux actions d’un click à une position donnée de
    la souris (voir figure)
    † Pour une cellule, faire apparaître des informations supplémentaire suite
    au déplacement du curseur
    † Pour un lien, afficher des informations supplémentaires suite au
    déplacement du curseur
    Le CellHandle est la seule solution pour
    interagir sur les vues. Rappelons que les
    renderers sont des vues sans réaction
    Besoin d’un CellHandle
    pour agir sur ce bouton

    View full-size slide

  107. 107
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Editors
    † Un « Editor » doit implémenter l’interface GraphCellEditor qui
    hérite également de l’interface CellEditor utilisée par tous les
    objets ayant un « Editor » : JTree, JTable, …
    † Cette interface possède entre autre une méthode qui retourne
    le composant à afficher pour l’édition
    † Component getGraphCellEditorComponent(JTable graph, Object value,
    boolean isSelected)
    † JGraph graph : référence du graph associé à l’« Editor »
    † Object value : valeur de l’élément (un objet de type GraphCell qui
    est en fait un objet MutableTreeNode)
    † boolean isSelected : l’élément (groupe, cellule, lien ou port) est-il
    sélectionné
    † Pour éviter d’implémenter toutes les méthodes de l’interface
    CellEditor vous pouvez utiliser la classe AbstractCellEditor

    View full-size slide

  108. 108
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Editors
    † Si la classe AbstractCellEditor est utilisée en place de
    CellEditor certaines méthodes ont un comportement prédéfini
    † stopCellEditing() : déclenche l’arrêt de l’« Editor »
    † cancelCellEditing() : déclenche l’annulation de l’« Editor »
    † addCellEditorListener(CellEditorListener) : ajoute un « écouteur »
    † Cependant vous devrez fournir obligatoirement une
    implémentation de la méthode
    † Object getCellEditorValue() : retourne la valeur que l’utilisateur vient
    de saisir (la méthode setUserObject(…) de l’élément GraphCell est
    alors appelée)
    † Principe de codage
    † Implémentez getGraphCellEditorComponent(…) pour retourner le
    composant d’édition
    † La validation du composant d’édition doit appeler stopCellEditing()
    † Implémentez getCellEditorValue()

    View full-size slide

  109. 109
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Vertex Editor
    † Exemple : modifier l’editor d’une cellule
    public class MyAbstractCellEditor extends AbstractCellEditor implements
    GraphCellEditor {
    private JPanel myPanel;
    private JTextField myTextField;
    public MyAbstractCellEditor() {
    myPanel = new JPanel();
    myTextField = new JTextField();
    myPanel.setLayout(new BorderLayout());
    myPanel.add(BorderLayout.NORTH, new JLabel("Mon Editor"));
    myPanel.add(BorderLayout.CENTER,myTextField);
    myTextField.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
    MyAbstractCellEditor.this.stopCellEditing();
    }});
    }
    public Component getGraphCellEditorComponent(JGraph gra, Object value,
    boolean isSelected) {
    myTextField.setText((String)((DefaultGraphCell)value).getUserObject());
    return myPanel;
    }
    public Object getCellEditorValue() {
    L’Editor est compoé d’un
    JLabel et d’un JTextField
    L’objet transmis à l’Editor
    est un objet GraphCell

    View full-size slide

  110. 110
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : Edge Editor
    † Exemple : modifier l’editor d’un lien
    public class MyAbstractEdgeCellEditor extends AbstractCellEditor
    implements GraphCellEditor {
    private JComboBox myCombo;
    private String[] myTab = {"Action", "Réaction", "Transition"};
    public MyAbstractEdgeCellEditor() {
    myCombo = new JComboBox(myTab);
    myCombo.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    MyAbstractEdgeCellEditor.this.stopCellEditing();
    }
    });
    }
    public Component getGraphCellEditorComponent(JGraph graph, Object
    value, boolean isSelected) {
    myCombo.setSelectedItem((DefaultEdge)value);
    return myCombo;
    }
    public Object getCellEditorValue() {
    return myCombo.getSelectedItem();
    }} L’objet transmis à l’Editor est un objet
    GraphCell et plus précisément un DefaultEdge

    View full-size slide

  111. 111
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : modèle de sélection
    † Le modèle de sélection gère les aspects liés à la sélection d’un
    élément d’un graphe (un lien, une cellule ou un groupe)
    † Un modèle de sélection doit implémenter l’interface appelée
    GraphSelectionModel
    † Possibilité de modifier un modèle de sélection pour tous les
    éléments d’un composant JGraph
    † setSelectionModel(GraphSelectionModel) : modifie le modèle de
    sélection
    † GraphSelectionModel getSelectionModel() : récupère le modèle de
    sélection
    † Pour écouter le changement de sélection d’un élément
    † JGraph#addGraphSelectionListener(GraphSelectionListener) : ajoute un
    écouteur de sélection
    Certaines méthodes liées à la sélection sont
    disponibles à la fois par le modèle de
    sélection ou par l’objet JGraph

    View full-size slide

  112. 112
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : modèle de sélection
    † La définition explicite du modèle de sélection n’est utile que
    si effectuer des traitements pointus sur les sélections
    † Pour le reste des aspects liés à la sélection utilisez les
    méthodes de la classe JGraph qui pointent directement sur le
    modèle de sélection
    † Curieusement certaines méthodes ne sont pas disponibles
    comme l’étaient des méthodes de JTable ou JTree
    † GraphSelectionModel#setSelectionMode(int) : choix du modèle de
    sélection
    † MULTIPLE_GRAPH_SELECTION : plusieurs éléments
    † SINGLE_GRAPH_SELECTION : un seul élément
    † Object JGraph#getSelectionCell() : premier élément sélectionné
    † Object[] JGraph#getSelectionCells() : éléments sélectionnés
    † clearSelection() : supprime les sélections

    View full-size slide

  113. 113
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : modèle de sélection
    † Deux modes différents de sélection
    Mode de sélection à
    SINGLE_GRAPH_SELECTION
    Mode de sélection à
    MULTIPLE_GRAPH_SELECTION
    Seul le lien du bas n’est
    pas sélectionné

    View full-size slide

  114. 114
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : modèle de sélection
    † Exemple : accès aux informations de la sélection courante
    myGraph.addGraphSelectionListener(new GraphSelectionListener() {
    public void valueChanged(GraphSelectionEvent selEvent) {
    Object[] list = myGraph.getSelectionCells();
    for (int i = 0; i < list.length; i++) {
    if (list[i] instanceof DefaultEdge) {
    System.out.println("Un Lien");
    } else if (list[i] instanceof DefaultGraphCell)
    {
    System.out.println("Une cellule ou groupe");
    }
    }
    }
    });

    View full-size slide

  115. 115
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Possibilité dans un JGraph d’ajouter dynamiquement des
    cellules et des liens
    † L’ajout des éléments se fait à partir de l’objet
    GraphLayoutCache qui s’occupe du « Mapping » entre le
    modèle et les vues
    † insert(Object cell) : ajoute un élément cell
    † insertEdge(Object edge, Object source, Object target) : ajoute un lien
    edge connecté à un port source et target
    † remove(Object[] cells) : supprime les objets cells
    † L’ajout d’une cellule nécessite uniquement un point de
    création
    † L’ajout d’un lien nécessite un port de départ et un port
    d’arrivée d’une ou plusieurs cellules

    View full-size slide

  116. 116
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † L’objet JGraph est associé à un objet de type
    BasicMarqueeHandle permettant de réaliser des actions sur
    l’ensemble des vues
    † A la différences des objets CellHandle associées à un type de
    vue l’objet BasicMarqueeHandle permet de faire des
    traitements sur tous types de vues
    † boolean isForceMarqueeEvent(MouseEvent e) : si true désactive le
    déplacement et l’objet CellHandle de l’élément associé
    † mouseMoved(…), mousePressed(…), … : les méthodes qui traitent les
    actions de la souris
    † L’association d’un objet BasicMarqueeHandle à un objet
    JGraph se fait par l’intermédiaire
    † JGraph#setMarqueeHandler(BasicMarqueeHandler basic) : associer
    basic à une référence JGraph

    View full-size slide

  117. 117
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple : application finale avec de la manipulation directe …
    Des boutons de contrôle « Annuler »,
    « Ajouter », « Supprimer »
    Composant
    JGraph
    Objet
    DefaultGraphCell
    incluant un objet
    DefaultPort
    On profitera de cet exemple pour résumer
    les parties précédentes et on montrera
    certaines méthodes non étudiées

    View full-size slide

  118. 118
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple (suite) : code de la partie graphique de l’application
    public class DynamicGraph extends JFrame {
    private int stateAppl = 0;
    public DynamicGraph() {
    super("SimpleGraph");
    myGraph = new JGraph(new DefaultGraphModel());
    myGraph.setMarqueeHandler(new MyMarqueeHandler());
    JScrollPane myScrollPane = JScrollPane(myGraph);
    getContentPane().add(myScrollPane);
    JPanel myPanel = new JPanel();
    noCell = new JToggleButton("Annuler");
    noCell.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    stateAppl = 0;
    }
    });
    addCell = new JToggleButton("Ajouter");
    removeCell = new JToggleButton("Supprimer");
    myPanel.add(noCell);
    getContentPane().add(myPanel, BorderLayout.SOUTH);
    ...
    }
    class MyMarqueeHandler extends BasicMarqueeHandler {
    ...
    Construction
    graphique de
    l’interface
    Abonnement
    des composants
    sources
    L’objet
    BasicMarqueeHandler
    pour la manipulation des
    vues

    View full-size slide

  119. 119
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple : ajouter dynamiquement une cellule
    public void mousePressed(MouseEvent e) {
    if (SwingUtilities.isLeftMouseButton(e)) {
    if (stateAppl == 1) {
    DefaultGraphCell myFirst = new DefaultGraphCell("Cellule 1");
    DefaultPort myPort1 = new DefaultPort();
    myFirst.add(myPort1);
    Map myHashTable = new Hashtable();
    GraphConstants.setBounds(myHashTable, new
    Rectangle2D.Double(e.getX(),e.getY(),40,100));
    myFirst.setAttributes(new AttributeMap(myHashTable));
    myGraph.getGraphLayoutCache().insert(myFirst);
    noCell.setSelected(true);
    stateAppl = 0;
    }
    }
    ...
    }
    Cette méthode sera également
    utilisée pour la construction
    dynamique d’un lien
    Construction
    d’une cellule
    Modification
    de la position
    Ajout dans le
    composant JGraph

    View full-size slide

  120. 120
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple : ajouter dynamiquement un lien (mousePressed)
    class MyMarqueeHandler extends BasicMarqueeHandler {
    protected Point2D start, current;
    protected PortView port, firstPort;
    public boolean isForceMarqueeEvent(MouseEvent e) {
    port = getSourcePortAt(e.getPoint());
    if (port != null && myGraph.isPortsVisible())
    return true;
    return super.isForceMarqueeEvent(e);
    }
    public void mousePressed(MouseEvent e) {
    ...
    if (port != null && myGraph.isPortsVisible()) {
    start = myGraph.toScreen(port.getLocation());
    firstPort = port;
    } else {
    super.mousePressed(e);
    }
    }
    Le reste sur le
    transparent précédent
    Tente d’extraire l’objet
    PortView suivant la
    position du curseur

    View full-size slide

  121. 121
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple : ajouter dynamiquement un lien (mouseDragged)
    public void mouseDragged(MouseEvent e) {
    if (start != null) {
    Graphics g = myGraph.getGraphics();
    PortView newPort = getTargetPortAt(e.getPoint());
    if (newPort == null || newPort != port) {
    paintConnector(Color.black, myGraph.getBackground(), g);
    port = newPort;
    if (port != null)
    current = myGraph.toScreen(port.getLocation());
    else
    current = myGraph.snap(e.getPoint());
    paintConnector(myGraph.getBackground(), Color.black,
    g);
    }
    }
    super.mouseDragged(e);
    }
    Pendant le déplacement de la
    souris on dessine le trait

    View full-size slide

  122. 122
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple : ajouter dynamiquement un lien (mouseReleased)
    public void mouseReleased(MouseEvent e) {
    if (e != null && port != null && firstPort != null && firstPort
    != port) {
    DefaultEdge myEdge = new DefaultEdge();
    myGraph.getGraphLayoutCache().insertEdge(myEdge,
    (DefaultPort)firstPort.getCell(), (DefaultPort)port.getCell());
    e.consume();
    } else {
    myGraph.repaint();
    }
    firstPort = port = null;
    start = current = null;
    super.mouseReleased(e);
    }
    PortView getSourcePortAt(Point2D point) // Extrait un PortView le plus proche
    de point
    PortView getTargetPortAt(Point2D point) // Extrait un PortView pour l’arrivée
    paintConnector(Color fg, Color bg, Graphics g) // Dessine les traits
    ...

    View full-size slide

  123. 123
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : ajout et suppression dynamique
    † Exemple : supprimer dynamiquement un lien ou une cellule
    public DynamicGraph() {
    ...
    JButton removeCell = new JButton("Supprimer");
    removeCell.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    Object[] t = myGraph.getSelectionCells();
    t = myGraph.getDescendants(t);
    myGraph.getGraphLayoutCache().remove(t);
    }
    });
    ...
    Cette méthode permet de
    récupérer tous les sous objets
    On reprend l’implémentation
    du constructeur

    View full-size slide

  124. 124
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    JGraph : bilan
    † Un composant JGraph est une vue paramétrable qui permet
    d’afficher et modifier des données d’un graphe
    JGraph
    GraphModel
    1
    GraphSelectionModel
    1
    Données du
    composant
    Sélection des
    données
    GraphModelListener
    0..n
    GraphSelectionListener
    0..n
    Avertir que le
    modèle a changé
    Ecouteur pour avertir que
    la sélection a changé
    GraphLayoutCache
    Mapping entre
    modèle et vue
    1
    CellViewFactory
    1
    VertexView EdgeView
    PortView
    Dispatching des
    vues
    Vue
    GraphCellEditor
    1
    1
    Ecouteur pour avertir
    que l’édition est
    annulée ou validée
    CellHandle
    VertexRenderer
    EdgeRenderer
    PortRenderer
    Renderer
    Paramétrage de
    l’affichage des données
    1
    BasicMarqueeHandler
    1

    View full-size slide

  125. 125
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : autres techniques …
    † Les composants de visualisation d’informations ont parfois
    besoin de techniques supplémentaires pour manipuler les
    données
    † Agrandissement (une table, un graphe, …)
    † Exportation dans un format d’image (EPS, BMP, JPG, …)
    † Représentation sous différentes vues (courbe, camembert, …)
    † Impression sur une ou plusieurs pages
    † Certaines techniques sont directement implémentées par une
    API Java (java.awt.print)
    † D’autres nécessitent au contraire l’utilisation de l’API Java 2D
    afin de permettre d’effectuer des traitements graphiques
    évolués
    † Exemple : l’API pour l’impression

    View full-size slide

  126. 126
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : impression
    † Le processus d’impression est l’ensemble des taches que
    réalise un programme pour envoyer des données vers une
    imprimante
    † Indiquer au système d’impression quels objets de l’application sont à
    imprimer
    † Indiquer au système les données concernant l’impression : nombre de
    pages, format de page, …
    † Appeler la fonction d’impression pour imprimer les objets à partir du
    gestionnaire d’impression (PrinterJob)
    Boîte de dialogue pour la
    gestion de l’impression
    définie par le système

    View full-size slide

  127. 127
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : Printable
    † Les composants Swing possèdent déjà un comportement pour
    l’impression mais se limitent pour la plupart à l’impression de
    texte
    † Pour être imprimable un objet doit implémenter l’interface
    Printable
    † int print(Graphics g, PageFormat pf, int pi) : méthode appelée pour
    effectuer le rendu sur l’imprimante
    † g une référence au contexte graphique
    † pf permet de connaître le taille du papier, ses marges, son
    orientation, …
    † pi numéro de page à imprimer
    † PAGE_EXISTS : indique au gestionnaire d’impression qu’il peut
    imprimer la page traitée dans print et qu’il pourra rappeler de nouveau
    print
    † NO_SUCH_PAGE : indique au gestionnaire d’impression qu’il n’a plus de
    page à imprimer et qu’il ne pourra pas rappeler print

    View full-size slide

  128. 128
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : Printable
    † Exemple : imprimer un contenu défini dans print
    public class HelloWorldPrintExample implements Printable {
    public int print(Graphics g, PageFormat pf, int pageIndex) throws
    PrinterException {
    if (pageIndex !=0) return NO_SUCH_PAGE;
    Graphics2D g2 = (Graphics2D)g;
    g2.setFont(new Font("Serif", Font.PLAIN,36));
    g2.setPaint(Color.BLACK);
    g2.drawString("Hello Every Body", 144,144);
    return PAGE_EXISTS;
    }
    }
    Appeler suite à la première
    page mais en avertissant le
    gestionnaire d’impression qu’il
    ne pourra plus rappeler print
    Appeler au tout début de
    l’impression et indique au
    gestion d’impression qu’il peut
    imprimer cette page et qu’il
    pourra rappeler print
    Impression en PDF

    View full-size slide

  129. 129
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : Printable
    † Exemple : imprimer un contenu défini à l’extérieur de print
    public class CompPrintExample extends JFrame implements Printable {
    public ComponentsPrintExample() {
    this.setTitle("Un simple fenêtre");
    JButton myButton = new JButton("Coucou");
    JTextArea myText = new JTextArea();
    myText.setLineWrap(true);
    myText.setText("Bonjour à tout le monde, un simple ...");
    this.getContentPane().add(BorderLayout.CENTER, myText);
    this.getContentPane().add(BorderLayout.SOUTH,myButton);
    this.pack();
    this.setVisible(true);
    }
    public int print(Graphics g, PageFormat pf, int pageIndex) throws
    PrinterException {
    if (pageIndex !=0) return NO_SUCH_PAGE;
    Graphics2D g2 = (Graphics2D)g;
    g2.translate(50,50);
    this.paint(g2);
    return PAGE_EXISTS;
    }
    }
    Transfert le graphique
    d’impression au
    composant

    View full-size slide

  130. 130
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : format de page
    † La classe PageFormat décrit les caractéristiques
    dimensionnelle d’une feuille de papier et son orientation
    † Une feuille est définie par sa dimension (taille de la feuille),
    une zone imprimable et une orientation
    † Les modifications des caractéristiques sont réalisées au
    travers de la boîte de dialogue qui gère la mise en page
    (voir transparent suivant)
    x
    y
    Portrait
    x
    y
    Landscape
    Zone
    imprimable

    View full-size slide

  131. 131
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : format de page
    † La classe PageFormat offre de nombreuses méthodes et
    constantes
    † int PORTRAIT : page en mode portrait
    † int LANDSCAPE : page en mode paysage
    † int REVERSE_LANDSCAPE : page en mode inverse paysage
    † int getOrientation() : retourne la valeur de l’orientation (à comparer
    avec les constantes de PageFormat)
    † double getWidth() : largeur de la page (A4 : 29,7 cm)
    † double getHeight() : hauteur de la page (A4 : 21 cm)
    † double getImageableX() : position en abscisse de la page
    † double getImageableY() : position en ordonnée de la page
    † double getImageableWidth() : largeur de la zone imprimable
    † double getImageableHeight() : hauteur de la zone imprimable

    View full-size slide

  132. 132
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : format de page
    † Exemple : imprimer suivant les caractéristiques de la page
    public class PageFormatPrintExample implements Printable {
    public int print(Graphics g, PageFormat pf, int pageIndex)
    {
    if (pageIndex !=0) return NO_SUCH_PAGE;
    Graphics2D g2 = (Graphics2D)g;
    Rectangle2D outline = new Rectangle2D.Double(
    pf.getImageableX(),
    pf.getImageableY(),
    pf.getImageableWidth(),
    pf.getImageableHeight());
    g2.setPaint(Color.black);
    g2.draw(outline);
    return PAGE_EXISTS;
    }
    Manipulation de la Zone
    imprimable

    View full-size slide

  133. 133
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : gestion d’impression
    † Le gestionnaire d’impression permet de contrôler le processus
    complet pour l’impression de page
    † Monter le dialogue d’impression
    † Montrer le dialogue de mise en page
    † Débuter et annuler une impression
    † Le gestionnaire d’impression est géré par un objet PrinterJob
    † static PrinterJob getPrinterJob() : retourne l’instance du gestionnaire
    d’impression
    † setPrintable(Printable printer) : indique l’objet à imprimer
    † setPrintable(Printable printer, PageFormat pf) : en donnant un format
    de page
    † print() : lance l’impression
    † setJobName(String jn) : modifie le nom du gestionnaire d’impression
    † getJobName() : retourne le nom du gestionnaire d’impression
    † PageFormat defaultPage() : retourne l’objet PageFormat par défaut

    View full-size slide

  134. 134
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : gestion d’impression
    † Exemple : gestion d’impression en action
    public class MyPrintDialog extends JFrame {
    public MyPrintDialog() {
    ...
    PrinterJob pj = PrinterJob.getPrinterJob();
    pj.setPrintable(new PageFormatPrintExample());
    if (pj.printDialog()) {
    try {
    pj.print();
    }catch(PrinterException e) {
    System.out.println(e);
    }
    }
    }
    }
    L’objet à imprimer et
    qui doit respecter
    l’interface Printable
    Le format de page est celui
    défini par défaut par le
    gestionnaire d’impression

    View full-size slide

  135. 135
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : configurat. de l’impression
    † Le gestionnaire d’impression permet de faire appel à des
    interfaces graphiques du système permettant la gestion de la
    mise en page et de l’impression
    † boolean PrinterJob#printDialog() : appel la boîte de dialogue pour
    configurer l’impression
    † PageFormat PrinterJob#pageDialog(PageFormat page) : appel la boîte
    de dialogue pour la mise en page où page est le format par défaut
    Boite de dialogue
    pour la mise en page
    Boite de dialogue pour la
    configuration de l’impression

    View full-size slide

  136. 136
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Visualisation d’informations : configurat. de l’impression
    † Exemple : configuration de l’impression en action
    public class MyPrintDialog extends JFrame {
    private PageFormat pf;
    private PrinterJob pj;
    public MyPrintDialog() {
    ...
    PrinterJob pj = PrinterJob.getPrinterJob();
    pf = pj.defaultPage();
    }
    public goLayoutAndPrintPage() {
    pj.pageDialog(pf);
    pj.setPrintable(new PageFormatPrintExample(),pf);
    if (pj.printDialog()) {
    try {
    pj.print();
    }catch(PrinterException e) {
    System.out.println(e);
    }
    }
    }
    }
    L’objet à imprimer à qui est
    associé le format de page
    Rien ne vous interdit de proposer des
    interfaces personnalisées pour la mise en
    page et la configuration de l’impression

    View full-size slide

  137. 137
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    † En manipulant NO_SUCH_PAGE et PAGE_EXISTS possibilité
    d’imprimer plusieurs pages avec un seul PageFormat pour
    toutes les pages du processus d’impression
    † La classe Book (java.awt.print.Book) offre la possibilité
    d’imprimer plusieurs pages avec différents PageFormat
    † append(Printable p, PageFormat pf) : associe un objet à imprimer p à
    un objet PageFormat pf
    † Exemple : impression avec différents formats de pages
    Visualisation d’informations : multi-pages avancés
    Book myBook = new Book();
    pfPortrait.setOrientation(PageFormat.PORTRAIT);
    myBook.append(myObject, pfPortrait);
    pfLandscape.setOrientation(PageFormat.LANDSCAPE);
    myBook.append(mySecondObject,pfLandscape);
    PrinterJob.getPrinterJob().setPageable(myBook);
    Ajout dans l’objet
    Book des objets à
    imprimer (peut-être le
    même) avec des
    PageFormat différent
    Une méthode supplémentaire dans
    PrinterJob pour gérer les objets Pageable

    View full-size slide

  138. 138
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Autres composants pour la visualisation d’informations
    † Le composant JFreeCharts permet de représenter des
    données dans un diagramme
    † Différentes représentations du diagramme sont proposées
    † Courbe 2D ou 3D
    † Bar horizontale ou verticale
    † Nuage de points
    † Camembert, …
    † JFreeCharts permet également l’agrandissement,
    l’impression, l’exportation sous différents formats
    † Cette API peut être utilisée dans les clients lourds, riches et
    légers (Servlets ou JSP)
    † API gratuite et utilisable dans les applications commerciales
    † Site et démos : www.jfree.org/jfreecharts

    View full-size slide

  139. 139
    Java Visu - M. Baron - Page
    mickael-baron.fr mickaelbaron
    Autres composants pour la visualisation d’informations

    View full-size slide