| Name: _____________________ | Class: CIS 355 |
| SSN/ID: _____________________ | Section & Group: ____________ |
Lab
Overview: General SpecsTCO:
| 11 | Given a business systems application that needs to be written in a programming language with which you are not familiar: compare that language to one with which you are familiar and formulate a plan to substitute the structure, grammar and syntax of the new programming language for those of the familiar language. |
Desired (Lab) Learning Outcome: The objective of this lab is to use an IDE to write a Swing GUI program that handles mouse and key events with more various controls and methods.
Dependencies: Reading assignments and the on-site and on-line topics/lectures. Also, please see this guide on Content Panes to see when you should issue a getContentPane() versus a setContentPane() (or use the original container's content pane directly!).
Lab Assignment: Using an IDE write a Swing GUI program that handles mouse and key events with more various controls and methods.
Narrative/Case Study: The objective of this lab is to use an IDE to write a Swing GUI program that handles mouse and key events with more various controls and methods. This lab introduces many GUI features that can be used to increase functionality of various components/containers/controls. Also the placement of these components/containers/controls is handled by layout managers.
Methods are used to increase the computational capabilities of the application. Finally, various event handlers are used to improve the user experience with the application. Be warned, this lab is long, but it provides an abundance of GUI information. The bad news is that we hardly scratch the surface as far as GUI functionality is concerned.
Environment: Once again, you should have Sun's JDK installed, as well as, if you like, an IDE like JCreator LE.
Remarks: This lab shows that a Java GUI is built piece by piece from various components/containers/controls. Then, additional GUI classes are used to enhance functionality, usability, and appearance. This lab is fairly comprehensive and time consuming. It also introduces concepts (borders) that are not covered in the current textbook by Bronson; thus, Threaded Discussions are used to gain the necessary knowledge needed to complete this lab (please note, the extra material on borders is not required for the lab but completion of the additional material will prove very helpful and neat, albeit slightly garish in its current incarnation. Some code and hints on how to solve the lab will be provided below. You should make every effort to do this lab in its entirety, since the experience gained in finishing it will provide a wealth of knowledge and capabilities.
We start by using a Swing GUI top level container called a JFrame. If you look at the Final ScreenShot, you'll see that our final GUI will contain quite a few elements, most notably:
We'll start by constructing the basic GUI elements and bringing them all together. Once we've succeeded in doing that, we'll slowly start adding functionality. That means we'll start with a class and then slowly add to it as it becomes more complex. Let's start right away. The code for the beginning of the class is:
/**
* Lab 3 for CIS 355 with Prof. Ricky J. Sethi
* GUI Lab Description
*
* @author Your Name Here
* @version Version 1.0 as of 2006-05-05
* For: CIS 355 with Professor Sethi
*
* Specification:
* input(keyboard):
* output(screen):
******************************************************************/
package cis355Package; // Need to place .class files in cis355Package dir
// Use java cis355Package/Lab3Cis355 to run
// Make sure gifs directory is at same level as cis355Package directory
import javax.swing.*; // Need for Swing
import java.awt.*; // Need for awt
import java.awt.Frame;
import java.awt.event.*; // Need for events
import javax.swing.border.*;
public class Lab3Cis355 extends JFrame { //start of class Lab3
//attributes
private String str1 = "Lab3 CIS355, Sun June 5, 2005, Soln by Your Name ";
private String str2 = " Devry University ";
private String str3 = " email = email@devry.edu ";
private String str4 = "\t\t" + str1 + "\n" +
"\t\t" + str2 + "\n" +
"\t\t" + str3;
private String str5 = "You hit the clear button";
private JPanel jpanTop; //top panel: this will contain the labels and jpanTop2, which will contain the layout buttons
private JPanel jpanTop2; //top panel 2 to hold the layout buttons
private JPanel jpanMiddle; //middle panel
private JPanel jpanBottom; //bottom panel
private JTextArea jtxaTop; //text area for top panel
private JLabel jlabTop; //label for top panel
private Icon iconTop; //icon used in the JLabel above
private JButton jbutFlow; //flow layout button for middle panel
private JButton jbutBorder; //border layout button - middle panel
private GridLayout grlt1; //grid layout for theWindow and the topPanel
private FlowLayout fllt1; //flow layout for topPanel2 and jbutFlow
private Font fontAB14; //Arial bold and 14
// Rest of the class declarations/definitions will eventually go here...
.
.
.
} // End of Class
Please note that we've also added in a Font object reference, since we'll be using that in quite a few places as well. Of course, we haven't created anything as yet; in order to create the actual objects/attributes we've declared, we need to initialize our constructor. Here is the beginning of the constructor:
// The Class Constructor
public Lab3Cis355() { //start of constructor
super("Lab3 CIS 355"); //title of the JFrame (could have used new mainFrame("Lab3 CIS 355"))
final Container theWindow = getContentPane(); //get ref to the JFrame's content pane
//create panels for the screen
jpanTop = new JPanel();
jpanTop2 = new JPanel();
jpanMiddle = new JPanel();
jpanBottom = new JPanel();
// Setup our font
fontAB14 = new Font("Arial", Font.BOLD, 14);
jtxaTop = new JTextArea(3, 30);
jtxaTop.append(str4);
//create a label and icon in the top panel
Icon iconTop = new ImageIcon("gifs/car.gif");
jlabTop = new JLabel(" " +
"Pick a layout for the buttons below " +
"before you click on anything in the " +
"bottom panel" + " Also hit Ctrl-D to Divide"
, iconTop,
SwingConstants.LEFT);
// Set the Layouts
grlt1 = new GridLayout(3, 1);
theWindow.setLayout(grlt1);
jpanTop.setLayout(grlt1);
fllt1 = new FlowLayout();
jpanTop2.setLayout(fllt1);
//add the jtextarea and top label to the top jpanel
jpanTop.add(jtxaTop);
jpanTop.add(jlabTop);
//create the buttons for the top panel
jbutFlow = new JButton("Flow Layout");
jbutBorder = new JButton("Border Layout");
//add the layout buttons to the second top panel
jpanTop2.add(jbutFlow);
jpanTop2.add(jbutBorder);
//add jpanTop2 to the top panel
jpanTop.add(jpanTop2);
//add the other two panels:
jpanBottom.setLayout(grlt1);
//add top and middle and bottom panels to screen
theWindow.add(jpanTop);
theWindow.add(jpanMiddle);
theWindow.add(jpanBottom);
// Rest of the constructor will eventually go here...
.
.
.
} // End of Constructor
Please note that the three JPanels are all arranged in the JFrame using the same GridLayout Manager, grlt1. Also notice that the main window's content pane Container, theWindow, was made final. That's because it is referenced in the anonymous inner classes and you have to make the local variable "final". Although we've got the gross outline of the class set, we still need a main() function, so let's add that in now, as well:
//////////////////////////////////////////////////////////////////////
// Main:
//////////////////////////////////////////////////////////////////////
public static void main(String args[]) {
Lab3Cis355 myLab1 = new Lab3Cis355(); //instantiate Lab1
myLab1.setExtendedState(myLab1.MAXIMIZED_BOTH);
} // End of main()
Notice that we maximize the JFrame as soon as the application is run. This is done so that the user can see the bottom JPanel immediately. Why? Because this might provide a better user experience.
However, before you compile and run it, we should make sure to add in a couple of things to the constructor; namely, we need some code to handle the window closing event by adding a WindowListener/WindowAdapter for the JFrame (e.g., when the user clicks the "X" mini-button in the top, right corner of the window) and we also need to show the window, itself! So let's add this in, as well (btw, where, in our nascent class, would you add this?):
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) { //start windowClosing()
System.exit(0);
} //end windowClosing()
});
setSize(1100, 800);
setVisible(true);
At this point, you should compile and run your program and see something similar to this image.
The next topic to cover, Borders, is not in the Bronson textbook, so we'll likely do a Threaded Discussion on it. Please note, you're not required to implement this borders code in your lab; it will, as noted in the introduction, serve as extra-credit to make up for other deficiencies you might have in this lab. In order to use borders, we'll first have to declare some Borders components. Where should these declarations go: in the attributes section, the constructor, or a new function? Once you've determined where to declare these variables/components, please add the following attribute declarations to your code:
private BorderLayout blt; //border layout for jbutBorder private Border borLine; //a Line border around jtxaTop private Border borLine2; //a Line border around jpanTop private Border borLine3; //a Line border around jpanMiddle private Border borLine4; //a Line border around jpanBottom private Border borEtch; //an etched border private Border borRBev; //a raised bevel border private Border borLBev; //a lowered bevel border private Border borCompRL; //a compound boder = Raised + Lowered private Border borCLRL; //a compound border = Line + Raised + Lowered
The borders-related code that's added to your constructor is:
/////create borders line border 3 = line width in 3 pixels //used within the jbutBorder's ActionListener blt = new BorderLayout(); //borLine is around jtxaTop borLine = BorderFactory.createLineBorder(Color.yellow, 3); //borLine2 is around jpanTop borLine2 = BorderFactory.createLineBorder(Color.green, 4); //borLine3 is around jpanMiddle borLine3 = BorderFactory.createLineBorder(Color.blue, 4); //borLine4 is around jpanBottom borLine4 = BorderFactory.createLineBorder(Color.red, 4); borEtch = BorderFactory.createEtchedBorder(Color.red, Color.green ); borRBev = BorderFactory.createRaisedBevelBorder(); borLBev = BorderFactory.createLoweredBevelBorder(); borCompRL = BorderFactory.createCompoundBorder(borRBev, borLBev); borCLRL = BorderFactory.createCompoundBorder(borCompRL, borLine); jpanTop.setBorder(borLine2); jpanMiddle.setBorder(borLine3); jpanBottom.setBorder(borLine4);
Here, we create Borders for all of the components/containers/controls. Please be sure to add this code immediately after you create your JPanels in your constructor! If you've added things in correctly, you should be able to compile and run your program to see something like this image.
Now, please take a look at the top JPanel (the green one) in the Final ScreenShot. You should see three structures/boxes/rectangles on top of or inside this top JPanel. You should see a JTextArea structure with a blue background and yellow font; a JLabel structure with an animated gif of a car on a road (this gif is provided as an animated gif); and, finally, you should see a structure with two buttons in/on it — labelled FlowLayout and BorderLayout.
These structures are arranged in the top JPanel using a GridLayout manager — the same layout manager and code used within our main JFrame (theWindow), above. In actuality, the JTextArea and JLabel are arranged within the top JPanel and another JPanel, jpanTop2, is also added to the top JPanel. It is this JPanel, jpanTop2, that contains the two buttons.
Now let's turn our attention back to the JTextArea, called jtxaTop, that's contained within the top JPanel, called jpanTop. We'd like to format it to be the same as the final screenshot so let's make those changes to jtxaTop; the code to be added to the constructor (immediately following the jtxaTop = new JTextArea(3, 30) definition and immediately before the jtxaTop.append(str4) line), is:
//create a new jtextarea with a new font and color jtxaTop.setFont(fontAB14); jtxaTop.setBackground(Color.blue); jtxaTop.setForeground(Color.yellow); jtxaTop.setBorder(borLine);
Back to our Final ScreenShot. The second structure in the top JPanel (not jpanTop2, which is the third component of jpanTop) is a label with an icon. An icon is simply a picture (in this case, it's the following .gif file — animated gif). The code that added this animated gif to your program was governed by the following lines your the constructor:
//create a label and icon in the top panel
Icon iconTop = new ImageIcon("gifs/car.gif");
jlabTop = new JLabel(" " +
"Pick a layout for the buttons below " +
"before you click on anything in the " +
"bottom panel" + " Also hit Ctrl-D to Divide"
, iconTop,
SwingConstants.LEFT);
Icon(s) are not discussed in the Bronson book so we'll just have to make that another Threaded Discussion topic.
Also notice in the code that the
new ImageIcon("gifs/car.gif");
is stored in a gifs subdirectory. Please create the gifs subdirectory under the JCreator LE project subdirectory for Lab 3 that is called p2cis355 (if that's what you called it).
Let's now add in a border for our JLabel by adding the following line immediately after the above line where we define jlabTop:
jlabTop.setBorder(borEtch);
Finally, we'll add a new border for our jbutBorder JButton. Recall that the last structure in the top JPanel is another JPanel called jpanTop2. It holds two buttons, labelled Flow Layout and Border Layout, and uses a FlowLayout manager. We'll now add the code to give both our buttons some borders. Please be sure to add this immediately after the JButton definitions, so you change their attributes before you add them to the content pane!
//give our buttons some borders: jbutFlow.setBorder(borRBev); jbutBorder.setBorder(borCLRL);
At this point you are finished with the top JPanel. We now create the controls for the middle JPanel. Please add the following code to the relevant area (does it go in the attributes section? The constructor? A new function?).
The attribute declarations:
private JLabel jlabNum1; //label for first input number private JLabel jlabNum2; //label for second input number private JLabel jlabResult; //label for result private JTextField jtxfNum1; //input field for first number private JTextField jtxfNum2; //input field for second number private JTextField jtxfResult; //output result field
The component definitions:
//create the labels and text fields for the middle panel
jlabNum1 = new JLabel("Enter in the first integer number: ");
jlabNum2 = new JLabel("Enter in the second integer number: ");
jlabResult = new JLabel(" " +
" " +
" The result is: ");
jtxfNum1 = new JTextField(5);
jtxfNum2 = new JTextField(5);
jtxfResult = new JTextField(20);
Notice that we create the controls for the middle JPanel, but we do not add them to that JPanel. The addition of the controls is actually done in event handlers for the Flow and Border Layout JButtons.
So, let's set up the bottom JPanel. This panel will consist of three other JPanels; please add the following attribute declarations to your ever-growing class:
private JPanel jpanNorth; private JPanel jpanCenter; private JPanel jpanSouth;
Once you've added their declarations, please define them, within your constructor, using the following code:
jpanNorth = new JPanel(); jpanCenter = new JPanel(); jpanSouth = new JPanel();
Now we're ready to tackle the radio buttons! Let's start off with the declaration code for the radio button attributes we need:
private JRadioButton jrbAdd; //add radio button for bottom panel private JRadioButton jrbSub; //subtract radio button - bottom panel private JRadioButton jrbMul; //multiply radio button - bottom panel private JRadioButton jrbDiv; //divide radio button - bottom panel private ButtonGroup butgMath; //button group = add, sub, mul, div private JRadioButton jrbClear; //clear radio button - bottom panel private JRadioButton jrbEnd; //end radio button - bottom panel private ButtonGroup butgAdmin; //button group - end and clear
Here is definition the code for the JRadioButtons for the bottom JPanel... does this go in the Attribute section or the Constructor of our class? Hint: I'd recommend adding this in right before you add the three JPanels to theWindow.
//add jradio buttons to button groups and add them to bottom panel
jpanBottom.setLayout(grlt1);
jrbAdd = new JRadioButton("Add");
jrbSub = new JRadioButton("Subtract");
jrbMul = new JRadioButton("Multiply");
jrbDiv = new JRadioButton("Divide");
jpanBottom.add(jrbAdd);
jpanBottom.add(jrbSub);
jpanBottom.add(jrbMul);
jpanBottom.add(jrbDiv);
butgMath = new ButtonGroup();
butgMath.add(jrbAdd);
butgMath.add(jrbSub);
butgMath.add(jrbMul);
butgMath.add(jrbDiv);
jrbClear = new JRadioButton("Clear Fields");
jrbEnd = new JRadioButton("End Program");
jpanBottom.add(jrbClear);
jpanBottom.add(jrbEnd);
butgAdmin = new ButtonGroup();
butgAdmin.add(jrbClear);
butgAdmin.add(jrbEnd);
Since only the outline of the code to put into the various event handlers will be provided for you (given immediately below), the actual event handling setup is up to you. However, here is the code for the two buttons' event handlers. Let's start with the code for the jbutFlow ActionListener, which looks something like this:
//event handler for jbutFlow
jbutFlow.addActionListener( new ActionListener() { //start anonymous inner class
public void actionPerformed(ActionEvent event) {
jpanMiddle.setLayout(fllt1);
jpanMiddle.add(jlabNum1);
jpanMiddle.add(jtxfNum1);
jpanMiddle.add(jlabNum2);
jpanMiddle.add(jtxfNum2);
jpanMiddle.add(jlabResult);
jpanMiddle.add(jtxfResult);
if ( Lab3Cis355.this.getExtendedState() == MAXIMIZED_BOTH ) { //start if
Lab3Cis355.this.setExtendedState(Lab3Cis355.this.MAXIMIZED_HORIZ);
Lab3Cis355.this.setExtendedState(Lab3Cis355.this.MAXIMIZED_BOTH);
} //end if
else { //start else
Lab3Cis355.this.setExtendedState(Lab3Cis355.this.MAXIMIZED_BOTH);
} //end else
jpanMiddle.validate();
jpanMiddle.repaint();
jtxfNum1.grabFocus();
} //end actionPerformed()
}); //end anonymous inner class and addActionListener()
In the above block, you should especially note the defined constants, like MAXIMIZED_BOTH, etc. This maximizes the JFrame. The reason we do this is because even when the screen is repainted, JPanel, etc., the middle JPanel controls did not appear because the layout took so much of the screen's real estate. If the JPanel is manually maximized, then the controls appear. Thus, it is more efficient to simply do the maximization in code.
Then, you should see MAXIMIZED_HORIZ. The reason for this is that if the screen is already maximized, you would manually have to send it back to a normal state and maximize again. So again, we sort of do this in code, instead.
Finally, you should notice the validate() and repaint() calls in the middle JPanel and also the call to grabFocus(), which will set the focus on the input text field for the first number. We probably could also have used a revalidate() call there.
The event handler for the jbutBorder ActionListener follows a very similar patter and looks something akin to:
//event handler for jbutBorder
jbutBorder.addActionListener( new ActionListener() { //start anonymous inner class
public void actionPerformed(ActionEvent event) {
jpanMiddle.setLayout(blt);
jpanNorth.setLayout(fllt1);
jpanCenter.setLayout(fllt1);
jpanSouth.setLayout(fllt1);
jpanNorth.add(jlabNum1);
jpanNorth.add(jtxfNum1);
jpanMiddle.add(jpanNorth,BorderLayout.NORTH);
jpanCenter.add(jlabNum2);
jpanCenter.add(jtxfNum2);
jpanMiddle.add(jpanCenter,BorderLayout.CENTER);
jpanSouth.add(jlabResult);
jpanSouth.add(jtxfResult);
jpanMiddle.add(jpanSouth,BorderLayout.SOUTH);
if ( Lab3Cis355.this.getExtendedState() == MAXIMIZED_BOTH ) { //start if
Lab3Cis355.this.setExtendedState(Lab3Cis355.this.MAXIMIZED_HORIZ);
Lab3Cis355.this.setExtendedState(Lab3Cis355.this.MAXIMIZED_BOTH);
} else { //start else
Lab3Cis355.this.setExtendedState(Lab3Cis355.this.MAXIMIZED_BOTH);
} //end else
jpanMiddle.validate();
jpanMiddle.repaint();
jtxfNum1.grabFocus();
} //end actionPerformed()
}); //end anonymous inner class and addActionListener()
The ItemListeners for jrbSub, jrbMul, and jrbDiv call doSub(), doMul() and doDiv(), respectively. The code for all three methods is very similar (actually, we will have four methods in all, since we need to include an event handler for jrbAdd — the reason we did not include it here is because jrbAdd will use a MouseListener, technically a MouseAdapter, to handle its events). They'll essentially follow the outline of the code that's provided for doSub() and you should be able to figure out the code for the other three methods.
//event handler for jrbSub
jrbSub.addItemListener( new ItemListener() { //start anonymous inner class
public void itemStateChanged(ItemEvent event) { //start itemStateChanged()
doSub();
} //end itemStateChanged()
}); //end anonymous inner class and addItemListener()
the code for doSub() should be something analagous to what's given below (for doAdd(), please add an extra JOptionPane.showMessageDialog(~~, ~~) statement to indicate that a Mouse event took place — put it after the call to doAdd()). Take a look at the Addition with Mouse Event Detected ScreenShot.
public void doSub() { //start doSub()
int intNum1 = Integer.parseInt(jtxfNum1.getText());
int intNum2 = Integer.parseInt(jtxfNum2.getText());
jtxfResult.setText( "The subtraction of " + intNum1 +
" minus " + intNum2 + " is " + (intNum1 - intNum2));
} //end doSub()
Sicne Mouse handling is not explained well in the Bronson book, we'll reserve it for yet another opportunity for a Threaded Discussion. In the meantime, here is some code to help get you started (it should be relatively straight-forward as adding this event handler is essentially the same as adding any other event handler):
//mouse event handler for jrbAdd
jrbAdd.addMouseListener( new MouseAdapter() { //start anonymous inner class
public void mouseEntered(MouseEvent event) { //start mouseEntered()
// Please add your code here
} //end mouseEntered()
}); //end anonymous inner class and addMouseListener()
Now, add a KeyListener, actually a KeyAdapter event handler on the jtxfNum2 text field. This will be activated with a Ctrl-D (hold the Control key down and at the same time hold down the D key (no shifting or capital D)). Bronson does a good explanation of Key events. The code for the KeyListener/KeyAdapter is:
//event handler for keys CTRL-D
jtxfNum2.addKeyListener( new KeyAdapter() { //start anonymous inner class
public void keyPressed(KeyEvent event) { //start keyPressed()
if (event.isControlDown() && event.getKeyCode() == event.VK_D) { //start if
doDiv();
} //end if
} //end keyPressed()
}); //end anonymous inner class and addKeyistener()
The code for the jrbClear ActionListener is:
//event handler for jrbClear
jrbClear.addActionListener( new ActionListener() { //start anonymous inner class
public void actionPerformed(ActionEvent event) { //start actionPerformed()
jtxfNum1.setText("");
jtxfNum2.setText("");
jtxfResult.setText("");
jtxfNum1.grabFocus();
} //end actionPerformed()
}); //end anonymous inner class and addActionListener()
Here, we are sending the focus back to the first input text field for the first integer.
The code that will go inside the ActionListener for jrbEnd is:
JOptionPane.showMessageDialog(null, str4); System.exit(0);
Another peculiarity should be noted here: for jrbSub, jrbMul, and jrbDiv we used ItemListeners. Remember, for jrbAdd, however, we used a MouseListener/Adapter. You might be wondering why we do not use an Adapter for an ActionListener. There is no need really, since there is only one method, actionPerformed(), in an ActionListener.
Another point to make is that for jrbClear and jrbEnd, we used an ActionListener for both radio buttons and not an ItemListener like we did for jrbSub, etc. This was to illustrate the fact that both will work equally well for them.
That's all for this lab. You should have all the information you will need to do it. This is an overwhelming lab at first sight. But, once you do it, you gain a lot of extremely useful information. Plus, we will not push GUI functionality in the rest of the labs in this course. You now know how to do GUI features — so use them whenever appropriate. Eight .jpg files are provided that show you what the output should look like. Plus, the info in various controls also helps you to figure out what should be included in the code and methods.
Please Note: it's okay not to use the package directives in the lab; you should read Appendix F and utilize them but it's not required for the lab, per se.
You can see a demo of the shell of the application here: Applet Demo Shell.
Some of the output files for this lab are Final ScreenShot; Border Layout Button Pressed and Flow Layout Button Pressed; Addition with Mouse Event Detected; Subtraction; Multiplication; Division; End; and, finally, an animated gif (save this as car.gif in your gifs/ directory).
Submit: Once your program runs and creates output exactly like the images above (and follows all the specifications), please turn in your entire JCreator project directory (zipped up) via the DropBox. Please make sure that you name it as: lastname_firstname_lab03.zip.
Student Name:
Date:
Read the Lab Presentation and respond to the following items prior to beginning the lab exercise.
Prepare this Lab Report when you have completed and lab assignment. Include any charts, graphs required to complete the lab. Refer to your initial lab plan to respond to the first questions.