|
~ Java for Web Page Production ~ Session 4 - Looping; Containers, Panels and Frames; Random numbers |
In previous sessions, we have become accustomed to using the QuickCup development environment to edit, compile and execute both applets and applications.
We have looked at the background to Java and its application on the Internet.
We have looked at some fundamentals of programming, such as variables (or attributes), arrays, commenting & indenting, scope, objects and classes (inlcuding nested classes - classes within classes), and inheritance. We have demonstrated creating our own classes and objects through the Bicycle example, and extending a JApplet through inheritance to create own own applets.
We have also looked at Java-specific features such the JApplet, JLabel, and (briefly) the JButton. We have looked at how to run an Applet from a web page, and how to pass String values (parameters) to the applet from the web page.
Finally, we have looked at how to use existing Classes and their Methods from libraries using the import statement.
We finished our last session by looking at a Pair-matching game, which demonstrates a number of fundamental techniques in Java programming. We will take a closer look at this Applet this session, make some alterations, and look at some sample explanatory Applications in order to explore these techniques further.
In particular, we will be looking at extending our understanding of fundamental programming techniques by learning about loops.
We will use this knowledge to look at how we create multiple buttons on the screen.
We will look at Random numbers to see how we randomize the positions of numbers on the buttons in the pairs game.
We will look at ways of containing controls such as buttons and labels using Containers, Panels, and Frames. We will look at how to control the positioning of these controls using Layouts.
In Session 3, we covered:
Uses for comments in source code
Using Comments to try things out
Indentation
Inheritance
Applet & Inheritance
Example class - the JLabel
Adding second JLabel to TextBurst
Scope
Libraries and Importing Classes
Class Paths
Nested Classes
Adding a dynamo to our Bicycle
Creating a 'pair matching' game
In session 4, we will be looking at:-
Introduction
Session 3 Summary
Session 4 Overview
Looping & Branching
Random Numbers
Generating Objects
Container Objects
Layouts
<<break>>
Combining Layouts with JPanels
JFrames and Dialog boxes
Summary & Further Resources
At the end of the previous session, we took a look at a fairly simple pair-matching game Applet, which introduced a number of concepts. Try opening the pairs project now, from the week 3 directory.
We found that by changing the squaresAcross and squaresDown parameters in the Pairs.htm web page file, we could alter the number of buttons that would appear in the applet, thus effectively adjusting the difficulty level in the game - the more squares in the game, the more difficult it is to find a matching pair.
You may wish to try this again to remind yourself. Each of these parameters started as 4, giving 4×4=16 squares. Try altering this to 10 squares across and 3 down, giving 10×3=30 squares. This means that there will be 15 pairs of numbers hidden in the buttons, numbered 1 to 15. These are randomly arranged throughout the buttons.
Take a look at the Pairs.java file in QuickCup. Go to line number 66 (press Ctrl+G, type 66 and press Enter):-
buttonValues = new int[buttonCount];
This line sets up a new array of integers (the array is declared on line 39). The array is called buttonValues, and it holds buttonCount 'boxes' for integer values. buttonCount is itself an integer variable (defined on line 62 to hold squaresDown×squaresAcross values - again, these are variables, which have taken their values from the parameters passed in from the web page).
Unusually, base variables like integers, chars and Strings do not have each 'box' in the array created separately. This is because they are so simple to store, that Java allocates the space for them at the time you create the array.
So for example, if we wanted to set the first of the button values to 1, we could say the following:-
buttonValues[0] = 1;
We could also state what the values will be at the time of the declaring the array, if we knew what the size of the array was to be in advance (e.g. 4 x 4):-
int buttonValues[] = { 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8 };
However, if we don't know what the size of array is going to be at the time of writing the Applet (because this gets passed in from the web page), then we must find some other way of filling the array.
The for loop
This is where loops come into their own. We will look at the most-used of these loop types - the for loop.
Go to line 69 in the Pairs.java program. The line is as follows:-
for (int i=0 ; i < buttonCount ; i++) buttonValues[i] = (int)((i+2)/2.0);
So what does this line do? It does what we want - fills the array with two sets of integers according to the number of buttons we will be using.
The for loop statement works as follows. We define a variable that will be available only within the loop - in the example above, we have declared an integer, and set it to a value of zero - int i=0
The value is then checked to see whether the instruction(s) needs to be executed - this is down using a condition. In this example, the condition is i < buttonCount which means is the value of the i variable less than the value of the buttonCount variable. In this example, i starts at 0 and buttonCount will stay as 16 if there are 4×4 buttons. Thus the condition can be read as execute this instruction if 0 is less than 16. This is clearly the case, so the statement gets executed.
The value is then used for one or more instructions to perform some task. The value is then altered (in this example, it is increased by 1 using the i++ command).
The condition is then used again to see if the instruction needs to be used again - now i is 1 but buttonCount remains as 16. Thus as 1 is less than 16, the instruction gets executed again. You can see that only when i has been incremented 16 times will this condition be false, and the instruction no longer executed.
In short, this construction will execute the instruction 16 times, increasing the value of i by one each time around.
In this example, we want to go through each 'box' in the buttonValues array, and set it to a value. So, for example, if we substitute the initial value of i (0) into the statement that follows the for loop definition (the bit in parenthesis), we would get the statement:-
buttonValues[0] = (int)((0+2)/2.0);
This means that the first 'box' in the buttonValues array gets set to 2/2=1.
Now i gets incremented with the i++ to become 1, and as 1 < 16 is true, the statement is executed again, but this time substituting i for 1:-
buttonValues[1] = (int)((1+2)/2.0);
This means that the second 'box' in the buttonValues array gets set to 3/2.0. This is actually 1.5, which is not an integer value. So how do we chop off the decimal part (0.5) and make it into an integer (1)?
The (int) part is what is known as casting. This means that the result, which could potentially be a real (decimal) value will be converted to an integer type. It won't work for converting between all classes, but it will work with number values, and is also used when using an object-oriented technique known as polymorphism which has been briefly described previously, but we won't be going into in any detail on this course.
So (int) chops off the 0.5 and turns the value into an integer (1). Thus we have our second 1 of the pair of 1s.
If we follow this through the sixteen parts of the loop, we get the following results:-
| value of i | condition | statement | buttonValue changed |
| 0 | 0<16 - True | (int)(0+2)/2.0) | (int)(1) = 1 |
| 1 | 1<16 - True | (int)(1+2)/2.0) | (int)(1.5) = 1 |
| 2 | 2<16 - True | (int)(2+2)/2.0) | (int)(2) = 2 |
| 3 | 3<16 - True | (int)(3+2)/2.0) | (int)(2.5) = 2 |
| 4 | 4<16 - True | (int)(4+2)/2.0) | (int)(3) = 3 |
| 5 | 5<16 - True | (int)(5+2)/2.0) | (int)(3.5) = 3 |
| 6 | 6<16 - True | (int)(6+2)/2.0) | (int)(4) = 4 |
| 7 | 7<16 - True | (int)(7+2)/2.0) | (int)(4.5) = 4 |
| 8 | 8<16 - True | (int)(8+2)/2.0) | (int)(5) = 5 |
| 9 | 9<16 - True | (int)(9+2)/2.0) | (int)(5.5) = 5 |
| 10 | 10<16 - True | (int)(10+2)/2.0) | (int)(6) = 6 |
| 11 | 11<16 - True | (int)(11+2)/2.0) | (int)(6.5) = 6 |
| 12 | 12<16 - True | (int)(12+2)/2.0) | (int)(7) = 7 |
| 13 | 13<16 - True | (int)(13+2)/2.0) | (int)(7.5) = 7 |
| 14 | 14<16 - True | (int)(14+2)/2.0) | (int)(8) = 8 |
| 15 | 15<16 - True | (int)(15+2)/2.0) | (int)(8.5) = 8 |
| 16 | 16<16 - False | Not executed | none |
Thus, you can see that we have set up the buttonValues array with the two pairs of eight numbers that we required.
You can also see that if the value of buttonCount changes if the number of button is different, then the number of times the command is executed will vary, so that we always have the correct number of pairs set up in the array.
A more involved example can be seen at line 72. In this case, the for loop is looking through the entire buttonValues array in the same way as before. However, now it is performing a number of instructions for each time the value of the i variable is incremented, rather than just the single instruction we saw before. To do this, the block of instructions needs to have an opening curly brace put before the first instruction, and a closing curly brace put after the last instruction, as follows:-
for (int i=0 ; i < buttonCount ; i++) {
int swapFirst = (int)(Math.random() * buttonCount);
int swapSecond = (int)(Math.random() * buttonCount);
int swapValue = buttonValues[swapFirst];
buttonValues[swapFirst] = buttonValues[swapSecond];
buttonValues[swapSecond] = swapValue;
}
We'll be looking at this piece of source code a little later when discussing random numbers.
Branching with the if statement
We've discussed looping using the for statement in order to perform a task repeatedly until the task has been completed.
Sometimes you may wish to perform a task only given certain circumstances. In our Pairs example, we may wish to say that if the two buttons we clicked reveal the same numbers, then place the word -MATCH- on both of the buttons. To do this, we would have to test the values of each of the buttons, and if this test is correct, set the button's text. Otherwise, we'd ignore the instructions to do this, and carry on with the program.
This concept is known as branching - meaning that according to what is happening in the program, we can branch off and do something else.
The source code we are describing here can be found starting on line 138:-
if (buttonValues[firstSelection]==buttonValue) {
clickedButton.setText("-MATCH-");
firstButton.setText("-MATCH-");
return;
}
At this stage of the program, it has already been determined that the second button has been clicked, and the value behind the second button has been placed in the buttonValue variable. Also, after the first button was pressed, the button number was placed in the firstSelection variable.
Thus, this condition states that if the value in the buttonValues array relating to button number firstSelection (i.e. the value from the first clicked button) is the same as the value behind the last button clicked (double-equals refers to equality, as distinct from a single equals which is used to set the contents of a variable), then the source code that follows between the curly braces is executed.
However, if the two values are not the same, the source code between the curly braces is ignored, and execution continues in the program after the last curly brace.
The code between the curly braces sets the text of the two buttons to -MATCH- and returns from the actionPerformed method - which is called whenever one of the buttons is clicked.
Exercise - Adding an if statement to test for odd numbers of buttons
Try changing the web page containing the applet (Pairs.htm tab in QuickCup) by changing the parameters squaresAcross and squaresDown to "3" each. Save the project, and run the applet (no need to compile it).
Try completing the puzzle. You can't - there's one square left over. Why is this? If you multiply 3 squares across by 3 squares down, you get 9 squares, which is an odd number of squares - we can have a pair of 1s, a pair of 2s, a pair of 3s and a pair of 4s, giving eight squares, but their one square (containing a single 5) left over, which we can never pair up!
You might say its up to the web page designer not to do something so daft. However, it is good practice in programming to take care of any such anomalies. In this case, there's a simple solution: If the number of squares is odd, add 1 to the number of squares down. An even number multiplied by an odd number is always an even number, so this would work.
How would be go about doing this? It requires only a single line of code as follows:-
if ( (squaresDown*squaresAcross) % 2 == 1 ) squaresDown++;
This introduces a new operator - the % or modulus operator. What this does is divide two numbers, and return the remainder rather than the division. For example, 10 divided by 5 is obviously 2. But 11 divided by 5 gives a fraction, or in division terms, it gives us 2 with 1 left over. The 1 left over is the modulus.
We can utilise this operator to show whether an integer number is odd or even. If you divide a number by 2, then the amount left over will be either 0 if the number is even, or 1 if the number is odd.
Thus the example above says that if the number of squares is odd, increase the number of squares down by 1.
You might say it would be better to report back an error rather than disguise an incorrect value being given to the Java program, and that argument certainly has merit. However, we will not be looking into exception handling, which deals with how to deal with unexpected errors, on this course.
Try inserting the line given above before line 59. Save the application, and try running it with the parameters 3x3, and 3x4. The first should be amended to 4x4, the second is OK, as 3x4=12.
Alternatively, you can open the version of Pairs under the week04\samples directory to see the program in its altered state.
When designing computer games, it is often necessary to incorporate a seemingly random factor into the program, otherwise the game will become predictable, and ultimately offer little challenge.
In our pairs example, we have set up values for the buttons, but their locations are easy to predict, as they are paired together, and start at 1 for the first button etc.
We need to place the buttons in a seemingly random order. One way of doing this is to swap button values randomly a number of times - a bit like 'shuffling' the values.
The following piece of code will do the job:-
for (int i=0 ; i < buttonCount ; i++) {
int swapFirst = (int)(Math.random() * buttonCount);
int swapSecond = (int)(Math.random() * buttonCount);
int swapValue = buttonValues[swapFirst];
buttonValues[swapFirst] = buttonValues[swapSecond];
buttonValues[swapSecond] = swapValue;
}
As you can see, it's another loop - The instructions between the curly brackets are repeatedly executed. Each time the loop goes around, the value of the i variable is incremented by 1 until i==buttonCount - i.e. for each button to be placed in the applet.
So, within the loop, three variables are created and a value set for them at the same time: swapFirst, swapSecond and swapValue.
The Math class contains a class method (i.e. you don't have to create an object out of the class to use it) called random. What this does is to generate a random number from 0 to 1. It could generated 0, but it will never generate 1. This value is a decimal number. So, the first time you use random, you might get the result 0.567655, the next time 0.243534, the next time, 0.928484 etc. - the value seems to be random.
What use is this you may well ask? Well, try multiplying a number by this value, and you get a random number from 0 to that number, but not including the biggest possible number.
So the line:-
int swapFirst = (int)(Math.random() * buttonCount);
will find a number between 0 up to (but not including) 1, and multiply this by the number of buttons. This gives you a number from 0 to (but not including) the number of buttons. Finally, we convert this to an integer by using the (int) cast. This value is placed into the swapFirst variable 'box', which is (of course) defined as an integer.
Thus, we have the index of the first button to swap - from 0 to buttonCount-1.
We do the same to get the second button, the index of which we place in the swapSecond variable.
Next, how do we swap the values of these two buttons? If we copied the value of the second button into the first button, then the value of the first button would disappear, so we couldn't copy it to the second button. For example:-
| Value of 1st button | Value of 2nd button | Instruction |
| 3 | 7 | none yet |
| 7 | 7 | buttonValues[swapFirst]=buttonValues[swapSecond] |
| 7 | 7 | buttonValues[swapSecond]=buttonValues[swapFirst] |
We've lost the value of the first button. So, we must copy the value of the first button into what is called a temporary variable - i.e. it is used purely to do an intermediate calculation, and then will no longer be needed:-
int swapValue = buttonValues[swapFirst];
Thus, the number 3 has now been stored away in swapValue. We can now copy the value of the second button into first button as we have a copy of the value of the first button stored away:-
buttonValues[swapFirst] = buttonValues[swapSecond];
So the value of the first button is now 7. Now we can store the value of the temporary variable into the second button. This concludes the swapping:-
buttonValues[swapSecond] = swapValue;
Thus, the sequence of events in our example is now:-
| Value of 1st button | Value of 2nd button | Temporary Value | Instruction |
| 3 | 7 | none yet | |
| 3 | 7 | 3 | int SwapValue = buttonValues[swapFirst]; |
| 7 | 7 | 3 | buttonValues[swapFirst]=buttonValues[swapSecond] |
| 7 | 3 | 3 | buttonValues[swapSecond]=swapValue |
In our Pairs example, we are generating a lot of objects out of a number of different classes. Let's take a look at a few examples:-
Creating an object whilst passing it to a method
getContentPane().setLayout(new GridLayout( squaresDown, squaresAcross ));
There are often situations where you need to create a new object, in order to pass that object to another method, which will then use that object to do a specific task.
In the above example (see line 64 in the week04 version of the QuickCup Pairs project), we are defining a new layout for the applet (remember that getContentPane() returns the container, into which all the controls such as buttons etc. go). Thus, we are setting a layout for the container, but first we need to create that layout as a new object.
We can do that using the constructor method new GridLayout( squareDown, squaresAcross) which divides the container into a grid with squaresDown rows and squaresAcross columns.
The constructor GridLayout sets up the new object, and returns the new object as a result. This result is then passed to the setLayout method so that it knows which layout to apply to the container.
We'll discuss layouts further later.
Creating different numbers of objects using an array
So what if we don't know how many object we need to store away until the program is executed.
Answer: We use an array. In our program, an array of buttons are defined on line 39 as follows:-
JButton buttons[];
This is simple enough. The Class for a button is called JButton, and we are creating an array called buttons, each 'box' in which will contain a JButton. However, no buttons have been created yet, and we don't know how big the array is to be.
On line 69 (of the latest version of Pairs.java) you can find the following line of code:-
buttons = new JButton[buttonCount];
This creates a new ArrayObject which will hold buttonCount JButtons. None of those buttons have yet been created, though. Note that the first index will be 0, the last will thus be buttonCount-1.
Finally, starting on line 87, we can see how the buttons get added to the applet:-
for (int i=0;i<buttonCount;i++) {
buttons[i] = new JButton("?");
buttons[i].setName("button"+Integer.toString(i));
buttons[i].addActionListener(this);
getContentPane().add(buttons[i]);
}
This loop goes through the array of buttons, from 0 to buttonCount-1 using the i variable to specify the index position of each value or 'box' in the array.
The first line:-
buttons[i] = new JButton("?");
creates a new JButton with a question mark showing on it. This is placed in the ith position in the buttons variable.
The name of the button is the set as "button" followed by the value of i - this is done so that the position of the button in the array can be recalled later when the button is clicked.
The next line adds what is known as an ActionListener to the button, which can be found in the current class (Pairs). This tells the button what method to call when a button is clicked, and where to find it. This is discussed next week in the section relating to interfaces.
Finally, the following line:-
getContentPane().add(buttons[i]);
adds the new button to the container - the button is placed in the next empty grid space in the gridLayout we set up earlier.
We keep on talking about Container objects. What is a container object.
It is simply an object that can hold other visual objects - it's a bit like a blank piece of paper.
You will find there are other classes which are descendants of (i.e inherit from) the Container class, such as a JApplet (an area within a web browser), a JPanel (which can be used to subdivide your applet into different sections), and a JFrame, which can be used as a pop-up window, and descendant of which is the dialog box.
You can quite often place containers inside other containers to control the layout of your controls further. We will be discussing this in the next topic.
The JApplet is the class we most often refer to. In order to get access to the container in order to place controls onto it, it is necessary to use the getContentPane() method on the object, which returns its Container object.
This may seem counter-intuitive, but it is part of a very powerful mechanism introduced in Java 2, known as the JRootPane. We will not be discussing this further on this course.
In our Pairs example, we have arranged the buttons in a grid layout. In order to do this, we have to tell Java that we wish to add controls into this style of layout.
Line 64 of week 4's version of the Pairs.java program shows the layout being set up:-
getContentPane().setLayout(new GridLayout(squaresDown,squaresAcross));
Again, we are applying the layout to the container of the JApplet by using the getContentPane() method. We pass to the setLayout method the new layout object for the Container - in this case, we are creating a grid layout, with squaresDown rows and squaresAcross cells.
GridLayout example
Open the QuickCup project named grid_example.qjp.
If you look at GridExample.htm you can see that this is a very simple applet, which simply adds six buttons to a 2x3 GridLayout container, numbering them from 1 to 6.
This gives us the opportunity to see how they are layed out.
Stripped of comments, the source code is simply as follows:-
| import javax.swing.*; import java.awt.*; public class GridExample extends JApplet { public void init() { getContentPane().setLayout(new GridLayout(2,3)); for (int i=0;i<(2*3);i++) getContentPane().add(new JButton("Button "+Integer.toString(i))); } } |
Very simple: We are not doing anything with the button clicks, so we do not need the ActionListener.
We simply set up a new GridLayout of 2 rows by 3 columns, and add six (2*3) new JButtons, labelled with the button number to show how the buttons are added to the container using this layout:-
Thus, with the GridLayout component, each successive component added to the container flows from left to right, then down one line from the left to right again etc.
There are other styles of layouts. Here's some of the more commonly used:-
BorderLayout
This layout has one central portion, CENTER, surrounded by four borders - NORTH, SOUTH, EAST and WEST.
Open the sample project border_example to see how and in what order controls get added to a border layout. Again, the uncommented source code for this is very straightforward:-
| import javax.swing.*; import java.awt.*; public class BorderExample extends JApplet { public void init() { |
The result of this is as follows:-

The constants which define the directions are obtained from the BorderLayout class, which can be found in the java.awt library.
Note that when adding the buttons to the container, we are specifying where in the container they are to go.
The commented out code does not do this. If you try uncommenting this code, and commenting the original five lines above it, you will see that only the BorderLayout.CENTER button gets filled.
The reason for this is that if you do not specify where to put a component in a BorderLayout, it defaults to CENTER - which means each successive component will appear underneath the last, so that only one component will ever be on top and visible, making it appear as though only one component was created. Be careful with this.
FlowLayout
This layout works a bit like a word-processed document. The first object is placed in the top-left hand corner of the container, and the following object flow from left-to-right, one after another. When they reach the right hand side of the container, they will wrap to the 'next line' - i.e. underneath and to the left of the last set of objects.
Unlike the grid object, the objects will not be automatically resized to be the same size as each other.
Open the sample project flow_example to see how and in what order controls get added to a flow layout. Again, the uncommented source code for this is very straightforward:-
| import javax.swing.*; import java.awt.*; public class FlowExample extends JApplet { public void init() { |
The result of this is as follows:-

You can see that when a button or label does not fit at the end of the line, it will be placed on the next line down at the left hand side, rather like in a word-processed document. Notice Button 8 and Button 10 are different sizes - this is allowed, unlike with a GridLayout. Note also that each successive label has an extra dot placed after it. This makes the length of each label slightly different, which changes how much can be fitted on each line, giving the whole thing a rather scattered look, but illustrating the differing lengths of each object, and how this affects the overall layout.
The following line:-
getContentPane().setLayout(new FlowLayout(FlowLayout.LEFT)); // Layout left justified
will set the layout of the Applet's container to be a new FlowLayout object. Notice that the FlowLayout constructor method is passed a parameter called FlowLayout.LEFT - this signifies that the objects in the container are to be aligned to the left hand margin.
Try changing this to the following values, saving, compiling and running appletviewer each time:-
FlowLayout.CENTER
FlowLayout.RIGHT
We introduce a new class next:-
StringBuffer s = new StringBuffer("."); // Create a new string to be added to
A StringBuffer is just like a String, except we have to declare it as we would any other object. What are the advantages of using it, then? The StringBuffer is designed to work much more efficiently then a standard String when we need to constantly change the string - e.g. in this case, we are adding an extra dot to the end of the string each time we go around the loop that follows. Thus, this is an ideal situation in which to use a StringBuffer.
This line declares a new StringBuffer called s and creates a new StringBuffer object, passing a single dot to its constructor method, so that the StringBuffer starts off as containing"."
We next have a loop and a number of instructions within curly braces. These instructions will be executed each time we go around the loop. The loop variable i starts off at 1 this time, and will go up to 10 before the loop is finished.
The first line of the loop:-
getContentPane().add(new JLabel("Label "+Integer.toString(i)+" "+s.toString()));
will create a new JLabel, and set its text to "Label" followed by the value of the variable i (so it will increase each time around the loop) followed by a space, following by the value of the StringBuffer called s, but converted to a standard String using the StringBuffer Class's toString method.
For example, if i was 1, the label would be set to "Label 0 ."
The next line is similar and adds a button to the container.
The last line in the loop will add a single dot to the StringBuffer called s. This means that each time, it will have an extra dot added to the String:-
s.append(".");
Thus, next time around the loop, when the label is created, it will be set to "Label 1 ..", then next time to "Label 2 ..." etc.
Try increasing the size of the font for the label with each successive iteration around the loop. Look back at the TextBurst applet to see how this is done, or just copy the lines below and replace the loop with them:-
for (int i=1;i<11;i++) {
JLabel theLabel = new JLabel("Label "+Integer.toString(i)+" "+s.toString());
theLabel.setFont(new Font("Helvetica",Font.BOLD,10+i));
getContentPane().add(theLabel);
getContentPane().add(new JButton("---- Button "+Integer.toString(i)+" ----"));
s.append("."); // add another dot to the string
}
Alternatively, take a look at the project called flow_example_2.
The results should look something like this:-
Combining Layouts using JPanels
We mentioned earlier that JPanels were a type of container. They are typically used as a mechanism for grouping a number of controls together.
As each JPanel has a layout of its own, and as containers can appear within other containers, you may start to get the idea that a JPanel can be used as a way of combining different types of layouts in different parts of the Applet.
Try opening the sample project called PanelExample. Compile it and run it. You should see something like this:-
This is achieve with the following source code (comments have been removed):-
| import javax.swing.*; import java.awt.*; public class PanelExample extends JApplet { public void init() { |
What we have is a combination of two layouts.
First, we have the BorderLayout, which is given to the JApplet Container. Buttons are added to the NORTH, SOUTH, EAST and WEST as in the border_layout_example project.
However, we replace the CENTER location with a JPanel. This is simply a container that can have its own layout, and contain its own objects.
The following line:-
JPanel panel = new JPanel(new GridLayout(2,3));
will create a new JPanel object called panel. The class constructor method can take as a parameter the layout type for the panel. In this case, it is a grid 2 rows by 3 columns in size.
The panel is placed at the centre of the JApplet container.
Then, the buttons are generated, and added to the panel rather than directly to the applet's container. Note that you don't have to use the getContentPane() method with a JPanel - what a blessing!
If you take a look at the Pairs2 project, you will see that this utilises exactly this technique to show a title at the top, the grid in the middle, and scoring details at the bottom.
Frames are windows that can pop up over your applet, rather like Windows applications. Dialog Boxes are specific examples of these frames. We will take a quick look at Dialog Boxes, as these are the most useful example of frames in day-to-day Applet programming.
Open the Pairs2 application, and look at the Pairs2.java source code tab. Go to line 177 by pressing Ctrl-G, entering 177, and pressing the Enter key.
You can see that if the pairsRemaining variable's value reaches 0, then another if statement is executed, but this is conditional on a class method returning a value of JOptionPane.YES_OPTION.
This method is as follows:-
| JOptionPane.showConfirmDialog( JOptionPane.getFrameForComponent(this), "Well Done! Would you like to play again?", // text message "Game Completed", //title JOptionPane.YES_NO_OPTION) |
It uses a class called JOptionPane which has a number of methods for getting information back from a dialog box - great for user interaction to pop-up questions.
In this example, it uses a method called showConfirmDialog which takes a frame as a parameter (use JOptionPane.getFrameForComponent(this) to get the frame for the applet), a text message to display in the dialog box, a title to put on top of the box, and the button option (e.g. JOptionPane.YES_NO_OPTION gives a Yes and No button).
When this method is called, all execution stops until a response is received from the user in the form of a button-click on either Yes or No.
The result can be given in the form JOptionPane.YES_OPTION and JOptionPane.NO_OPTION for each of the buttons.
Other button options include:-
and return values include:-
YES_OPTION
NO_OPTION
OK_OPTION
CANCEL_OPTION
There are many possibilities when using the JOptionPane - explore the Java on-line text for further information.
In our example, if the user clicks on the YES_OPTION button, then all the buttons' text are reset to a question mark, the scoring is reset and the label updated, and the ordering of numbers behind the buttons is randomized again. Thus, a new game is born! If the NO_OPTION button was pressed, then no action is taken, so the user will not be able to do anything - the applet will no longer do anything useful!
We will be looking at how the scoring works in the Pairs2 applet in the next session.
| TechRepublic - sign up for their Java Tips email newsletter - it gives excellent Java tips straight to your mailbox twice weekly. | http://www.techrepublic.com |