Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Chapter 9 Improving the User Interface Go Section 1 - Query Controlled Programs Go Section 2 - Menu Controlled Programs Go Section 3 - Introduction to Try-Catch Statements Go Section 4 - GUI Driven Programs Go Section 5 - Printf and String.format Statements Go Section 6 - Processing Numerous ActionListeners 1 Chapter 9 Objectives • Design a query-controlled program. • Design a menu-controlled program. • Understand the model-view program design • Write try-catch and throw statements for error processing • Design a graphical user interface for an Applet program. • Understand the model-view-controller program design • Format output text for a GUI program using System.format 2 Section 1 Query Controlled Programs 3 9.1 A Thermometer Class // The Thermometer model class. public class Thermometer { private double degreesCelsius; // Java will provide a default constructor! public double getCelsius() { return degreesCelsius; } This is a model class that we will be using in a number of demo programs in this chapter. public double getFahrenheit() { return degreesCelsius * 9.0 / 5.0 + 32.0; } public void setCelsius(double degrees) { degreesCelsius = degrees; } public void setFahrenheit(double degrees) { degreesCelsius = (degrees - 32.0) * 5.0 / 9.0; } } // end of class 4 9.1 Query Controlled Programs We have studied count-controlled loops (entering data inside a for loop a prescribed number of times) and sentinel-controlled loops (entering data until a sentinel value is entered, like -1) and also query-controlled loops that ask the user if they want to run a loop another time and they answer either “yes” or “no”. Here is the sample output of a new program named ConvertWithQuery_9_1. 5 9.1 Repeating Sets of Inputs • The Query Program is implemented by two classes: – The View class ConvertWithQuery_9_1 (the driver) – The Model class Thermometer that models a Thermometer object. – Did you notice that the Thermometer class has only one instance variable, degreesCelsius. – If the fahrenheit equivalent is needed it is returned by the accessor method getFahrenheit(). 6 9.1 ConvertWithQuery_9_1 Driver Program public class ConvertWithQuery_9_1 { public static void main(String [] args) { Scanner reader = new Scanner(System.in); Thermometer thermo = new Thermometer(); String doItAgain = “y”; while (doItAgain.equals(“y”) || doItAgain.equals(“Y”)) { System.out.print(“\nEnter degrees Fahrenheit: ”); double fahr = reader.nextDouble(); thermo.setFahrenheit(fahr); reader.nextLine(); // Consume the trailing end of line System.out.println(“The equivalent in Celsius is ” + thermo.getCelsius()); System.out.print(“\nDo it again (y/n)?”); doItAgain = reader.nextLine(); } } } 7 9.1 ConvertWithQuery_9_1 Program Let’s stop and run the program ConvertWithQuery_9_1.java with …. the model class Thermometer.java and the view class ConvertWithQuery_9_1.java Thermometer ConvertWithQuery_9_1 model class view class The driver class is ConvertWithQuery_9_1.java and it is also the view class. This class calls methods of the model class, Thermometer. 8 Section 2 Menu Controlled Programs 9 9.2 Form of Menu Controlled Programs In a menu-driven program, a list of options are displayed for the user so an operation can be selected to perform. Once the operation is complete, the program redisplays the menu so another operation can be selected. One of the operations always available is to quit the program. The run of a sample menu controlled program is shown on the next slide. 10 9.2 ConvertWithMenu_9_2 Program Output 1) Convert from Fahrenheit to Celsius 2) Convert from Celsius to Fahrenheit 3) Quit Enter your option: 1 Enter degrees Fahrenheit: 32 The equivalent in Celsius is 0.0 Sample program run of the menu controlled program named ConvertWithMenu_9_2 1) Convert from Fahrenheit to Celsius 2) Convert from Celsius to Fahrenheit 3) Quit Enter your option: 2 Enter degrees Celsius: 100 The equivalent in Fahrenheit is 212.0 1) Convert from Fahrenheit to Celsius 2) Convert from Celsius to Fahrenheit 3) Quit Enter your option: 11 9.2 ConvertWithMenu_9_2 Code menuOption = 4; // prime the loop to start while (menuOption != 3) { System.out.print(menu); // Display the menu and get the user's option menuOption = reader.nextInt(); System.out.println (); if (menuOption == 1) { System.out.print("Enter degrees Fahrenheit: "); double farh = reader.nextDouble(); thermo.setFahrenheit(fahr); System.out.println ("The equivalent in Celsius is " + thermo.getCelsius()); } else if (menuOption == 2) { System.out.print("Enter degrees Celsius: "); double celsius = reader.nextDouble(); thermo.setCelsius(celsius); System.out.println ("The equivalent in Fahrenheit is " + thermo.getFahrenheit()); } else if (menuOption == 3) System.out.println("Goodbye!"); // this selection ends the loop else System.out.println ("Invalid option"); // Invalid option; re-enter option } 12 9.2 ConvertWithMenu_9_2 View Program Let’s stop and run the program ConvertWithMenu_9_2.java with …. the model class Thermometer.java and the view class ConvertWithMenu_9_2.java Thermometer ConvertWithMenu_9_2 model class view class The driver class is ConvertWithMenu_9_2.java and it is also the view class. This class calls methods of the model class, Thermometer. 13 Section 3 Try - Catch Statements Allowing Programs to Gracefully Continue 14 9.3 Handling Number Format Exceptions To this point, if data input is of the wrong type, a program will throw an exception and display an error message in the terminal window and halt the program. (An applet program may just do nothing in response to invalid data and you wouldn’t know there is a problem.) What we really want is for a program to identify invalid data and output an error message, but then allow the program to run without crashing it. 15 9.3 Handling Number Format Exceptions In a console program where we are asking for numeric input and characters other than numeric digits are entered from the keyboard, then the program will crash unless the code is embedded within a try-catch statement. Methods like nextInt() and nextDouble() actually implicitly (behind the scene) parse the data input from the keyboard when using a Scanner object. However, if the data is not numeric, then an exception will be thrown by the program and it will be halted … unless the reader.nextInt() or reader.nextDouble() is imbedded in a try-catch statement. 16 9.3 General Form of a Try-Catch Statement Programmers write the code in the try clause (branch) that they need in a program to call various operations. If one of the operations fails and an exception is thrown - “it will be caught” and the catch clause (branch) will be executed and an error message displayed. try { // code here that has the possibility of throwing an exception } catch (Exception e) { // error message here that describes the exception } 17 9.3 Try-Catch Statement Example Statements within a try branch are executed until an exception is thrown or all statements are executed. If an exception is thrown, execution is immediately sent to the catch branch, skipping the remainder of any code in the try branch. try { System.out.print("Enter degrees Fahrenheit: "); double fahr = reader.nextDouble(); thermo.setFahrenheit(fahr); System.out.println("The equivalent Celsius is " + thermo.getCelsius()); } catch (Exception e) { System.out.println(“Bad Number Format! You did not input a number.”); } 18 9.3 Handling Number Format Exceptions If no statement throws an exception within the try clause, the catch clause is skipped. Many types of exceptions can be thrown. There is an Exception class that is at the top of a hierarchy for all exception types. Catching an Exception object will catch any of them. However, it is better to be specific about the kind of exception when you can. For example, you may want a program to output the error message “divide by zero error” if an exception is thrown. So it would be better to use an ArithmeticException. 19 9.3 ConvertWithQuery_9_3 Program Let’s stop and run the program ConvertWithQuery_9_3.java and see how a try-catch statement can provide error checking and allow a program to “gracefully continue”. We’ll use …. the model class Thermometer.java and the view class ConvertWithQuery_9_3.java Thermometer ConvertWithQuery_9_3 model class view class The driver class is ConvertWithQuery_9_3.java and it is also the view class. This class calls methods of the model class, Thermometer. 20 9.3 Original getScore method of Student Class Remember the code for the getScore method of the Student class. It looked like this. public int getScore (int i) { if (i == 1) return test1; else if (i == 2) return test2; else return test3; } This method trusts whoever calls this method to pass it a correct value, either a 1, 2, or 3, since there are only 3 tests for a Student object. Programmers build in their own kind of error messages into code like this by writing “throw” statements in their methods . (See next slide) 21 9.3 Modified getScore method of Student Class Here is an example of how to add a Java “throw” statement to a method like getScore and change its method signature: public int getScore (int i) throws IOException { if ( i < 1 | | i > 3 ) throw new IOException(“Test number out of range. Must be 1, 2, or 3”); if (i == 1) return test1; else if (i == 2) return test2; else return test3; } To be able to use a throw statement with IOException you must import the following: import java.io.IOException; 22 9.3 Calling getScore in a Try-Catch Statement In some other file, (other than Student.java) we could then call the getScore method in a try-catch statement as follows: try { Student s1 = new Student(“Ann”, 95, 88, 92); System.out.print(“Which test score do you want? ”); int whichTestScore = reader.nextInt(); int testScore = s1.getScore(whichTestScore )); System.out.println("The test score is: ” + testScore ); } catch (Exception e) { System.out.println(e); } Note: if the user enters some integer other than 1, 2, or 3, then the error message from the throw statement in the method “Test number out of range. Must be 1, 2, or 3” comes back in the parameter e and is printed by the System.out.println statement. 23 9.3 Throw Statement Specify Errors More Clearly Writing throw statements in methods helps clarify the errors that occur in a program. If a user enters a String, the error message still makes sense and instructs the user what he or she should do. public int getScore (int i) throws IOException { if ( i < 1 | | i > 3 ) throw new IOException(“Test number out of range. Must be 1, 2, or 3”); if (i == 1) return test1; else if (i == 2) return test2; else return test3; } 24 9.3 When to Write a Throw Statement In conclusion, if you are writing a method that has the possibility of failing based on user input, then you can include a throw statement in your method like the one in getScore. However, if you don’t have access to the code of the method, then you can write an appropriate error message in the catch clause so it is printed instead of printing e. catch (Exception e) { System.out.println(“Error! Your input is out of range!”); } instead of catch (Exception e) { System.out.println(e); } 25 Section 4 GUI Driven Programs 26 9.4 GUI programs are event-driven • GUI programs are event-driven. – • when a program opens, it waits for events Events are generated when the user interacts with the GUI by …. • • entering data in text fields • clicking buttons • making selections from menus or other GUI components. Events invoke controller classes, which in turn invoke model classes. 27 9.4 GUI Programs In many ways, GUI programs provide more user-friendly interaction with a program. However, some GUI components are more user-friendly than others. JOptionPane boxes, like we have used previously, can be limiting and tedious to use if a lot of input needs to be entered. A JTextField is one GUI component that is easier to use than a JOptionPane box. We are going to examine and use the basic components in many GUI programs … JLabels, JTextFields, JButtons, and JTextAreas. We will also look at the basic ways of controlling the placement of GUI components using border, flow, and grid layouts. 28 9.4 ConvertWithGUI_9_4 Applet Program JLabels Title only available for JFrame programs not Applet programs. JTextFields JButton - note a button can have a name or label on it that isn’t a JLabel The User Interface components of the GUI-based temperature conversion program 29 9.4 The JLabel Component JLabels provide labeling of other GUI components, but primarily labeling or identifying JTextFields. They may be located anywhere near the component they are identifying, above, below, to the left, or to the right of a component. The choice is up to the user and is only limited by the demands of the particular kind of layout that is being implemented. Placing JLabels near JTextFields helps the user understand what the JTextFields are for. 30 9.4 The JTextField Component JTextFields allow for the input of data into a GUI program, but also allow for output of data. After data is entered into a JTextField, if a button is clicked or a menu item selected, then the data can be received and processed. All input from a JTextField must be processed first as String data. If the string data is numeric, it can then be processed using parsing. A program can have any number of JTextFields and each can be set up to receive or display different sets of data in a GUI program. 31 9.4 The JButton Component JButtons allow for controlling events in a GUI program. As we just mentioned on the last slide, after data is entered into a JTextField, if a button is clicked, then the data can be received and processed. All JButtons in a program have “listeners” so that the events specified by the program can take place when the buttons are clicked. A program can have any number of JButtons with each button designated to process one of the specific events in the GUI program. 32 9.4 The JTextArea Component JTextAreas also allow for the entry of data into a GUI program, but are mostly used for the output of data. JTextAreas are usually more appropriate for outputting data in a GUI program than JTextFields, because they provide more area for output to be displayed in. Many times more than just a single number or single word needs to be displayed or you want to display data in columns. It is possible to concatenate String and numeric output in JTextAreas and then format it using the String.format() method, which is similar to System.out.printf. A program can have any number of JTextAreas each with a designated purpose within a GUI program. 33 9.4 The ConvertWithGUI_9_4 View Class • ConvertWithGUI_9_4 is the main view class and it will … – construct and maintain a variable to a Thermometer object. The Thermometer class is the model class. – construct and maintain variables for JLabels, JTextFields, and a JButton and add these GUI components to the window’s container. – construct and attach a FahrenheitListener object to the JButton. – provide a private inner class named FahrenheitListener that is the controller class for the program. This program is a GUI Driven applet program. 34 9.4 The ConvertWithGUI_9_4 View Code public class ConvertWithGUI_9_4 extends JApplet { // >>>>>>> The model <<<<<<<< // Declare and instantiate the thermometer Thermometer thermo = new Thermometer(); // >>>>>>> The view <<<<<<<< Here we construct the Thermometer object for the program and all of the GUI components. They are all global and are declared and constructed immediately after the class definition. // Declare and instantiate the window objects. JLabel titleLabel = new JLabel("Temperature Converter Applet"); JLabel fahrLabel JLabel celsiusLabel JTextField fahrField = new JLabel(" = new JLabel(" Degrees Fahrenheit"); Degrees Celsius"); = new JTextField("32.0"); JTextField celsiusField = new JTextField("0.0"); JButton fahrButton = new JButton("Convert >>>"); JButton celsiusButton = new JButton("<<< Convert"); Initial Code of ConvertWithGUI_9_4.java 35 9.4 BorderLayout With Five Regions Here is a representation of a BorderLayout. The largest region is the Center region, so that is where you usually place the panel with the most components. The other four regions will become larger as components are added to them. You don’t have to use any region. We will put our GUI components in panels and then add them to the regions we want to use. north region center region east region west region south region 36 9.4 The ConvertWithGUI_9_4 View Code public void init () { // declare title panel and add components JPanel titlePanel = new JPanel(); titlePanel.add(titleLabel); // declare data panel and add components JPanel dataPanel = new JPanel(new GridLayout(2, 2, 12, 6)); dataPanel.add(fahrLabel); dataPanel.add(celsiusLabel); dataPanel.add(fahrField); dataPanel.add(celsiusField); // declare button panel and add components JPanel buttonPanel = new JPanel(); buttonPanel.add(fahrButton); // set up container and add panels Container container = getContentPane(); container.add(titlePanel, BorderLayout.NORTH); container.add(dataPanel, BorderLayout.CENTER); container.add(buttonPanel, BorderLayout.SOUTH); The init method for the program creates panels for the components and then adds them to the panels. It also establishes the placement of the panels in the BorderLayout. It finally, adds a listener to the JButton. // Attach a listener to the convert button fahrButton.addActionListener(new FahrenheitListener()); } 37 9.4 ConvertWithGUI_9_4 Applet Program titlePanel in NORTH dataPanel in CENTER buttonPanel in SOUTH For this applet, only the north, center, and south regions of the BorderLayout are used. Each of these regions contains a panel and each of the panels contains one or more components. 38 9.4 The Private Inner Listener Controller Class When the user clicks the Convert button, the following code is executed. // >>>>>>> The controller <<<<<<<< private class FahrenheitListener implements ActionListener { public void actionPerformed(ActionEvent e) { String input = fahrField.getText(); // Obtain input double fahr = Double.parseDouble(input); // Convert to double thermo.setFahrenheit(fahr); // Reset thermometer double celsius = thermo.getCelsius(); celsiusField.setText("" + celsius); // Obtain Celsius // output result } } The private inner listener class must implement ActionListener and needs only one method … the actionPerformed() method. 39 9.4 The getText() JTextField Method The JTextField class has a number of important methods. One of the most important is the getText() method that retrieves what has been entered into a JTextField, like fahrField, as a String. If by program design the value is intended to be a number, then it must be parsed to the type of number that is expected. After it is parsed it can be used as needed in the program. 40 9.4 The setText() JTextField Method The setText() method erases everything in a JTextField and then places a String value back in it. If the value is a number, it must be first converted to a String. Remember this code that draws the number 10 with g … g.drawString( "" + 10, 100, 100 ); To convert 10 to a String, we had to concatenate it to empty string. The same thing is being done with the line of code: celsiusField.setText("" + celsius); It converts the number stored in celsius to a String before placing the String in the JTextField. 41 9.4 The JTextField and JTextArea Methods The most important JTextField and JTextArea methods are: JTextField or JTextArea Methods What it does String getText( ) returns the string currently occupying the JTextField or JTextArea. void setText(String s) displays the String s in the JTextField or JTextArea after erasing it. void append(String s) concatenates the String s to any other information already being displayed in the JTextField or JTextArea. No erasing! void setEditable (boolean b) the JTextField or JTextArea is read only by the user if b is false. The user can erase or edit the field if b is true. The default value if this method is not called is true so the it is editable. void requestFocus (boolean b) makes the cursor go immediately to the JTextField or JTextArea without the user clicking the mouse in it. 42 9.4 Using The setEditable Method Many times we may want to have a JTextField or JTextArea that is only for displaying output and we don’t want the user to be able to delete or edit any of the information. This is where we can use the setEditable() method. Let’s say we have the following JTextArea declared: JTextArea output = new JTextArea (); output.setEditable(false); Programmers make JTextAreas un-editable more often than JTextFields. Typically, JTextFields are used for input and JTextAreas are used for output. 43 9.4 Using The requestFocus Method You can use requestFocus with either a JTextField or JTextArea, however, since users aren’t usually typing in a JTextArea it doesn’t make sense to request the focus for that component. We use requestFocus when we want to save the user effort by placing the mouse cursor in an obvious place where something needs to be entered for input. So, if you have a JTextField variable named fahrFld and you have declared and instantiated it in a GUI program, then when it loads you can make the cursor go immediately to fahrFld, without the user clicking the mouse in the JTextField, by using the line of code: fahrFld.requestFocus(); However, there are times when this method doesn’t seem to work. 44 9.4 JTextField ActionListeners After entering data into a JTextField named fahrFld , if you want the input to be processed by pressing the “enter” or “return” key on your keyboard without clicking a GUI button, you can add an action listener to the JTextField variable. fahrFld.addActionListener(new FahrenheitListener()); If you have a private inner class already defined named FahrenheitListener that you are using for a button, then you simply add an anonymous call to the class constructor as the parameter for the addActionListener ( ) method as seen above. 45 9.4 Model-View-Controller Pattern • The model-view/controller pattern is used by most programmers as a way to consistently divide the responsibility of different parts of an application between the different classes in an organized manner. – Model: The data that the program uses and the operations that can be performed on that data. In this program, the Thermometer class serves as the model. – View: What the user of the program interacts with. In this program, the ConvertWithGUI_9_4 class contains the view and sets up the model. – Controller: Usually a private inner listener class that coordinates model and view classes by passing messages and data between them. In this program the controller is the private inner listener class FahrenheitListener. – Driver: Since ConvertWithGUI_9_4 is an applet class it acts as a driver. It is the file you compile to run the program. 46 9.4 Variations of Model-View-Controller • • Finally, GUI programs that are just JFrame programs are meant to be stand-alone programs that will not appear in a web page and may include the following files: • model classes • a view class • a private inner class that is a listener • an application class or driver class that starts the program However, applet programs usually combine the view class and are the driver so that many times you have only the following files: • model classes • a view class that is also a driver class • a private inner class that is a listener 47 9.4 Variations of Model-View-Controller Note: it is possible for JFrame or applet programs both to have only one file. A file that contains both of the following: • a view class that is also a driver class that doesn’t use a model class • a private inner class that is a listener GUI programs like these do not use a model class and may just contain methods that do mathematical calculations or process data in a way such that a model class is not needed. In this case, everything is stored in one file. This will be the case when you work on the PI_Approximator GUI program. 48 9.4 Handling Exceptions in a GUI Program In GUI programs, we have to actually explicitly perform the parsing of input with lines of code that use parseInt() and parseDouble(), since a user on the internet would not be able to see any exception errors in a terminal window. To allow a GUI or terminal program to continue, we can place our lines that parse the input inside try-catch statements. The try-catch statement allows exceptions to be caught and handled appropriately. 49 9.4 Number Format Exceptions in a GUI Here a try-catch statement is used to process the input from a GUI program. Notice the input has to be parsed to make sure the input is of type double. If it is not parsed, an exception will be thrown. try { String input = fahrField.getText(); // get the input from a GUI field double fahr = Double.parseDouble(input); // parse the input to a double … // other code } catch (Exception e) { System.out.println(“Bad Number Format!”); } More about this on the next slide … 50 9.4 Number Format Exceptions in a GUI Again, all input from a GUI text field is of type string, even values like 17 or 34.5678. The methods parseInt and parseDouble convert input to an int or double value unless a value like the string “asdf” is entered. “asdf” cannot be parsed to an int or double, so either the method parseInt or parseDouble would throw an exception within the try branch and the catch clause would be immediately executed. try { String input = fahrField.getText(); // get the input from a GUI field double fahr = Double.parseDouble(input); // parse the input to a double … // other code } catch (Exception e) { System.out.println(“Bad Number Format!”); } 51 9.4 Making ConvertWithGUI_9_4 More Robust private class FahrenheitListener implements ActionListener { public void actionPerformed(ActionEvent e) { try{ String input = fahrField.getText(); // Obtain input double fahr = Double.parseDouble(input); // Convert to double if (fahr >= -459.67) { thermo.setFahrenheit(fahr); // Reset thermometer double celsius = thermo.getCelsius(); // Obtain Celsius String s = String.format("%,15.5f", celsius); // Format result celsiusField.setText(s); // Output result } else { JOptionPane.showMessageDialog(ConvertWithGUI_9_4.this, "Impossible! That number is below absolute zero", Fahrenheit Converter", JOptionPane.ERROR_MESSAGE); fahrField.setText(""); celsiusField.setText(""); } }catch(Exception ex){ JOptionPane.showMessageDialog(ConvertWithGUI_9_4.this, "Bad number format", Fahrenheit Converter", JOptionPane.ERROR_MESSAGE); fahrField.setText(""); celsiusField.setText(""); } } } Code that catches number format errors and invalid input. 52 9.4 The Parsing Code Throws This Exception Bad Number Format Exception Thrown because of input KCD123 53 9.4 Programmer Set Limit Throws Exception Illegal Range Exception Thrown because of input -500 degrees F. For this kind of exception, code must be written that throws the exception if a Fahrenheit value below -459.69 is entered into the JTextField. 54 9.4 Layouts for GUI Programs • • The 3 most commonly used simple layouts are: – BorderLayout – FlowLayout – GridLayout BorderLayout is the default layout for JFrame and JApplet programs. So there is no need to set the layout of the GUI. • To change the layout to a different one use: Container c = getContentPane(); c.setLayout( new FlowLayout( ) ); or c.setLayout( new GridLayout(numRows, numCols ) ); 55 9.4 FlowLayout When a FlowLayout is used, the content pane displays the GUI components in rows in a left to right fashion based on how wide the GUI window is. If Java runs out of room when placing a component, it automatically flows to the next row where it will be displayed. In stand-alone JFrame programs that are not applets on line, a FlowLayout can cause the presentation of the GUI to change if the user stretches the GUI window wider or narrower. For applets, however, if you know how wide the GUI window needs to be to display things the way you want, then you can set the display size of the applet and then it won’t be able to be resized when it is embedded in a web page. Then the components won’t move. FlowLayout is the no-thrills presentation of GUI components. It is used when exact placement of components may not be required. 56 9.4 FlowLayout Output Examples If the user resizes the GUI window of a FlowLayout, then it will look differently as the components are displayed in the different rows. 57 9.4 BorderLayout Every container object (frame or panel) uses a layout manager object to organize and lay out the graphical components contained in it. The default layout manager for JFrames and JApplets is an object of the class BorderLayout. You can arrange up to five graphical objects in a container in the following positions: NORTH, SOUTH, EAST, WEST, and CENTER If we add fewer than 5 objects to a BorderLayout, the layout manager stretches some of them to fill the unoccupied areas. 58 9.4 BorderLayout With Five Regions Here is our representation of a BorderLayout again. The largest region is the Center region, so that is where you what to place the panel that contains the most components. Any of the other four regions can be used if desired or excluded. north region center region east region west region south region 59 9.4 GridLayout with Rows & Columns This code produces a frame with a grid containing 2 rows and 2 columns of colored panels. package ch02; import javax.swing.*; // To import JFrame and JPanel classes import java.awt.*; // To import Color, Container, and GridLayout classes public class GUIWindow4 { public static void main(String[] args) { JFrame theGUI = new JFrame(); theGUI.setTitle("Fourth GUI Program"); theGUI.setSize(300, 200); theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Example from Chapter 2 of a GridLayout that divides a container into rows and columns with equal size cells. JPanel panel1 = new JPanel(); panel1.setBackground(Color.white); JPanel panel2 = new JPanel(); panel2.setBackground(Color.black); JPanel panel3 = new JPanel(); panel3.setBackground(Color.gray); JPanel panel4 = new JPanel(); panel4.setBackground(Color.white); Container pane = theGUI.getContentPane(); pane.setLayout(new GridLayout(2, 2)); // (2 rows, 2 columns) pane.add(panel1); pane.add(panel2); theGUI.setVisible(true); pane.add(panel3); pane.add(panel4); } } 60 9.4 Alternate GridLayout Constructor Instead of … JPanel dataPanel = new JPanel(new GridLayout(2, 2)); You can use … JPanel dataPanel = new JPanel(new GridLayout(2, 2, 5, 3)); This constructor call takes 4 parameters. The first two are still the number or rows and columns and the third is the horizontal gap between columns and the fourth parameter is the vertical gap between rows. For more info on GridLayout: http://java.sun.com/j2se/1.6.0/docs/api/java/awt/GridLayout.html 61 9.4 Advanced Layouts Because a program may use an overall layout for the container and then contain JPanel objects in each region of a layout, sometimes we place individual layouts inside the panels to more accurately control the overall layout of the GUI. Notice here how we place two JPanels that have GridLayouts in the CENTER and SOUTH regions of a BorderLayout. Here is an example: JPanel dataPanel = new JPanel(new GridLayout(2, 2); …. // add the components to this panel JPanel buttonPanel = new JPanel(new GridLayout(1, 4); …. // add the components to this panel Container c = getContentPane(); c.add(dataPanel, BorderLayout.CENTER); c.add(buttonPanel, BorderLayout.SOUTH); 62 9.4 Making Temperature Conversion Go Both Ways Temperature converter program that goes both ways after modifying the ConvertWithGUI_9_4.java code. There are now two JTextFields and two JButtons. 63 9.4 Making Temperature Conversion Go Both Ways • Here are the changes that have to be made: – Declare and instantiate a second button – Add second button to button panel – Create a listener object and attach it to the second button – Define a second listener class that converts from Celsius to Fahrenheit You are now going to complete the above changes to the ConvertWithGUI_9_4.java file so the program works both ways. 64 9.4 GUI Program JTextAreas JTextAreas are similar to JTextFields. You can construct a text area with 10 rows and 20 columns to display textual information using: JTextArea output = new JTextArea(10, 20); 65 9.4 GUI Program JScrollPanes You can force a JTextArea to display scroll bars by wrapping it in a JScrollPane as follows: JTextArea output = new JTextArea(10, 20); JScrollPane myJScrollPane = new JScrollPane(output); Now a user can scroll down a text area and view information that is being displayed beyond the bottom of the window. The user of the program can then scroll down or up at will to view any of the information in the window. 66 9.4 Setting Wheel Scrolling You can also make JTextAreas respond to the scroll wheel on a mouse by using the following code: JTextArea output = new JTextArea(10, 20); Code in the init() method: JPanel textPanel = new JPanel(); JScrollPane myJScrollPane = new JScrollPane(output); myJScrollPane.setWheelScrollingEnabled(true); textPanel.add(myJScrollPane); 67 Section 5 More About Printf Statements and Using String.format ( ) 68 9.5 Sample Unformatted and Formatted Output We’ve learned that println statements don’t allow us to format data in a program easily. However, printf statements do. When we are working with GUI programs and we want to output data to a JTextArea, we can’t use printf. But Java provides a format() method of the String class that works identical to printf. Therefore, we can format a String value first and then send it to a JTextArea. Output #1 unformatted and less readable Washington 4000.0 Adams 36000.0 Jefferson 150000.0 Output #2 formatted and more readable using String.format() NAME Washington Adams Jefferson SALARY 4,000.00 36,000.00 150,000.00 69 9.5 DisplayTable Demo Code public class DisplayTable_9_7 { public static void main(String[] args) throws IOException { Scanner names = new Scanner(new File("ch09/names.txt")); Scanner salaries = new Scanner(new File("ch09/salaries.txt")); System.out.printf("%-16s%12s%n", "NAME", "SALARY"); while (names.hasNext()) { String name = names.nextLine(); double salary = salaries.nextDouble(); System.out.printf("%-16s %,12.2f %n", name, salary); } } } Note the %,12.2f in the last printf statement above, the use of the decimal separator flag %, (comma) to place commas every 3 decimal places in the value contained in salary. Run the DisplayTable_9_7.java demo program and view the output to see the commas in the numbers. 70 9.5 Formatted Output with printf and format Since the introduction of Java 5.0, printf statements and String.format statements have been available for formatting output for left or right justification. There are two parameters for either of these statements: 1. A format string that contains literal string information and formatting information called format specifiers. 2. A list of variables or expressions to be formatted. There should be one variable or expression for every format specifier in the format string. The general form of a printf or String.format statement is: System.out.printf (<format string>, <expression 1>, … <expression n>); String s = String.format (<format string>, <expression 1>, … <expression n>); 71 9.5 Use of printf Statements Earlier this year you learned about printf statements and found that output could be formatted for left or right justification in a console program. Here is an example you may remember: System.out.printf("The square of %5d is %10.3f%n", number, square); You can see how it follows the general form of a printf statement: System.out.printf (<format string>, <expression 1>, … <expression n>); In the above printf statement, the first parameter is the format string and it contains a combination of literal string information, “The square of” and “is”, and the format specifiers for the expressions, namely %5d, %10.3f, and %n. (number and square are the expressions) 72 9.5 Why String.format Statements A String.format statement is appropriate if we want to format columns in a JTextArea. When we send the string to the JTextArea, we want it to be nicely formatted. We would only use System.out.printf if we were going to display things in the console window NOT in a GUI.. 73 9.5 Use of String.format Statements The parameters of a printf or String.format statement are written following the exact same rules. Compare the general forms again: System.out.printf (<format string>, <expression 1>, … <expression n>); String s = String.format (<format string>, <expression 1>, … <expression n>); System.format statements are used to format data in the same way as printf statements, however, the formatted data is not send to output, but rather returned as a String value that can be stored in a String variable or sent directly to a GUI JTextField or JTextArea. Here is an example, of how it might be used if we have a previously defined JTextArea named output: String s = String.format("The square of %5d is %10.3f%n", number, square); output.setText(s); // erases the entire JTextArea and then displays s or output.append(s); // add s to the already existing output without erasing it 74 9.5 Format Specifiers The format string consists of one or more format specifiers. Each format specifier … begins with a ‘%’ character which is followed by a number and ends with a letter that indicates the format type. Example format specifiers: “%5d” “%5.2f “%12s” For integers the letter that indicates the format type is d. For doubles the letter that indicates the format type is f. For strings the letter that indicates the format type is s. 75 9.5 Left & Right Justification of Output “%5d” - right justifies the int value in a field width of 5 “%7.2f - right justifies the double value in a field width of 7 “%12s” - right justifies the String value in a field width of 12 “%-5d” - left justifies the int value in a field width of 5 “%-7.2f - left justifies the double value in a field width of 7 “%-12s” - left justifies the String value in a field width of 12 76 9.5 Printf Example of formatting int values for (int i = 1; i <= 5; i++) { System.out.print(“Enter the age: ”); int age = reader.nextInt(); System.out.printf("%5d", age); } Screen output is 5 ages all on one line. 1 format specifier in the format string variable to be formatted Here the “%5d” tells us that we have a field width of 5. 77 9.5 Printf Example of formatting double values for (int i = 1; i <= 5; i++) { System.out.print(“Enter the average: ”); double average = reader.nextDouble(); System.out.printf("%5.2f", average); } Screen output is 5 averages all on one line. 1 format specifier in the format string variable to be formatted Here the “%5.2f” tells us that we have a field width of 5 with a precision of 2 decimal places. 78 9.5 Printf Example of formatting String values for (int i = 1; i <= 5; i++) { System.out.print(“Enter the name: ”); String name = reader.nextLine(); System.out.printf("%12s", name); } Screen output is 5 names all on one line. 1 format specifier in the format string variable to be formatted Here the “%12s” tells us that we have a field width of 12. 79 9.5 Printf Example of formatting All values for (int i = 1; i <= 5; i++) { Note the %n System.out.print(“Enter the name: ”); that produces String name = reader.nextLine(); a new line System.out.print(“Enter the age: ”); int age = reader.nextInt(); System.out.print(“Enter the average: ”); double average = reader.nextDouble(); System.out.printf("%12s%5d%5.2f%n", name, age, average); } 4 format specifiers in the format string variables to be formatted 80 9.5 Non-Specific Double Format Specifiers • Non-Specific format specifiers are always left justified instead of right justified. So if you need them right justified, then you need to use a field width. In this example, the field width is not given: double dollars = 25; double tax = dollars * 0.125; Note: no field width just precision System.out.printf(“Income: $%.2f%n ”, dollars); System.out.printf(“Tax owed: $%.2f%n ”, tax); %.2f allows as many spaces to the left of the decimal point as are needed to display that portion of the double value in the variables dollars and tax. Or in one line of code: System.out.printf(“Income: $%.2f%nTax owed: $%.2f%n”, dollars, tax); 81 9.5 %n and %% • Symbol %n embeds an new-line character in a format string. • Symbol %% produces a literal '%' character. • When compiler sees a format specifier, it attempts to match that specifier to an expression following the string. – It must match in type and position or your program or you will get a ... java.util.IllegalFormatConversionException 82 9.5 The Comma Format Flag printf and String.format can justify text and produce tabular output and make use of other format flags. One key format flag, the comma, will place a comma every three places in a number. For example, the lines of code: int num = 20345000; System.out.printf("%,10d", num); String s = String.format("%,10d", num); output.setText(s); // where output is a JTextArea will display 20,345,000 when sent to either output. 83 9.5 Formatting Columns of Data • To output data in formatted columns: – Establish the width of each field. – Choose appropriate format flags and format specifiers to use with printf. • The width of a field that contains a double appears before the decimal point in the format specifier f, as in “%5.2f”. • So 5 is the overall field width. This means that the floating point value will be displayed with two decimal places and one of the five spaces will be used for the decimal point. So there will be only 2 spaces reserved for the part of the number to the left of the decimal point. If java needs more spaces to display that part of the number, then the system will use whatever spaces are needed and the output will end up left justified, instead of right justified. So be sure and pick a large enough field width. 84 Section 6 Processing Numerous ActionListeners 85 9.6 Processing Numerous ActionListeners Let’s say a GUI program has 5 buttons and they all need an actionListener. There is an easier way to process button mouse clicks than writing a private inner class for each button. In the PI_Approximator program, the class definition line was public class PI_Approximator extends JApplet We then added an actionListener to the computeButton in the init() method and then wrote the code for a private inner class that had an actionPerformed() method that would respond to mouse clicks. This worked fine because we only had one button to process the calculation of π. 86 9.6 Processing Numerous ActionListeners In the ConvertWithGUI_9_4 program, we had two action listeners, one for each of the two buttons, because different things happened when we clicked each one of the buttons. So we had to have two private inner classes with each one having an actionPerformed method. This approach is sufficient for having two or maybe three buttons, because its not too hard to write private inner classes, but what if you have 5 or 10 buttons. Well, there is a simpler approach when you have a lot of buttons and that is what we are going to show you. 87 9.6 Processing Calculator ActionListeners In the Calculator sample GUI program, there are 5 JButtons in the program that have actionListeners added in the init() method: addBtn.addActionListener(this); subBtn.addActionListener(this); multBtn.addActionListener(this); divBtn.addActionListener(this); clearBtn.addActionListener(this); However, notice the class definition line of Calculator has a different form: public class Calculator extends JApplet implements ActionListener Notice the addition of … implements ActionListener 88 9.6 One ActionPerformed Method When your JApplet class implements ActionListener, then you don’t have to have any private inner classes! All you have to do is provide one actionPerformed method and process the different possible action events with an extended-if statement. In each branch of the extended if statement, we can implement code that needs to be executed for each different actionListener (button). So if we have 5 buttons, then we need 5 branches in our extended if statement. (See next slide) 89 9.6 Processing Calculator ActionListeners So, after the init() method we only need an actionPerformed() method that has some code and an extended if like this: public void actionPerformed(ActionEvent e) { // other code with clearBtn, etc. if (e.getSource() == addBtn) { } else if (e.getSource() == subBtn) { } else if (e.getSource() == multBtn) { } else if (e.getSource() == divBtn) { } With this approach to detecting mouse clicks, Java looks at the source of the ActionEvent e, which is the parameter of the method. In other words, when the mouse is clicked on any one of the buttons, the method actionPerformed is immediately called and the source of the mouse click is pinpointed because it is returned by e.getSource() and then the appropriate branch of code is executed. 90 9.6 The CalculatorOneOperand Approach You will take this approach when writing the code for the CalculatorOneOperand program. More details on that later. 91