I. User Interface Example A. Writing GUIs in Java 1. plan ------------------------------------------ INITIAL GUI SKETCH |-------------------------------------| | Formula-Register Calculator | |-------------------------------------| | [ 0.0 ] | |-------------------------------------| | Named Formulas | | | | [ add0 ][\/] [ r1 + r2] (Eval) | | | |-------------------------------------| | Registers | | | | r0 [ 0.0] r1 [ 0.1] | | r2 [ 2.2] r3 [ 0.3] | | r4 [ 0.4] r5 [ 0.5] | | r6 [ 60.6] r7 [ 0.7] | | r8 [ 0.8] r9 [ 0.9] | | | |-------------------------------------| | Formula Composition | | | | First Second | | Register Operator Register | | [ r0][\/] [ +][\/] [ r1][\/] | | | | Name [ ] ( Save ) | | ( Reset ) | |-------------------------------------| ------------------------------------------ 2. Infrastructure, building the Frame a. main program ------------------------------------------ package gui; import javax.swing.JFrame; /** The main program for the calculator. * @author Gary T. Leavens */ public class Calculator { /** * Create a calculator frame and show it. */ public static void main(String[] args) { CalculatorFrame frame = new CalculatorFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } ------------------------------------------ b. JFrame ------------------------------------------ package gui; import javax.swing.*; /** A frame for the Calculator. * @author Gary T. Leavens */ public class CalculatorFrame extends JFrame { /** * Initialize this frame. */ public CalculatorFrame() { setTitle("Formula-Register Calculator"); setSize(WIDTH, HEIGHT); } /** The width of this frame, in pixels. */ public static final int WIDTH = 500; /** The height of this frame, in pixels. */ public static final int HEIGHT = 600; } ------------------------------------------ c. Layout ------------------------------------------ GRIDBAG LAYOUT RECIPE (From "Core Java 2, Volume 1", p. 519) 1. Sketch the layout on paper 2. Find a grid such that the smallest components fit inside single cells. 3. Label rows 0, 1, 2,..., and columns 0, 1, 2, ... from top left. The gridx, gridy are coordinates gridwidth, gridheight sizes of components (>1 if span cells) 4. Decide on fill (horizontal?, vertical? both?), and anchor (alignment) if not filled 5. Set weights to 100, unless you want components in a row or column to stay at their default size (use 0 for them). 6. Write code and double check constraints 7. Compile, run, and enjoy. ------------------------------------------ ------------------------------------------ STARTING A GRIDBAG LAYOUT Container contentPane = getContentPane(); GridBagLayout layout = new GridBagLayout(); contentPane.setLayout(layout); Then - create the components, and - for each component: a. set its constraints b. add it to the contentPane A sample: // textBox for output JTextField outputText = new JTextField(25); outputText.setEditable(false); outputText.setHorizontalAlignment(JTextField.RIGHT); // add components to the grid GridBagConstraints constraints = new GridBagConstraints(); constraints.fill = GridBagConstraints.NONE; constraints.anchor = GridBagConstraints.CENTER; constraints.gridx = 0; constraints.gridy = 0; constraints.gridwidth = 7; constraints.gridheight = 1; contentPane.add(outputText, constraints); ------------------------------------------ 3. Other stuff a. borders ------------------------------------------ MOTTO: YOU CAN DO IT YOU JUST HAVE TO LOOK UP HOW Example: - Make the output text border blue - give it a title Border lined = BorderFactory .createLineBorder(Color.BLUE); Border outputTitle = BorderFactory .createTitledBorder(lined, "Output"); outputText.setBorder(outputTitle); ------------------------------------------ b. a helper method for adding components: ------------------------------------------ A HELPER METHOD FOR ADDING COMPONENTS /** * Add the given component to the given grid bag layout. * This simplifies otherwise tedious code. See Core Java 2, * Volume 1, pp. 521-522. * @param c the component to add * @param constraints the grid bag constraints object to use * @param x the gird x position * @param y the grid y position * @param w the grid width (columns spanned) * @param h the grid height (rows spanned) */ private void add(Component c, GridBagConstraints constraints, int x, int y, int w, int h) { constraints.gridx = x; constraints.gridy = y; constraints.gridwidth = w; constraints.gridheight = h; getContentPane().add(c, constraints); } ------------------------------------------ 4. Adding the main labels: ------------------------------------------ JLabel nfLabel = new JLabel("Named Formulas"); JLabel regsLabel = new JLabel("Registers"); JLabel fcLabel = new JLabel("Formula Composition"); // add components to the grid add(nfLabel, constraints, 0, 1, 7, 1); add(regsLabel, constraints, 0, 3, 7, 1); add(fcLabel, constraints, 0, 9, 7, 1); ------------------------------------------ 5. Adding text fields and labels for registers ------------------------------------------ for (int i = 0; i < 10; i++) { regLabels[i] = new JLabel("r" + i); regTexts[i] = new JTextField(25); regTexts[i].setEditable(true); regTexts[i].setHorizontalAlignment(JTextField.RIGHT); Border rb = BorderFactory.createLineBorder(Color.BLACK); regTexts[i].setBorder(rb); } for (int i = 0; i < 10; i = i + 2) { constraints.anchor = GridBagConstraints.EAST; int row = 4+i/2; add(regLabels[i], constraints, 0, row, 1, 1); add(regLabels[i+1], constraints, 4, row, 1, 1); constraints.anchor = GridBagConstraints.WEST; constraints.fill = GridBagConstraints.NONE; add(regTexts[i], constraints, 1, row, 2, 1); add(regTexts[i+1], constraints, 5, row, 2, 1); } ------------------------------------------ 6. Adding listeners for the text fields ------------------------------------------ package gui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.JTextField; import calc.Registers; /** Listener for the registers. * These keep track of a textfield and a register number, * and they put the contents of the text field into the register. * @author Gary T. Leavens */ public class RegisterInputListener implements FocusListener, ActionListener { /** The text field we listen to. */ private JTextField tf; /** The register we put the input into. */ private int regNum; /** * Initialize this RegisterInputListener to listen to events * on the given JTextField and output to the given register. * @param tf the text field * @param regNum the number of the register */ //@ requires tf != null && 0 <= regNum; public RegisterInputListener(JTextField tf, int regNum) { this.tf = tf; this.regNum = regNum; } /** Done when the user moves focus away. */ public void focusLost(FocusEvent e) { Registers.put(regNum, parseDoubleFrom(tf)); } /** Done when the user types the enter key. */ public void actionPerformed(ActionEvent e) { Registers.put(regNum, parseDoubleFrom(tf)); } /** Parse a Double from the given JTextField */ private double parseDoubleFrom(JTextField t) { try { return Double.parseDouble(t.getText().trim()); } catch (NumberFormatException e) { return Double.NaN; } } /** What is done when focus is gained. */ public void focusGained(FocusEvent e) { } } ------------------------------------------ ------------------------------------------ for (int i = 0; i < 10; i++) { /* ... */ regTexts[i] = new JTextField(25); /* ... */ // Add Listener for events on this text field RegisterInputListener ril = new RegisterInputListener(regTexts[i], i); regTexts[i].addActionListener(ril); regTexts[i].addFocusListener(ril); } ------------------------------------------ 7. Code cleanup