swing:tree

Δένδρα (Trees)

Μπορείτε να δημιουργήσετε μία δενδρική δομή απεικόνισης των δεδομένων σας με χρήση της κλάσης JTree. Ένα παράδειγμα δενδρικής δομής δίνεται στο παρακάτω σχήμα.

Όπως φαίνεται στο παραπάνω σχήμα ένα Component τύπου JTree απεικονίζει τα δεδομένα του κατακόρυφα ξεκινώντας από ένα κόμβο που ονομάζεται ρίζα του δένδρου και κάθε γραμμή του δένδρου περιέχει μόνο ένα κόμβο. Ένας κόμβος μπορεί να έχει ένα ή περισσότερα παιδιά (branch node) ή όχι (leaf node). Ένας κόμβος μπορεί να προσδιοριστεί μέσα από το TreePath το οποίο προσδιορίζει τη σειρά τον κόμβων από την ρίζα και έως τον συγκεκριμένο κόμβο.

Μπορείτε να δείτε το παράδειγμα δημιουργίας και διαχείρισης ενός JTree από το site της Oracle. Παρακάτω θα αναλύσουμε τα διάφορα στάδια του προγράμματος.

Δημιουργία του δένδρου

Κάθε δένδρο είναι ένα αντικείμενο της κλάσης JTree. Επίσης ένα δένδρο περιέχει τον κόμβο που αντιστοιχεί στην ρίζα του δένδρου, αλλά και όλους τους άλλους κόμβους που συναποτελούν το δένδρο και διαμορφώνουν την τελική δενδρική δομή. Κάθε κόμβος του δένδρου θα πρέπει να υλοποιεί το interface MutableTreeNode. Οι μέθοδοι του συγκεκριμένου interface δίνονται παρακάτω:

void insert(MutableTreeNode child, int index)
//Adds child to the receiver at index.
 
void remove(int index)
//Removes the child at index from the receiver.
 
void remove(MutableTreeNode node)
//Removes node from the receiver.
 
void removeFromParent()
//Removes the receiver from its parent.
 
void setParent(MutableTreeNode newParent)
//Sets the parent of the receiver to newParent.
 
void setUserObject(Object object)
Resets the user object of the receiver to object.

Από τις παραπάνω μεθόδους είναι προφανές ότι σε ένα κόμβο μπορείτε να προσθέσετε άλλους κόμβους ή να αφαιρέσετε κόμβους ή να μετακινήσετε κόμβους. Ένας απλός τρόπος ώστε οι κόμβοι σας να υλοποιούν το συγκεκριμένο interface είναι να ανήκουν στην κλάση DefaultMutableTreeNode που υλοποιεί το συγκεκριμένο interface. Η κλάση αυτή περιέχει πολλές βοηθητικές μεθόδους οι οποίες σας βοηθούν να πλοηγηθείτε στο δένδρο όταν το χρειαστείτε. Παρακάτω δίνεται ο κώδικας που δημιουργεί το δένδρο.

DefaultMutableTreeNode top =
  new DefaultMutableTreeNode("The Java Series");
  createNodes(top);
 
  //Create a tree that allows one selection at a time.
  tree = new JTree(top);
  tree.setEditable(true);
  tree.getSelectionModel().setSelectionMode
      (TreeSelectionModel.SINGLE_TREE_SELECTION);

Ο παραπάνω κώδικας δημιουργεί το στοιχείο της ρίζας με τον όνομα top και με βάση αυτό δημιουργεί και τα υπόλοιπα αντικείμενα μέσω της μεθόδου void createNodes(DefaultMutableTreeNode top). Στην συνέχεια, δημιουργεί το δένδρο στο οποίο ορίζει ως ρίζα το στοχείο top. Επίσης, ορίζει ότι το δένδρο μπορεί να μεταβληθεί από τον χρήστη και ορίζει ότι μόνο ένας κόμβος του δένδρου μπορεί να επιλεγεί από τον χρήστη κάθε φορά.

  tree.setEditable(true);
  tree.getSelectionModel().setSelectionMode
      (TreeSelectionModel.SINGLE_TREE_SELECTION);

Οι επιλογές που έχετε αναφορικά με τον αριθμό των κόμβων που μπορείτε να επιλέξετε είναι οι παρακάτω:

static int CONTIGUOUS_TREE_SELECTION
//Πολλαπλοί συνεχόμενοι κόμβοι
static int DISCONTIGUOUS_TREE_SELECTION
//Πολλαπλοί κόμβοι, όχι απαραίτητα συνεχόμενοι
static int SINGLE_TREE_SELECTION
//Μόνο ένας κόμβος μπορεί να επιλεγεί κάθε φορά.

Παρακάτω δίνεται ένα τμήμα της μεθόδου createNodes.

  private void createNodes(DefaultMutableTreeNode top) {
    DefaultMutableTreeNode category = null;
    DefaultMutableTreeNode book = null;
 
    category = new DefaultMutableTreeNode("Books for Java Programmers");
    top.add(category);
 
    //original Tutorial
    book = new DefaultMutableTreeNode(new BookInfo
      ("The Java Tutorial: A Short Course on the Basics",
      "tutorial.html"));
    category.add(book);
 
    //Tutorial Continued
    book = new DefaultMutableTreeNode(new BookInfo
      ("The Java Tutorial Continued: The Rest of the JDK",
      "tutorialcont.html"));
    category.add(book);
 
    //JFC Swing Tutorial
    book = new DefaultMutableTreeNode(new BookInfo
      ("The JFC Swing Tutorial: A Guide to Constructing GUIs",
      "swingtutorial.html"));
    category.add(book);
 
    ....
  }

Από τον παρακάτω κατασκευαστή της κλάσης DefaultMutableTreeNode παρατηρούμε ότι κατά την δημιουργία αντικειμένων της κλάσης αυτής μπορούμε να αποθηκεύσουμε οποιοδήποτε αντικείμενο μέσα σε αυτή.

public DefaultMutableTreeNode(Object userObject);

Έτσι στη μέθοδο createNodes αποθηκεύονται Strings, αν πρόκειται για κόμβους που αναφέρονται στις κατηγορίες των βιβλίων ή αντικείμενα της κλάσης BookInfo αν πρόκειται για βιβλία. Αντίστοιχα, αν θέλετε να λάβετε το περιεχόμενο ενός κόμβου μπορείτε να το προσπελάσετε με την μέθοδο

public Object getUserObject()

Σε αυτή την περίπτωση θα χρειαστείτε να γνωρίζετε την κλάση του αντικειμένου το οποίο επιστρέφει η παραπάνω μέθοδος και να εφαρμόσετε κατάλληλο typecasting.

Ανταποκρινόμενοι στα events ενός δένδρου

Ένα δένδρο μπορεί να παράγει δύο τύπους events:

  • TreeSelectionEvent: events που συνδέονται με επιλογή κόμβων του δένδρου. Τα events αυτά λαμβάνονται μέσα από ένα αντικείμενο που υλοποιεί το interface TreeSelectionListener.
  • TreeModelEvent: events που συνδέονται με μεταβολή της δομής του δένδρου. Τα events αυτά λαμβάνονται μέσα από ένα αντικείμενο που υλοποιεί το interface TreeModelListener.

TreeSelectionEvents

Σε όλα τα events που συνδέονται με ένα αντικείμενο μπορείτε να πάρετε το αντικείμενο το οποίο συνδέεται με το event μέσα από την μέθοδο public Object getSource() της κλάσης EventObject. Εκτός της παραπάνω μεθόδου, οι μέθοδοι που υποστηρίζει κάθε event αυτού του τύπου είναι τα εξής:

Object  cloneWithSource(Object newSource)
//Returns a copy of the receiver, but with the source being newSource.
 
TreePath  getNewLeadSelectionPath()
//Returns the current lead path.
 
TreePath  getOldLeadSelectionPath()
//Returns the path that was previously the lead path.
 
TreePath  getPath()
//Returns the first path element.
 
TreePath[]  getPaths()
//Returns the paths that have been added or removed from the selection.
 
boolean   isAddedPath()
//Returns whether the path identified by getPath was added to the selection.
 
boolean   isAddedPath(int index)
//Returns whether the path at getPaths()[index] was added to the selection.
 
boolean   isAddedPath(TreePath path)
//Returns whether the specified path was added to the selection.

Στο δένδρο του τρέχοντος παραδείγματος μας που υποστηρίζει το μοντέλο επιλογής κόμβων SINGLE_TREE_SELECTION η μόνη μέθοδος που σας χρειάζεται είναι η getPath() από την οποία λαμβάνεται το TreePath του κόμβου που επιλέξατε.

Αντίστοιχα, το interface TreeSelectionListener υποστηρίζει μόνο μία μέθοδο η οποία καλείται κάθε φορά που επιλέγεται νέος κόμβος, όπως φαίνεται παρακάτω.

void valueChanged(TreeSelectionEvent e)
Called whenever the value of the selection changes.

TreeModelEvents

Τα events αυτού του τύπου δημιουργούνται όταν έχουμε μεταβολή στην δομή του δένδρου. Σε αυτή την περίπτωση θα χρειαστείτε μία κλάση που υλοποιεί το interface TreeModelListener για να λάβετε τις μεταβολές στη δομή του δένδρου. Ο συγκεκριμένος Listener ορίζει τις παρακάτω μεθόδους.

void treeNodesChanged(TreeModelEvent e)
//Invoked after a node (or a set of siblings) has changed in some way.
 
void treeNodesInserted(TreeModelEvent e)
//Invoked after nodes have been inserted into the tree.
 
void treeNodesRemoved(TreeModelEvent e)
//Invoked after nodes have been removed from the tree.
 
void treeStructureChanged(TreeModelEvent e)
//Invoked after the tree has drastically changed structure from a given node down.

Αλλάζοντας τα εικονίδια και την εμφάνιση στους κόμβους ενός δένδρου

Ένα από τα βασικά πράγματα που πιθανόν θα χρειαστείτε είναι να μεταβάλλεται την εμφάνιση των κόμβων ενός δένδρου βάζοντας διαφορετικά εικονίδια για τους κόμβους που είναι φύλλα, για τους κόμβους που δεν είναι φύλλα, αλλά είναι επιλεγμένοι και ανοιχτοί ή για τους κόμβους που είναι κλειστοί. Για να το κάνετε αυτό θα χρειαστείτε ένα αντικείμενο που υλοποιεί το interface TreeCellRenderer. Η πιο απλή επιλογή είναι να χρησιμοποιήσετε την κλάση DefaultTreeCellRenderer. Το παρακάτω απόσπασμα είναι ενδεικτικό για το πως μπορείτε να αλλάξετε τα εικονίδια των κόμβων σε κάθε μία από τις παραπάνω κατηγορίες.

  DefaultTreeCellRenderer tRenderer =  
        new DefaultTreeCellRenderer();
  ImageIcon folderIcon = new ImageIcon( System.getProperty("user.dir")+"/icons/small/folder.png" );
  tRenderer.setLeafIcon( folderIcon );
  tRenderer.setClosedIcon( folderIcon );
  tRenderer.setOpenIcon( folderIcon );
  tRenderer.setTextSelectionColor(Color.RED);
  tree.setCellRenderer(tRenderer);
swing/tree.txt · Last modified: 2016/02/26 11:15 (external edit)