Clase de arbori generali din pachetul javax.swing

In pachetul javax.swing exista doua clase de arbori generali afisabili in interfata grafica. Una din ele, JFileChooser,  este specializata, fiind folosita pentru afisarea arborelui de fisiere si selectarea unui fisier din acest arbore. Cealalta clasa, JTree, are ca instante arbori generali creati de utilizator si afisabili pe ecran.
 

Clasa JFileChooser

Clasa javax.swing.JFileChooser ofera o interfata grafica pentru navigarea in sistemul de fisiere. Instanta acestei clase poate fi pusa intr-un container sau, recomandabil, intr-o fereastra de dialog.

Clasa JFileChooser are numerosi constructori si metode. La crearea instantelor acestei clase se poate indica sub diverse forme directorul care va servi drept radacina a arborelui. In lipsa, se considera ca radacina este directorul principal (home) al utilizatorului aplicatiei. Metodele permit, printre altele, sa se deschida o fereastra de dialog pentru selectarea fisierelor (in mod Open sau Save) si sa se determine calea si numele fisierului selectat.

Cand este selectat un fisier, instanta respectiva a clasei JFileChooser genereaza un eveniment de actiune (ActionEvent).
 
Dintre constructorii clasei JFileChooser mentionam aici:
   public JFileChooser() - creeaza un JFileChooser care porneste de la directorul principal al utilizatorului (user home directory);
   public JFileChooser(String currentDirectoryPath) - creeaza un JFileChooser care are ca radacina directorul da carui cale este data ca argument;
   public JFileChooser(File currentDirectory) - creeaza un JFileChooser care are ca radacina directorul da carui cale este data ca argument sub forma de instanta a clasei File; 

Dintre metodele clasei JFileChooser mentionam aici:
   public File getSelectedFile() - intoarce calea si numele fisierului selectat;
   public void setSelectedFile(File file) - seteaza fisierul selectat;
   public File[] getSelectedFiles() - intoarce tabloul fisiwerelor selectate (cand este permisa selectarea multipla);
   public void setSelectedFiles(File[] selectedFiles) - seteaza fisierele selectate (cand este permisa selectarea multipla);
   public File getCurrentDirectory() - intoarce directorul curent;
   public void setCurrentDirectory(File dir) - seteaza directorul curent;
   public void changeToParentDirectory() - se trece la directorul parinte al celui curent;
   public void rescanCurrentDirectory() - rescaneaza directorul curent (actualizeaza informatia despre continutul acestuia);
   public void ensureFileIsVisible(File f) - daca fisierul f este ascuns, il face vizibil;
   public int showOpenDialog(Component parent) - deschide o fereastra de dialog cu titlul Open, care contine un JFileChooser. Fereastra contine, de asemenea doua butoane: Open si Cancel. La apasarea unuia din aceste butoane fereastra se inchide, iar valoarea intoarsa este una din urmatoarele:
     JFileChooser.CANCEL_OPTION 
     JFileChooser.APPROVE_OPTION 
     JFileCHooser.ERROR_OPTION 
Ultima valoare intoarsa apare daca s-a produs o eroare.
   public int showSaveDialog(Component parent) - similar cu metoda precedenta, dar titlul ferestrei este Save, iar cele doua butoane sunt Save si Cancel;
   public void setMultiSelectionEnabled(boolean b) - seteaza modul de selectie: daca argumentul este true se seteaza selectia multipla, altfel cea simpla;
   public String getName(File f) - intoarce numele fisierului f;
   public Icon getIcon(File f) - intoarce pictograma fisierului f;
   public void addActionListener(ActionListener l) - adauga ascultatorul de evenimente de actiune.

Exemplu: In fisierul TestJFileChooser.java este dat un exemplu de aplicatie in care se testeaza functionarea unui JFileChooser. Aplicatia contine o interfata grafica (clasa GUI) care prezinta trei butoane:
   Open file - deschide o fereastra de dialog pentru deschidere de fisiere;
   Save file - deschide o fereastra de dialog pentru salvare de fisiere;
   Clear - sterge aria de text de afisare a mesajelor.
Daca se apasa pe unul din butoanele "Open file" sau "Save file" se deschide fereastra de dialog corespunzatoare, iar dupa ce se face selectia si se apasa unul din butoanele Open/Save sau Cancel se inchide fereastra si se afiseaza in aria de text din interfata grafica mesajul privind selectia facuta.

Clasa JTree

Clasa javax.swing.JTree are ca instante componente de control care vizualizeaza un arbore general si permite efectuarea de operatii asupra acestui arbore: selectarea unui nod, adaugarea sau eliminarea de fii ai nodului selectat etc. Arborele propriuzis este alcatuit din noduri care apartin unor clase care implementeaza interfata javax.swing.tree.TreeNode.

Forma sub care arborele este afisat pe ecran este asemanatoare cu cea sub care apare arborele sistemului de fisiere intr-un JFileChooser. Deosebirea este ca, acum, nodurile arborelui nu mai contin directoare sau fisiere, ci orice alte informatii, depinzand de aplicatie. Principalul avantaj al clasei JTree este ca da posibilitatea sa se lucreze cu arborele in mod interactiv, selectand diferite noduri ale acestuia prin intermediul interfetei grafice.

Ca exemplu, in fisierul TestJTree1.java este data o aplicatie simpla cu interfata grafica, in care apare o instanta a clasei JTree, creata prin instructiunea
    JTree tree=new JTree();
Acest constructor creeaza un JTree care contine deja in mod implicit un exemplu de arbore. Aplicatia vizualizeaza acest arbore pe ecran si afiseaza la partea de jos calea catre ultimul nod selectat. Se poate urmari modul in care se expandeaza si se colapseaza nodurile arborelui si se afiseaza efectul selectarii unui nod.
 
Dintre constructorii clasei JTree mentionam aici:
   public JTree() - creeaza un JTree care contine un exemplu de arbore; 
   public JTree(TreeNode root) - creeaza un JTree care are ca radacina nodul root, primit ca argument;
   public JTree(TreeModel newModel) - creeaza un JTree care contine un arbore care respecta modelul newModel.

Dintre metodele clasei JTree mentionam aici:
   public TreeModel getModel() - intoarce modelul arborelui (arborele propriu-zis, care contine datele);
   public void setModel(TreeModel newModel) - seteaza modelul arborelui;
   public TreePath getSelectionPath() - intoarce calea catre nodul selectat;
   public void addTreeSelectionListener(TreeSelectionListener tsl) - adauga la JTree un ascultator de evenimente de selectie;
   public void addTreeExpansionListener(TreeExpansionListener tel) - adauga la JTree un ascultator de evenimente de expandare;
   public void addTreeWillExpandListener(TreeWillExpandListener tel) - adauga un ascultator de evenimente care indica faptul ca urmeaza o expandare;

   public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf,  int row,  boolean hasFocus) - converteste valoarea din nod (obiectul de informatie atasat nodului respectiv) intr-un text afisabil pe ecran. Aceasta metoda este apelata de programul de vizualizare a arborelui. Pentru a se vizualiza nodul sub alta forma decat cea data de metoda toString()  a obiectului value din nodul respectiv,  este necesar sa definim propria noastra clasa de arbore, care extinde clasa JTree si in care sa fie redefinita metoda convertValueToText.

Precizam ca instantele clasei JTree nu contin arborele propriu-zis, ci numai reprezentarea grafica a arborelui. Aceasta reprezentare se creeaza la executarea unui constructor al clasei JTree. De exemplu, daca se executa expresia new JTree(radacina), in care radacina este referinta la un TreeNode, atunci se construieste reprezentarea grafica a arborelui care are ca radacina nodul radacina. Daca acest arbore isi modifica ulterior structura, este necesar sa se construiasca o alta instanta a clasei JTree, care reflecta noua structura.

Interfetele TreeNode si MutableTreeNode

Interfata javax.swing.tree.TreeNode defineste specificatiile pe care trebuie sa le respecte o clasa pentru a fi nod nemodificabil al unui JTree.
 
Conform acestei specificatii, orice clasa care are ca instante noduri ale unui JTree trebuie sa contina urmatoarele metode:

   public int getChildCount() - intoarce numarul de fii;
   public Enumeration children() - intoarce o enumeratie a fiilor nodului;
   public TreeNode getChildAt(int childIndex) - intoarce fiul cu indicele dat;
   public TreeNode getParent() - intoarce parintele (tatal) nodului;
   public int getIndex(TreeNode node) - intoarce indicele fiului node; daca nu exista un astfel de fiu, intoarce -1;
   public boolean getAllowsChildren() - intoarce true daca nodul admite fii;
   public boolean isLeaf() - intoarce true daca nodul este frunza;

Interfata javax.swing.tree.MutableTreeNode extinde interfata TreeNode pentru cazul in care nodul permite sa fie modificat. In consecinta, ea ofera si metodele necesare pentru modificarea nodului.
 
In plus fata de interfata TreeNode, interfata MutableTreeNode impune urmatoarele metode:
   public void insert(MutableTreeNode child, int index) - insereaza noul fiu child pe pozitia index;
   public void remove(int index) - elimina fiul de pe pozitia index;
   public void remove(MutableTreeNode node) - elimina fiul node;
   public void setUserObject(Object object) - inlocuieste obiectul de informatie din nod prin object;
   public void removeFromParent() - elimina nodul din lista fiilor parintelui acestuia;
   public void setParent(MutableTreeNode newParent) - pune nodul ca fiu al lui newParent.

Clasa DefaultMutableTreeNode

Clasa javax.swing.tree.DefaultMutableTreeNode implementeaza interfata MutableTreeNode si poate fi, deci, folosita pentru realizarea de noduri modificabile ale arborilor din clasa JTree. Clasa implementeaza toate metodele interfetelor TreeNode si MutableTreeNode si - in plus - ofera metode pentru toate tipurile cunoscute de parcurgere si traversare a arborilor. Nodul contine atat referinte catre fii, cat si catre parinte. Nodul radacina are referinta catre parinte nula. Remarcam, deci, ca aceasta clasa poate servi pentru realizarea unei mari varietati de arbori.
 
Clasa are urmatorii constructori:
   public DefaultMutableTreeNode() - creeaza un nod fara continut, dar modificabil;
   public DefaultMutableTreeNode(Object userObject) - creeaza un nod care contine obiectul userObject, nu are fii si este modificabil;
   public DefaultMutableTreeNode(Object userObject, boolean allowsChildren) - creeaza un nod care contine obiectul userObject, nu are copii, iar proprietatea de a fi modificabil este data de al doilea argument;

Clasa DefaultMutableTreeNode implementeaza toate metodele interfetelor TreeNode si MutableTreeNode. Dintre metodele pe care le contine in plus fata de interfetele mentionate, remarcam aici:
   public void setAllowsChildren(boolean allows) - seteaza proprietatea nodului de a admite copii;
   public Object getUserObject() - intoarce obiectul de informatie din nod;
   public void removeAllChildren() - elimina toti fiii;
   public void add(MutableTreeNode newChild) - elimina nodul newChild din lista fiilor fostului sau parinte si il adauga la sfarsitul listei fiilor acestui nod;
   public boolean isNodeAncestor(TreeNode anotherNode) - intoarce true daca nodul anotherNode este un "stramos" (ancestor)  al acestui nod;
   public boolean isNodeDescendant(DefaultMutableTreeNode anotherNode) - intoarce true daca nodul anotherNode este un descendent al acestui nod;
   public TreeNode getSharedAncestor(DefaultMutableTreeNode aNode) - intoarce cel mai apropiat stramos (ancestor) comun intre acest nod si aNode;
   public boolean isNodeRelated(DefaultMutableTreeNode aNode) - intoarce true daca nodul aNode se gaseste in acelasi arbore cu acest nod;
   public int getDepth() - intoarce adancimea (inaltimea) subarborelui care are acest nod ca racacina;
   public int getLevel() - intoarce nivelul nodului;
   public TreeNode[] getPath() - intoarce tabloul nodurilor de pe calea de la radacina la acest nod;
   public Object[] getUserObjectPath() - intoarce tabloul obiectelor de informatie continute in nodurile de pe calea de la radacina la acest nod;
   public TreeNode getRoot() - intoarce radacina arborelui in care se gaseste acest nod;
   public boolean isRoot() - intoarce true daca acest nod este radacina arborelui (are parinte null);
   public DefaultMutableTreeNode getNextNode() - intoarce nodul urmator la traversarea arborelui in preordine;
   public DefaultMutableTreeNode getPreviousNode() - intoarce nodul precedent la traversarea arborelui in preordine;
   public Enumeration preorderEnumeration() - intoarce o enumeratie pentru traversarea in preordine a subarborelui cu radacina in acest nod;
   public Enumeration postorderEnumeration() - intoarce o enumeratie pentru traversarea in postordine a subarborelui cu radacina in acest nod;
   public Enumeration breadthFirstEnumeration() - intoarce o enumeratie pentru traversarea in latime (pe niveluri) a subarborelui cu radacina in acest nod;
   public boolean isNodeChild(TreeNode aNode) - intoarce true daca nodul aNode este fiu al acestui nod;
   public TreeNode getFirstChild() - intoarce primul fiu al acestui nod;
   public TreeNode getLastChild() - intoarce ultimul fiu al acestui nod;
   public TreeNode getChildAfter(TreeNode aChild) - intoarce fiul care urmeaza dupa fiul aChild;
   public TreeNode getChildBefore(TreeNode aChild) - intoarce fiul care precede fiul aChild;
   public DefaultMutableTreeNode getFirstLeaf() - intoarce prima frunza descendenta a acestui nod;
   public DefaultMutableTreeNode getLastLeaf() - intoarce ultima frunza descendenta a acestui nod;
   public int getLeafCount() - intoarce numarul de frunze descendente ale acestui nod.

Exemplu: In fisierul TestJTree2.java este dat un exemplu de aplicatie in care se testeaza crearea si actualizarea unui arbore, ale carui informatii din noduri contin siruri de caractere. Nodurile arborelui sunt instante ale clasei DefaultMutableTreeNode. Reprezentarea grafica a arborelui se face printr-o instanta a clasei JTree, la construirea careia se da ca argument nodul radacina al arborelui. Interfata grafica contine la partea superioara un sir de butoane pentru adaugarea sau eliminarea unui nod si pentru traversarea arborelui in preordine, in postordine si in latime. Partea centrala a interfetei grafice contine un panou impartit in doua (JSplitPane), care are in partea stanga reprezentarea grafica a arborelui, iar in partea dreapta o arie de text pentru afisarea rezultatelor traversarii. La partea de jos este o eticheta pentru mesaje. Initial, arborele contine numai nodul radacina. Daca se selecteaza un nod si se apasa pe butonul "Pune fiu", apare o fereastra de dialog, in care se cere sa se introduca numele fiului. Dupa introducerea acestuia, se pune nodului selectat anterior un nou fiu cu numele dat de utilizator. Daca se selecteaza un nod si se apasa pe butonul "Elimina nod", se elimina nodul selectat. Daca se apasa pe unul din butoanele "In preordine", "In postordine" sau "In latime", se afiseaza in aria de text rezultatul traversarii de tipul corespunzator. In fine, daca se apasa butonul "Stergere text", se sterge continutul ariei de text.

La fiecare adaugare sau eliminare de nod se creeaza o noua instanta a clasei JTree si se pune in locul celei anterioare.
 
Consideram ca programul clasei TestJTree2 este usor de urmarit, atat datorita modularizarii specifice programarii orientate pe obiecte, cat si datorita comentariilor pe care le contine. Vom face deci aici numai cateva precizari suplimentare.

Pentru crearea arborelui s-au folosit instructiunile
   radacina=new DefaultMutableTreeNode("Radacina arborelui");
   tree=new JTree(radacina);
S-a creat astfel un  nod, referit prin variabila radacina, apoi s-a creeat o instanta JTree folosind arborele cu aceasta radacina. Daca arborele nu ar fi fost modificabil, era necesar sa se construieasca mai intai intregul arbore prin adaugarea la radacina a tuturor subarborilor acesteia si abia la sfarsit sa se creeze clasa JTree, care contine reprezentarea grafica a arborelui.

Era posibil, de asemenea, sa se creeze arborele prin instructiunile urmatoare:
   radacina=new DefaultMutableTreeNode("Radacina arborelui");
   modelArbore=new DefaultTreeModel(radacina);
   tree=new JTree(modelArbore);
Unde modelArbore este o referinta la DefaultTreeModel. Aceasta ar fi permis o mai mare flexibilitate, deoarece era posibil sa se asculte si evenimentele din clasa TreeModelEvent.

Pentru ascultarea evenimentelor de selectie s-a creat clasa AscultSelectie. Metoda valueChanged a
acestei clase determina si memoreaza in variabila path calea catre ultimul nod selectat.

Modificarea arborilor se face prin metodele claselor ascultatoare PuneFiu si EliminaNod, care asculta evenimentele de actiune generate de butoanele cu aceleasi nume.

In metoda actionPerformed a clasei PuneFiu se cere utilizatorului, printr-o fereastra de dialog, sa se introduca numele fiului adaugat, dupa care se determina nodul selectat ca fiind ultimul din calea selectata si i se pune un fiu cu continutul dat de utilizator, dupa care se reconstruieste instanta clasei JTree pentru noul arbore si se pune in interfata grafica in locul celei vechi.

In metoda actionPerformed a clasei EliminaNod se determina nodul de eliminat, ca fiind ultimul nod din calea selectata, si i se aplica acestui nod metoda removeFromParent(), facandu-se astfel efectiv eliminarea lui din arbore. Daca acest nod este radacina unui subarbore, se elimina intregul subarbore. Dupa eliminare, se reconstruieste instanta clasei JTree si se pune in locul celei vechi.

Pentru traversarea arborelui in preordine, in postordine si in latime s-a creat clasa ascultatoare Traversari, care invoca metodele de traversare corespunzatoare ale clasei DefaultMutableTreeNode. Aceste metode intorc o enumeratie (un iterator) care respecta interfata java.util.Enumeration. Aceasta enumeratie este apoi folosita pentru afisarea in aria de text a succesiunii nodurilor in traversarea respectiva.

In acest exemplu s-au folosit numai o mica parte din facilitatile oferite de clasele JTree, DefaultMutableTreeModel si clasele conexe. Pentru aprofundare recomandam consultarea capitolului How to Use Trees din sectiunea Creating a GUI with JFC/Swing, subsectiunea Using Swing Components a tutorialului Java (The Java Tutorial, al firmei Sun) .



© Copyright 2001 - Severin BUMBARU, Universitatea "Dunarea de Jos" din Galati