|
| 1. Introduction | |
| 2. Decision tree GUI code |
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).
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
Figure 1: Some output produced by code presented in Tables 1 and 2
Figure 2: Example error message window
Created and maintained by Frans Coenen. Last updated 21 March 2003