1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
| import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
public class TreeFactory {
/**
* @see #addTreeNode(List, char, int, boolean, DefaultMutableTreeNode)
*/
public TreeNode createTreeNode(List<String> treeDef,
char depthPrefix, int tabLength) {
return addTreeNode(treeDef, depthPrefix, tabLength, false, null);
}
/**
* Créer un modèle d'arbre à partir de la définition spécifiée (une liste de
* valeur pour chaque node, précédé d'un nombre de tabulation déterminant la
* profondeur du node)
*
* @param treeDef
* définition
* @param depthPrefix
* le caractère utilisé pour définir les tabulations
* @param tabLength
* le nombre de caractères pour une tabulation (doit être > 0)
* @param allowEmptyNodes true si on autorise les descentes de plus d'un niveau
* @param rootNode
* un node dans lequel ajouté les nodes créés, ou null pour faire
* un nouvel arbre
* @return toujours un node non null, qui contient les nodes créés à partir
* de la définition
*/
public TreeNode addTreeNode(List<String> treeDef,
char depthPrefix, int tabLength, boolean allowEmptyNodes, DefaultMutableTreeNode rootNode) {
if (tabLength <= 0)
throw new IllegalArgumentException("tabLength must be > 0");
// on utilise toujours un node root (on peut avoir plusieurs nodes de niveau 0 dans treeDef)
if (rootNode == null) {
rootNode = new DefaultMutableTreeNode("");
}
if (treeDef == null || treeDef.isEmpty()) {
return rootNode; // si pas de définition on retourne la racine
}
DefaultMutableTreeNode currentParentNode = rootNode; // le node courant dans lequel on ajoute des nodes de nivea uinférieur
Stack<DefaultMutableTreeNode> stack = new Stack<>(); // pile pour gérer l'arborescence (la remontée surtout)
stack.push(currentParentNode);
int currentDepth = 0; // on considère qu'on démarre au niveau 0
for (String def : treeDef) {
// on calcul la différence de niveau avec le node précédemment ajouté
int itemDepth = 0;
for (int i = 0; def.charAt(i) == depthPrefix && i < def.length(); i++) {
itemDepth++;
}
int depthDiff = currentDepth - itemDepth;
if (depthDiff % tabLength != 0) {
throw new IllegalArgumentException(String.format("Bad tabulation length (must be multiple of %d) in \"%s\"", tabLength, def)); // on peut faire une exception spécifique
}
depthDiff /= tabLength; // nombre de niveau qu'on descend ou monte
if ( !allowEmptyNodes && depthDiff<-1 ) {
throw new IllegalArgumentException("Depth is growing too much (> 1)"); // on peut faire une exception spécifique
}
String item = def.substring(itemDepth); // valeur de l'item sans les tabulation
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(getItemValue(itemDepth, item)); // on créé le nouvel item
if ( depthDiff<0 ) { // on descend
// le nouveau node doit être ajouté à un niveau inférieur du précédent node, soit dans le dernier fils du parent actuel
DefaultMutableTreeNode lastSiblingNode;
if ( currentParentNode.isLeaf() ) { // pas de fils encore, on en créé un vide
lastSiblingNode = new DefaultMutableTreeNode( getEmptyNodeItemValue() );
currentParentNode.add(lastSiblingNode);
}
else {
lastSiblingNode = (DefaultMutableTreeNode) currentParentNode.getLastChild();
}
for( int i = -depthDiff-1; i>=0 ; i--) {
stack.push(currentParentNode); // on stocke tout nouveau niveau dans la pile, pour pouvoir remonter au bon node plus tard
currentParentNode = lastSiblingNode;
if ( i==0 ) {
// niveau inférieur atteint
currentParentNode.add(newNode);
} else {
// dans ce cas, on est descendu de plusieurs niveau : on intercale des nodes vides
lastSiblingNode = new DefaultMutableTreeNode( getEmptyNodeItemValue() );
currentParentNode.add(lastSiblingNode);
}
}
currentDepth = itemDepth;
} else if ( depthDiff>0) { // on remonte
for (int i = depthDiff-1; i >= 0; i--) { // on remonte d'un niveau de moins, parce que le currentParentNode est le parent du niveau actuel
currentParentNode = stack.pop();
}
currentParentNode.add(newNode); // on ajoute le nouveau node
currentDepth = itemDepth;
} else {// même niveau
currentParentNode.add(newNode); // on ajoute le nouveau node
}
}
return rootNode;
}
/**
* En redéfinissant cette méthode, on générer des objets différents, pour représenter les nodes
*
* @param itemDepth prodondeur de l'item
* @param item texte du node
* @return valeur pour un node
*/
protected Object getItemValue(int itemDepth, String item) {
return item.trim();
}
/**
* Génére la valeur utilisée pour faire des nodes de remplissage
*
* @return valeur pour un node vide
*/
protected Object getEmptyNodeItemValue() {
return "...";
}
public static void main(String[] args) {
String[] treeDef = { "Les saisons",
"---Printemps",
"------Mars",
"---------Les fleurs bourgeonnent ",
"------Avril",
"------Mai",
"---Ete",
"------Juin",
"---------Voila les beaux jours",
"------Juillet",
"------Aout",
"---Automne",
"------Septembre",
"---------Rentree des ecoliers",
"------Octobre",
"------Novembre",
"---Hiver",
"------Décembre",
"---------On attend la neige",
"------Janvier",
"------Février"
};
TreeNode tree = new TreeFactory().createTreeNode(
Arrays.asList(treeDef), '-', 3);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTree jtree=new JTree(tree);
jtree.setRootVisible(false);
jtree.setShowsRootHandles(true);
jtree.setExpandsSelectedPaths(true);
for (int i = 0; i < jtree.getRowCount(); i++) {
jtree.expandRow(i);
}
frame.getContentPane().add(new JScrollPane(jtree));
frame.setSize(300, 450);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
} |
Partager