Java programming course: 17.3 Modifying AdministratorFrame


Modifying AdministratorFrame

The frame now needs to show AnimalPanel inside a new tab of the JTabbedPane:

package virtualzoo.ui;

import virtualzoo.core.*;
import java.awt.*;
import javax.swing.*;

public class AdministratorFrame extends JFrame {
    
    private ZooKeeperEditor zooKeeperEditor;
    
    public AdministratorFrame() {
        super("Zoo Administrator");
        setLayout(new BorderLayout());
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        ZooAdministrator admin = ZooAdministrator.getInstance();
        
        // Create tabbed pane
        JTabbedPane tabPane = new JTabbedPane();
        
        // Create animal panel
        AnimalPanel animalPanel = new AnimalPanel();
        tabPane.addTab("Animals", animalPanel);
        
        // Create zoo keeper panel
        ZooKeeperPanel zooKeeperPanel = new ZooKeeperPanel();
        tabPane.addTab("Zoo Keepers", zooKeeperPanel);
        
        add(tabPane, BorderLayout.CENTER);        

        // Set components to their preferred size
        pack();
        
        // Place in the centre of the desktop
        setLocationRelativeTo(null);
    }
    
}
 

At this point you can run the application to ensure it appears as below:

Zoo Administrator frame with Animals tab

You can double-click the Animals node on the left to expand it, and then click the Pen sub-nodes that appear to see the animals in that pen. To make all the nodes expanded when you start the application add the following method inside AnimalTree:

private void expandNodes() {
    for (int i = 0; i < getRowCount(); i++) {
        expandRow(i);
    }
}
 
  • The getRowCount() method simply returns the total number of nodes in the tree, while expandRow() forces the specified node to be expanded.

Now call expandNodes() from the constructor:

public AnimalTree() {
    admin = ZooAdministrator.getInstance();
    root = new DefaultMutableTreeNode("Animals");
    model = new DefaultTreeModel(root);
    setModel(model);
    buildTree();
    expandNodes();
    getSelectionModel().setSelectionMode
            (TreeSelectionModel.SINGLE_TREE_SELECTION);
}
 

You will note that after entering some details and clicking the Save button the added animal is not appearing in the list on the left. This will be addressed in the next section.

Updating AnimalTree automatically

For the AnimalTree object to get notified whenever a change to the collection of animal objects held by the administrator changes it can implement the AnimalListener interface, so you will need to import virtualzoo.core.event:

package virtualzoo.ui;

import virtualzoo.core.*;
import virtualzoo.core.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;

public class AnimalTree extends JTree implements AnimalListener {
 

If you click the glyph that appears to the left of the class declaration statement above, you can click the option to implement all abstract methods. The following code will appear:

@Override
public void animalCreated(AnimalEvent event) {
    throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void animalChanged(AnimalEvent event) {
    throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void animalRemoved(AnimalEvent event) {
    throw new UnsupportedOperationException("Not supported yet.");
}
 

To handle the animalCreated() method first, insert the following code:

@Override
public void animalCreated(AnimalEvent event) {
    DefaultMutableTreeNode animalNode =
                         new DefaultMutableTreeNode(event.getAnimal());
    Pen pen = event.getAnimal().getPen();
    DefaultMutableTreeNode parentNode = getTreeNode(pen);
    model.insertNodeInto(animalNode, parentNode, parentNode.getChildCount());
    buildTree();
    model.reload();
    expandNodes();
}
 
  • Firstly, a new DefaultMutableTreeNode is created for the new Animal
  • Then the Pen it should be in is determined
  • The Pen is passed as an argument to getTreeNode() (a method to be written shortly) which will return the node which relates to the Pen
  • The insertNodeInto() method is invoked on the model to cause the new animal to appear in the tree
  • The tree is then rebuilt in order that the nodes are correctly sorted

The getTreeNode() method loops through each of the nodes under the root node until it finds the one in the argument, which it then returns:

private DefaultMutableTreeNode getTreeNode(Pen pen) {
    Enumeration penNodes = root.children();
    while (penNodes.hasMoreElements()) {
        DefaultMutableTreeNode penNode =
			(DefaultMutableTreeNode) penNodes.nextElement();
        Pen penNodePen = (Pen) penNode.getUserObject();
        if (penNodePen.equals(pen)) return penNode;
    }
    throw new IllegalArgumentException(pen + " not found");
}
 
  • An Enumeration is an alternative way of iterating over a group. The hasMoreElements() method returns true if there are more elements to process, and the nextElement() method returns the next element to be processed

You now need to wire up the AnimalTree object which is referenced in AnimalPanel so that it listens to events. In AnimalPanel import virtualzoo.core and define a new instance variable to reference the ZooAdministrator object:

private ZooAdministrator admin; 

Now change the constructor to obtain the ZooAdministrator object and call its addAnimalListener() method:

public AnimalPanel() {
    initComponents();
    admin = ZooAdministrator.getInstance();
    admin.addAnimalListener(animalTree);
}
 

You can now run the application, enter, and save one (or several) animals, and you should find the tree automatically updates itself.

Modifying existing animal details

Now that you have completed the code necessary to add new animals you need to enable their details to be changed. What you will do is detect whenever the user selects one of the names in AnimalTree and pass that selected Animal object to AnimalEditor so that it transitions into "change" mode.

The JTree class (of which AnimalTree is a subclass) supports the fact that client objects may wish to listen to selections of nodes in the tree. All client objects need to do is implement the TreeSelectionListener interface and provide the appropriate code in its required valueChanged() method. Then you can pass the client object as an argument to the addTreeSelectionListener() method of JTree. You will now code these steps.

Firstly, change the class header of AnimalPanel to implement TreeSelectionListener (you will also need to import the java.swing, javax.swing.event and javax.swing.tree packages):

package virtualzoo.ui;

import virtualzoo.core.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

public class AnimalPanel extends javax.swing.JPanel implements TreeSelectionListener {
 

Now you need to code the only method required by the interface:

@Override
public void valueChanged(TreeSelectionEvent e) {
    // A node has been selected from AnimalTree
    DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)
			     animalTree.getLastSelectedPathComponent();
    if (selectedNode != null) {
        Object selectedObject = selectedNode.getUserObject();
        if (selectedObject instanceof Animal) {
            Animal selectedAnimal = (Animal) selectedObject;
            animalEditor.setAnimal(selectedAnimal);
        }
    }
}
 
  • The valueChanged() method will be called every time the user selects an any node in the tree, which could be either an animal, a pen, or the root node
  • The getLastSelectedPathComponent() method retrieves the selected Object. This will be null if nothing is actually selected so it is tested to ensure that it is not null before continuing. Provided it is not null then it is checked to ensure that an animal node was selected, and if so, this gets cast from Object to Animal (any other type of node will be ignored)
  • You then pass the Animal object to the setAnimal() method of AnimalEditor, which you coded earlier

You need to ensure you listen to the tree selection events so invoke the registration in the constructor:

public AnimalPanel() {
    initComponents();
    admin = ZooAdministrator.getInstance();
    admin.addAnimalListener(animalTree);
    animalTree.addTreeSelectionListener(this);
}
 

In AnimalTree you need to ensure the tree is updated:

@Override
public void animalChanged(AnimalEvent event) {
    model.reload();
    expandNodes();
}
 


Print
×
Stay Informed

When you subscribe, we will send you an e-mail whenever there are new updates on the site.

Related Posts

 

Comments

No comments made yet. Be the first to submit a comment
Monday, 27 October 2025

Captcha Image