EXAMPLE GUI APPLICATION --- DECISION TREE PROGRAM (SWING EXAMPLE)

CONTENTS

1. Introduction
2. Decision tree GUI code


1. INTRODUCTION

In this WWW page I have presented an entire GUI application example based on the decision tree example programme given earlier. I have included in the example a further illustration of the append method found in the JTextArea class and illustrated previously with respect to JButton Swing objects. I have also included a further example of the showMessageDialog method which I have used for error messaging. The example is no longer generic (as was the case for previous decision tree example) in that it operates with a hard coded tree, i.e. it cannot be passed a tree from an application class (although this would not be difficult to include).



2. DECISION TREE GUI CODE

The code presented in Table 1 is the main body of the decision tree example. An accompanying application class is given in Table 2 and some example output in Figure 1. An example of the error message window produced using the showMessageDialog method is given in Figure 2.

// DECISION TREE
// Frans Coenen
// Thursday 15 August 2002
// Revised Thursday 20 March 2003
// Department of Computer Science, University of Liverpool

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DecisionTreeGui extends JFrame implements ActionListener {

    /* ------------------------------- */
    /*                                 */
    /*              FIELDS             */
    /*                                 */
    /* ------------------------------- */

    /* NESTED CLASS */

    private class BinTree {
        
        /* FIELDS */
        
        private int     nodeID;
        private String  questOrAns = null;
        private BinTree yesBranch  = null;
        private BinTree noBranch   = null;
        
        /* CONSTRUCTOR */
        
        public BinTree(int newNodeID, String newQuestAns) {
            nodeID     = newNodeID;
            questOrAns = newQuestAns;
            }
        }
	
    /* GUI FIELDS */	
    private JTextArea aTextArea = new JTextArea(20,40);
    private JButton pushButtonYes     = new JButton("Yes");   
    private JButton pushButtonGenerate   = new JButton("Generate"); 
    private JButton pushButtonQuery   = new JButton("Query");   
    private JButton pushButtonOutput  = new JButton("Output");   
    private JButton pushButtonNo      = new JButton("No");    
    private int numButtonPresses = 0;  
      
    /* OTHER FIELDS */

    // Reference to start Node of decision tree
    BinTree rootNode = null;
    // Marker reference
    BinTree currentNode = null;
    
    /* ------------------------------------ */
    /*                                      */
    /*              CONSTRUCTORS            */
    /*                                      */
    /* ------------------------------------ */

    /* Default Constructor */

    public DecisionTreeGui(String text) {
        super(text);
	Container container = getContentPane();
	container.setLayout(new FlowLayout());
	container.setBackground(Color.yellow);
	
	/// Text fields
        
        container.add(new JScrollPane(aTextArea));   
	
	// Button
        container.add(pushButtonYes);
        container.add(pushButtonGenerate);
	container.add(pushButtonQuery);
	container.add(pushButtonOutput);
	container.add(pushButtonNo);
	
	// Register event handlers	
	pushButtonYes.addActionListener(this);
	pushButtonGenerate.addActionListener(this);
	pushButtonQuery.addActionListener(this);
	pushButtonOutput.addActionListener(this);
	pushButtonNo.addActionListener(this);
	}

    /* ----------------------------------------------- */
    /*                                                 */
    /*                   GUI METHODS                   */
    /*                                                 */
    /* ----------------------------------------------- */
    
    /* ACTION PERFORMED */
    
    /* Process button press events */
                     
    public void actionPerformed(ActionEvent event) {
        numButtonPresses++;
              
        if (event.getActionCommand().equals("Yes")) 
				yesButtonPressed();
	else if (event.getActionCommand().equals("Generate")) 
				GenerateButtonPressed();
	else if (event.getActionCommand().equals("Query")) 
				QueryButtonPressed();
        else if (event.getActionCommand().equals("Output")) 
				outputButtonPressed();
	else if (event.getActionCommand().equals("No")) 
				noButtonPressed();
    	}
	
    /* YES BUTTON PRESSED */
    
    private void yesButtonPressed() {        
        // Check if tree exists
	if (rootNode == null) {
	    noTreeToQueryErrorMessage();
	    return;
	    }
	    
        // Check if query process has been initialised
	if (currentNode == null) {
            noCurrentNodeErrorMessage();
            return;
            }
	
	// If tree exists process response
	aTextArea.append("Yes\n");
	currentNode = currentNode.yesBranch;
	outputNode();
	}
    
    /* GENERATE BUTTON PRESSED */
    
    private void GenerateButtonPressed() {
        aTextArea.append("GENERATE DECISION TREE\n");
        aTextArea.append("================\n");
        createRoot(1,"Does animal eat meat?");
        addYesNode(1,2,"Does animal have stripes?");
        addNoNode(1,3,"Does animal have stripes?");
        addYesNode(2,4,"Animal is a Tiger");
        addNoNode(2,5,"Animal is a Leopard");
        addYesNode(3,6,"Animal is a Zebra");
        addNoNode(3,7,"Animal is a Horse");
    	
	aTextArea.append("\n");
	}
	
    /* QUERY BUTTON PRESSED */
    
    private void QueryButtonPressed() {
        // Check if tree exists
	if (rootNode == null) {
	    noTreeToQueryErrorMessage();
	    return;
	    }
	
	// If tree exists commence query process.
        currentNode = rootNode;	
	aTextArea.append("QUERY DECISION TREE\n");
	aTextArea.append("=============\n");
	outputNode();
	}
	
    /* OUTPUT BUTTON PRESSED */
    
    private void outputButtonPressed() {
        
        // Check if tree exists
	if (rootNode == null) {
	    noTreeToOutputErrorMessage();
	    return;
	    }
	
	// If tree exists output    
	aTextArea.append("OUTPUT DECISION TREE\n");
        aTextArea.append("================\n");
	outputBinTree();
	aTextArea.append("\n");
	}
		
    /* NO BUTTON PRESSED */
    
    private void noButtonPressed() {
        // Check if tree exists
	if (rootNode == null) {
	    noTreeToQueryErrorMessage();
	    return;
	    }
        // Check if query process has been initialised
	if (currentNode == null) {
            noCurrentNodeErrorMessage();
            return;
            }
	
	// If tree exists process response
	aTextArea.append("No\n");
	currentNode = currentNode.noBranch;
	outputNode();
	}
    	
    /* ----------------------------------------------- */
    /*                                                 */
    /*            TREE BUILDING METHODS                */
    /*                                                 */
    /* ----------------------------------------------- */

    /* CREATE ROOT NODE */

    public void createRoot(int newNodeID, String newQuestAns) {
        rootNode = new BinTree(newNodeID,newQuestAns);  
        aTextArea.append("Created root node " + newNodeID + "\n");   
        }
             
    /* ADD YES NODE */

    public void addYesNode(int existingNodeID, int newNodeID, String newQuestAns) {
        // Check if root node exists        
        if (rootNode == null) {
            noRootNodeErrorMessage();
            return;
            }
	    
        // Query tree        
        if (searchTreeAndAddYesNode(rootNode,existingNodeID,newNodeID,newQuestAns)) {
            aTextArea.append("Added node " + newNodeID +
             " onto \"yes\" branch of node " + existingNodeID + "\n");
            }
        else aTextArea.append("Node " + existingNodeID + " not found\n");
        }

    /* SEARCH TREE AND ADD YES NODE */

    private boolean searchTreeAndAddYesNode(BinTree currentNode,
             int existingNodeID, int newNodeID, String newQuestAns) {
        if (currentNode.nodeID == existingNodeID) {
            // Found node
            if (currentNode.yesBranch == null) currentNode.yesBranch = new
             BinTree(newNodeID,newQuestAns);
            else {
                aTextArea.append("WARNING: Overwriting previous node " +
             		"(id = " + currentNode.yesBranch.nodeID +
             		") linked to yes branch of node " +
             		existingNodeID + "\n");
                currentNode.yesBranch = new BinTree(newNodeID,newQuestAns);
                }    
            return(true);
            }
        else {
            // Try yes branch if it exists
            if (currentNode.yesBranch != null) {        
                if (searchTreeAndAddYesNode(currentNode.yesBranch,
                     existingNodeID,newNodeID,newQuestAns)) {        
         return(true);
         }   
                else {
                // Try no branch if it exists
         if (currentNode.noBranch != null) {
             return(searchTreeAndAddYesNode(currentNode.noBranch,
                     existingNodeID,newNodeID,newQuestAns));
             }
         else return(false); // Not found here
         }
                }
            return(false);              // Not found here
            }
        }       
                
    /* ADD NO NODE */

    public void addNoNode(int existingNodeID, int newNodeID, String newQuestAns) {
        // Check if root node exists        
        if (rootNode == null) {
            noRootNodeErrorMessage();
            return;
            }
        
        // Search tree     
        if (searchTreeAndAddNoNode(rootNode,existingNodeID,newNodeID,newQuestAns)) {
            aTextArea.append("Added node " + newNodeID +
             	" onto \"no\" branch of node " + existingNodeID + "\n");
            }
        else aTextArea.append("Node " + existingNodeID + " not found\n");
        }
        
    /* SEARCH TREE AND ADD NO NODE */

    private boolean searchTreeAndAddNoNode(BinTree currentNode,
             int existingNodeID, int newNodeID, String newQuestAns) {
        if (currentNode.nodeID == existingNodeID) {
            // Found node
            if (currentNode.noBranch == null) currentNode.noBranch = new
             BinTree(newNodeID,newQuestAns);
            else {
                aTextArea.append("WARNING: Overwriting previous node " +
             		"(id = " + currentNode.noBranch.nodeID +
             		") linked to no branch of node " +
             		existingNodeID + "\n");
                currentNode.noBranch = new BinTree(newNodeID,newQuestAns);
                }    
            return(true);
            }
        else {
            // Try yes branch if it exists
            if (currentNode.yesBranch != null) {        
                if (searchTreeAndAddNoNode(currentNode.yesBranch,
                     existingNodeID,newNodeID,newQuestAns)) {        
         return(true);
         }   
                else {
                // Try no branch if it exists
         if (currentNode.noBranch != null) {
             return(searchTreeAndAddNoNode(currentNode.noBranch,
                     existingNodeID,newNodeID,newQuestAns));
             }
         else return(false); // Not found here
         }
                 }
            else return(false); // Not found here
            }
        }       

    /* --------------------------------------------- */
    /*                                               */
    /*              TREE QUERY METHODS               */
    /*                                               */
    /* --------------------------------------------- */

    /* OUTPUT NODE: First check:
    1. That we have not arrived at the answer --- if so output result.
    2. That no error has occurred in the construction of the tree (the tree must
       be balanced, e.g. body nodes must have "yes" and "no" branches) --- if 
       so error.
    Otherwise output question. */   
    
    private void outputNode() {

        // Test for leaf node (answer) and missing branches
        if (currentNode.yesBranch==null) {
            if (currentNode.noBranch==null) 
	    		aTextArea.append(currentNode.questOrAns + "\nEND\n\n");
            else missingYesBranchErrorMessage(currentNode.questOrAns);
            // Return
	    currentNode=null;
	    return;
            }
        if (currentNode.noBranch==null) {
            missingNoBranchErrorMessage(currentNode.questOrAns);
            // Return
	    currentNode=null;
	    return;
            }

        // Question
        aTextArea.append(currentNode.questOrAns + 
				" (enter \"Yes\" or \"No\")\n");
        }

    /* ----------------------------------------------- */
    /*                                                 */
    /*              TREE OUTPUT METHODS                */
    /*                                                 */
    /* ----------------------------------------------- */

    /* OUTPUT BIN TREE */

    private void outputBinTree() {

        outputBinTree("1",rootNode);
        }

    private void outputBinTree(String tag, BinTree currentNode) {

        // Check for empty node

        if (currentNode == null) return;

        // Output

        aTextArea.append("[" + tag + "] nodeID = " + currentNode.nodeID +
             ", question/answer = " + currentNode.questOrAns + "\n");
             
        // Go down yes branch

        outputBinTree(tag + ".1",currentNode.yesBranch);

        // Go down no branch

        outputBinTree(tag + ".2",currentNode.noBranch);
        } 

    /* ------------------------------------------------------ */
    /*                                                        */
    /*                    ERROR MESSAGES                      */
    /*                                                        */
    /* ------------------------------------------------------ */   
	
    private void noRootNodeErrorMessage() {
    	JOptionPane.showMessageDialog(null,"ERROR 1: No root node! " +
		"Decision tree must include a single root node.\n\n");
	}
    
    private void noTreeToQueryErrorMessage() {
        JOptionPane.showMessageDialog(null,"ERROR 2: No decision tree " +
		"created. To query a decision tree you must\nfirst create " +
		" a tree using the \"Generate\" button.\n\n");
	}
    
    private void noTreeToOutputErrorMessage() {
        JOptionPane.showMessageDialog(null,"ERROR 3: No decision tree " +
		"created. To output a decision tree you must\nfirst create " +
		"a tree using the \"Generate\" button.\n\n");
	}
    
    private void missingYesBranchErrorMessage(String text) {
        JOptionPane.showMessageDialog(null,"Error 4: Missing \"Yes\" " +
		"branch at \"" + text + "\" question.\n\n");
	aTextArea.append("END\n\n");
	}
    
    private void missingNoBranchErrorMessage(String text) {
        JOptionPane.showMessageDialog(null,"Error 5: Missing \"No\" " +
		"branch at \"" + text + "\" question.\n\n");
	aTextArea.append("END\n\n");
	}
    
    private void noCurrentNodeErrorMessage() {
        JOptionPane.showMessageDialog(null,"Error 6: False start. To query " +
		"the decision tree initialise the process\nusing the " +
		"\"query\" button.\n\n");
	}
    }

Table 1:Decision tree GUI (Swing example)

// DECISION TREE GUI APPLICATION
// Frans Coenen
// Thursday 15 August 2002
// Revised Thursday 20 March 2003
// Department of Computer Science, University of Liverpool

import java.io.*;
import javax.swing.*;

class DecisionTreeGuiApp {

    /* ------------------------------- */
    /*                                 */
    /*              FIELDS             */
    /*                                  */
    /* ------------------------------- */

    static BufferedReader keyboardInput = new
          BufferedReader(new InputStreamReader(System.in));
    static DecisionTreeGui newTree;
    
    /* --------------------------------- */
    /*                                   */
    /*               METHODS             */
    /*                                   */
    /* --------------------------------- */

    /* MAIN */

    public static void main(String[] args) throws IOException {
	// Create instance of class DecisionTreeGui
	newTree = new DecisionTreeGui("Decision Tree Gui");
        
	// Make window vissible
	newTree.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	newTree.setSize(500,400);
        newTree.setVisible(true);
        }
    }

Table 2:Decision tree GUI Application Class

DECISION TREE GUI

Figure 1: Some output produced by code presented in Tables 1 and 2

DECISION TREE ERROR MESSAGE WINDOW

Figure 2: Example error message window




Created and maintained by Frans Coenen. Last updated 21 March 2003