Lorsque vous développez des programmes d'interface utilisateur à l'aide de Java Swing, vous êtes susceptible de rencontrer la nécessité d'utiliser une arborescence avec des cases, mais Java Swing ne fournit pas ce composant, donc si vous avez cette exigence, vous devez implémenter un arbre avec des cases vous-même.
Il existe des différences entre CheckBoxTree et Jtree à deux niveaux:
1. Sur la couche de modèle, chaque nœud de CheckBoxTree a besoin d'un membre pour enregistrer s'il est sélectionné, mais les nœuds JTree ne le font pas.
2. Sur le calque de vue, chaque nœud de CheckBoxTree affiche une case de plus que le nœud de Jtree.
Puisqu'il y a deux différences, tant que nous remplissons ces deux différences avec notre propre implémentation, l'arbre avec cases sera implémenté.
Maintenant, commencez à résoudre la première différence. Pour résoudre la première différence, une nouvelle classe de classe de nœud à cocher boxtEenode doit être définie, ce qui hérite du defaultMutableTreenode et ajoute un nouveau membre Isselued pour indiquer si le nœud est sélectionné. Pour un cocher à cocher, si un nœud est sélectionné, sa case à cocher sera cochée et la motivation pour l'utilisation de CheckBoxTree est de sélectionner un sous-arbre à la fois. Ensuite, lorsqu'un nœud est sélectionné ou annulé, son nœud ancêtre et son nœud descendant doivent apporter quelques modifications. Ici, nous appliquons les règles récursives suivantes:
1. Si un nœud est sélectionné manuellement, tous ses descendants doivent être sélectionnés; Si le nœud est sélectionné pour faire sélectionner tous les enfants de son nœud parent, son nœud parent est sélectionné.
2. Si un nœud n'est pas contrôlé manuellement, tous ses descendants doivent être incontrôlés; Si le nœud parent du nœud est sélectionné, son nœud parent n'est pas contrôlé.
Remarque: Les deux règles ci-dessus sont des règles récursives. Lorsqu'un nœud change et provoque un autre changement de nœud, un autre nœud entraînera également le changement d'autres nœuds. Dans les deux règles ci-dessus, la sélection manuelle ou la désélection manuelle d'un nœud provoquera une sélection non manuelle ou un non-sélection des autres nœuds. Cette sélection non manuelle ou non-insélectionnée de cette sélection non manuelle ou non sécurisée ne s'appliquera pas aux règles ci-dessus.
Le code source de CheckBoxTreenode implémenté conformément aux règles ci-dessus est la suivante:
Demo de package; Importer javax.swing.tree.defaultMutableTreenode; Classe publique CheckBoxTreenode étend defaultMutableTreenode {Boolean Protected ISSelected; public CheckboxTreenode () {this (null); } public checkboxTreenode (objet userObject, true, false); } public CheckboxTreenode (objet userObject, booléen permis, booléen issélecté) {super (userObject, permettre aux enfants); this.isselected = ISSelected; } public boolean isselected () {return isselected; } public void SetSelected (boolean _isselected) {this.isselected = _isselected; if (_isselected) {// Si vous sélectionnez, sélectionnez tous ses nœuds enfants if (enfants! = null) {for (objet obj: enfants) {CheckBoxTreenode node = (checkboxTreenode) obj; if (_isselected! = node.isselected ()) node.setSelected (_isselected); }} // Vérifiez, si tous les nœuds enfants du nœud parent sont sélectionnés, sélectionnez le parent à cochéage de nœud parent PNODE = (CheckBoxTeenode); // Commencez à vérifier si tous les nœuds enfants du pnode sont sélectionnés if (pNode! = Null) {int index = 0; for (; index <pnode.children.size (); ++ index) {checkboxTeReenode pChildNode = (CheckBoxTeenode) pnode.children.get (index); if (! pchildNode.isselected ()) Break; } / * * Indique que tous les nœuds enfants de Pnode ont été sélectionnés, le nœud parent est sélectionné. * Cette méthode est une méthode récursive, il n'est donc pas nécessaire d'itérer ici, car * lorsque le nœud parent est sélectionné, le nœud parent lui-même vérifiera vers le haut. * / if (index == pnode.children.size ()) {if (pnode.isselected ()! = _isselected) pnode.setSelected (_isselected); }}} else {/ * * Si l'annulation du nœud parent entraîne l'annulation du nœud enfant, tous les nœuds enfants doivent être sélectionnés à l'heure actuelle; * Sinon, l'annulation du nœud enfant entraînera l'annulation du nœud parent, puis l'annulation du nœud parent entraînera l'annulation du nœud enfant, mais * n'est pas nécessaire d'annuler le nœud enfant à ce moment. * / if (enfants! = null) {int index = 0; for (; index <enfants.size (); ++ index) {checkBoxTeenode childNode = (checkboxTreenode) kniad.get (index); if (! childNode.isselected ()) Break; } // lors de l'annulation de haut en bas if (index == children.size ()) {for (int i = 0; i <children.size (); ++ i) {checkboxTreenode node = (checkboxTreenode) children.get (i); if (node.isselected ()! = _isselected) node.setSelected (_isselected); }}} // Annuler, tant qu'il y a un nœud enfant qui n'est pas sélectionné, le nœud parent ne doit pas être sélectionné. CheckboxTreenode PNode = (CheckBoxTreenode) Parent; if (pNode! = null && pnode.isselected ()! = _isselected) pnode.setselected (_isselected); }}} La première différence est résolue en héritant de la définition de défaut de défaut à cocher la définition de la définition, et la deuxième différence doit être résolue ensuite. La deuxième différence est la différence d'apparence, et chaque nœud de Jtree est affiché via TreeCellRenderer. Pour résoudre la deuxième différence, nous définissons une nouvelle classe CheckBoxTreeCellRenderer qui implémente l'interface TreeCellRenderer. Le code source de CheckBoxTreeRereger est le suivant:
Demo de package; import java.awt.color; Importer java.awt.component; import java.awt.dimension; Importer javax.swing.jCheckbox; import javax.swing.jpanel; import javax.swing.jtree; import javax.swing.uimanager; Importer javax.swing.plaf.coloruiresource; Importer javax.swing.tree.treecellRenderer; classe publique CheckboxTreeCellRenderer étend JPanel implémente TreeCellRenderer {Protection JCheckBox Check; Étiquette à cocher protégée à CheckTeleabel; public CheckBoxTreeCellRenderer () {setLayout (null); add (check = new JCheckbox ()); add (label = new CheckBoxTreelAbel ()); check.setbackground (uimanager.getColor ("Tree.TextBackground")); label.setForeground (uimanager.getColor ("Tree.TextForeground")); } / ** * Renvoie un objet <code> jpanel </code>, qui contient un objet <code> jcheckbox </code> et un objet <code> jLabel </code>. Et décider si <code> jcheckbox </code> * est sélectionné selon si chaque nœud est sélectionné. * / @Override Component public gettreeCellRendererComponent (arbre Jtree, valeur d'objet, booléen sélectionné, boolean étendu, feuille booléenne, ligne int, booléen hasfocus) {string stringValue = Tree.ConvertValutotext (valeur, sélectionnée, élargie, feuille, ligne, hasfocus); setEnabled (arbre.iseNabled ()); check.Setselected (((CheckboxTreenode) Value) .isselected ()); label.setfont (arbre.getfont ()); Label.SeTText (StringValue); Label.SetSelected (sélectionné); Label.setFocus (HasFocus); if (Leaf) Label.seTICon (uimanager.geTicon ("Tree.leaficon")); else if (étendu) label.seticon (uimanager.geTicon ("Tree.OpenIcon")); else Label.seTICon (uimanager.geTicon ("Tree.ClosediCon")); retourner ceci; } @Override public dimension getPreferRedSize () {dimension dCheck = check.getPreferRedSize (); Dimension dLabel = label.getPreferRedSize (); retourner la nouvelle dimension (dcheck.width + dLabel.width, dcheck.height <dLabel.height? dLabel.height: dcheck.height); } @Override public void dolayout () {dimension dCheck = check.getPreferRedSize (); Dimension dLabel = label.getPreferRedSize (); int ycheck = 0; int yLabel = 0; if (dcheck.height <dlabel.height) ycheck = (dLabel.height - dcheck.height) / 2; else ylabel = (dcheck.height - dlabel.height) / 2; check.setLocation (0, ycheck); check.setbounds (0, ycheck, dcheck.width, dcheck.height); Label.SetLocation (dcheck.width, ylabel); Label.SetBounds (dcheck.width, ylabel, dlabel.width, dLabel.height); } @Override public void setackground (couleur couleur) {if (instance de couleur de coloriireSource) color = null; super.setbackground (couleur); }} Dans l'implémentation de CheckBoxTreeCellRenderer, la méthode GetTreeCellRendeRerComponent renvoie JPanel, au lieu de renvoyer JLabel comme DefaultTreeCellRenderer. Par conséquent, le JLabel dans le JPanel ne peut pas réagir à la sélection. Par conséquent, nous avons réimplémenté une sous-classe de JLabel CheckboxTreelabel, qui peut réagir à la sélection, et son code source est le suivant:
Demo de package; import java.awt.color; import java.awt.dimension; import java.awt.graphics; Importer javax.swing.icon; import javax.swing.jlabel; import javax.swing.uimanager; Importer javax.swing.plaf.coloruiresource; classe publique CheckBoxTreelabel étend JLabel {private booléen isselected; Boolean privé Hasfocus; public CheckBoxTreelAbel () {} @Override public void setbackground (couleur couleur) {if (instance de couleur de coloriireSource) color = null; super.setbackground (couleur); } @Override public void peinture (graphiques g) {String str; if ((str = getText ())! = null) {if (0 <str.length ()) {if (isselected) g.setColor (uiManager.getColor ("arbre.selectionbackground")); else g.setColor (uiManager.getColor ("Tree.TextBackground")); Dimension d = getPreferRedSize (); int imageoffset = 0; Icon currentIcon = geticon (); if (currentIcon! = null) imageoffset = currentIcon.geTIConWidth () + math.max (0, getIConTextGap () - 1); G.Fillrect (ImageOffset, 0, D.Width - 1 - ImageOffset, D.Height); if (Hasfocus) {g.setColor (uimanager.getColor ("Tree.SelectionborderColor")); G.Drawrect (ImageOffset, 0, D.Width - 1 - ImageOffset, D.Height - 1); }}} super.paint (g); } @Override public dimension getPreferRedSize () {dimension retdimension = super.getPreferredSize (); if (retdimension! = null) retdimension = new dimension (retdimension.width + 3, retdimension.height); retour retdimension; } public void SetSelected (boolean isselected) {this.isselected = isselected; } public void setFocus (boolean hasfocus) {this.hasfocus = hasfocus; }} En définissant CheckBoxTreenode et CheckBoxTreeCellRenderer. Nous avons résolu les deux différences fondamentales entre CheckBoxTree et Jtree, mais il y a toujours un problème détaillé qui doit être résolu, c'est-à-dire que CheckBoxTree peut décider de sélectionner un certain nœud en réponse aux événements utilisateur. Pour ce faire, nous ajoutons un écouteur à CheckBoxTree qui répond aux événements de la souris utilisateur. Le code source de cette classe est le suivant:
Demo de package; Importer java.awt.event.mousEadapter; Importer java.awt.event.mousevent; import javax.swing.jtree; Importer javax.swing.tree.treepath; Importer javax.swing.tree.defaultTreemodel; classe publique CheckBoxTereenoDeSelectionListener étend MousEadapter {@Override public void MouseClicked (événement MouseEvent) {Jtree Tree = (jTree) event.getsource (); int x = event.getx (); int y = event.gety (); int row = arbre.getRowForLocation (x, y); Treepath Path = Tree.getPathForrow (Row); if (path! = null) {checkBoxTreenode node = (checkboxTeenode) path.getlastPathComponent (); if (node! = null) {boolean isselected =! node.isselected (); Node.SetSelected (ISSELECT); ((DefaultTrEemodel) Tree.getModel ()). NodestructureChanged (Node); }}}}} Jusqu'à présent, tous les composants requis par CheckBoxTree ont été terminés et l'étape suivante est de savoir comment les utiliser. Le code source pour l'utilisation de ces composants est donné ci-dessous:
Demo de package; import javax.swing.jframe; import javax.swing.jscrollpane; import javax.swing.jtree; Importer javax.swing.tree.defaultTreemodel; classe publique Demomain {public static void main (String [] args) {jframe frame = new JFrame ("CheckBoxTreeDemo"); frame.setbounds (200, 200, 400, 400); Jtree arbre = new Jtree (); CheckBoxTeReenode rootNode = new CheckBoxTreenode ("root"); CheckBoxTreenode Node1 = nouveau CheckBoxTreenode ("Node_1"); CheckBoxTreenode Node1_1 = nouveau CheckBoxTreenode ("Node_1_1"); CheckboxTreenode Node1_2 = nouveau CheckBoxTreenode ("Node_1_2"); CheckboxTreenode Node1_3 = nouveau CheckBoxTreenode ("Node_1_3"); Node1.add (Node1_1); Node1.add (Node1_2); Node1.add (Node1_3); CheckBoxTreenode Node2 = nouveau CheckBoxTreenode ("Node_2"); CheckboxTreenode Node2_1 = nouveau CheckBoxTreenode ("Node_2_1"); CheckboxTreenode Node2_2 = nouveau CheckBoxTreenode ("Node_2_2"); node2.add (node2_1); node2.add (node2_2); rootNode.add (Node1); rootNode.add (Node2); DefaultTrEemodel modèle = new defaultTreemodel (rootNode); Tree.AddMouseListener (nouveau CheckBoxTreenOdeselectionListener ()); Tree.setModel (modèle); Tree.SetCellRenderer (nouveau CheckBoxTreeCellRenderer ()); JscrollPane Scroll = new JscrollPane (arbre); Scroll.SetBounds (0, 0, 300, 320); frame.getContentPane (). Add (Scroll); frame.setDefaultCloseOperation (jframe.exit_on_close); frame.setVisible (true); }}Les résultats de l'exécution sont présentés dans la figure ci-dessous:
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.