Your goal this week is to expand on your understanding of the Swing API, as well as to continue to improve your skills working with Java objects.
Here's a small screenshot of what your new program might look like:
Here is what you must provide:
A 10 x 10 grid of buttons that initalize in state "A". You may indicate state "A" by a text label (I used "wow"), but I recommend using a small, colorful image, such as a red ball or a green square. (Don't use "A" for the label - that's just boring!)
Any button in the above grid, when clicked, should respond by flipping from its current state to the "other" state, "B". Likewise, please indicate state "B" via a different image or label. (Not "B", please!)
At the bottom or side of your window, provide a special button called "step" that, when clicked, inverts the state of all 100 buttons.
Your application should perform these update operations only when buttons are actually pressed. This means that it should be event-driven, and not have a loop that constantly polls for user interactions. An event-driven approach will make your program much more efficient as far as CPU usage is concerned.
Finally, make sure to configure your program so that it will shut down the Java VM when the user clicks on the close-window button.
Sounds easy enough, right?
Here are some other tips:
To read more about creating arrays in Java, check out this page. Be sure to note that when you create an array of references-to-objects, that's all you get: an array of references to objects, none of which actually refer to real objects yet! You must construct each individual one with a new statement. You might want to use a two-dimensional array to represent your grid of JButtons.
Just like last week's starter-program, your lab should not directly create the user interface in its main() method. This is not the correct way to use Swing. What you need to do is to use the static SwingUtilities.invokeLater(Runnable r) method to perform your UI initialization. (The SwingUtilities class is in the javax.swing package.) Here is one example of how you might do that:
public class MyApp {
/** Frame for my UI to appear in. **/
private JFrame frame;
/** A button! **/
private JButton button;
/**
* A private helper method that performs the UI initialization. DO NOT
* CALL THIS DIRECTLY. It must be invoked by SwingUtilities.invokeLater().
**/
private void initGUI() {
// Set up the user interface.
frame = new JFrame("My Application");
button = new JButton("A Button!");
... // etc.
// Finally, show the GUI.
frame.pack();
frame.setVisible(true);
}
/**
* Safely initializes the user interface via SwingUtilities.invokeLater().
**/
public void startApp() {
// Call initGUI()!
// (We do this extra stuff to make sure that Swing won't hang.)
SwingUtilities.invokeLater(
new Runnable() { public void run() { initGUI(); } }
);
}
/**
* The main entry-point of our program.
**/
public static void main(String args[]) {
// Create application object, and start it.
MyApp appInstance = new MyApp();
appInstance.startApp();
}
}
(You don't have to understand exactly what this is doing yet. We will talk about this next week at lecture. However, if you are really curious then you can read this tutorial about threads and Swing.)
Consider using a default BorderLayout as the layout manager of your JFrame's content pane. You can add a JPanel container-object to the CENTER of the content pane, and your special "step" button to the SOUTH. You can then set a different, more applicable layout manager on the inner JPanel and add your grid of 100 buttons to it.
(Building up a user interface from smaller collections of components is a very common pattern in GUI implementation, in Java and in other languages!)
For the buttons in the grid, you might want to create a ToggleButton class that subclasses JButton, to make the task of toggling a button's state and updating its appearance as simple as possible. You wouldn't use a ToggleButton for the "step" button though, since that only needs standard JButton functionality.
You will need to understand how to register an ActionListener with a component to be able to listen for mouse clicks. The ActionEvent contains a reference to the component that fired the event, and you can retrieve this reference and cast it to the appropriate type.
You might want to think about how to only use one ActionListener implementation to handle all buttons in the user interface, or perhaps how to use one to handle individual toggle-buttons, and another to handle the "step" button. This will become very helpful next week!
You might be tempted to use a MouseListener for this assignment, but don't do it! The main reason why is that Swing widgets already have capabilities for handling both mouse and keyboard events, and both of these kinds of events are mapped to ActionEvents. However, if you only listen for mouse events, your application won't be able to respond to keyboard events. The intended approach is for Swing applications to handle ActionEvents, and the Swing widgets handle the lower-level mouse and keyboard events.
You'll want to understand what it means when a class implements an interface as well.