I/O in AP Java Enjoyable, Meaningful, NonDistracting I/O in AP Java Ken Lambert, Washington and Lee University Martin Osborne, Western Washington University Copyright 2002 Free Supplemental Materials www.cs.wwu.edu/martin Slides for this talk Software packages – TerminalIO – TurtleGraphics – BreezySwing Languages for Introductory Programming Fortran (60's) PL/1 (70's) Pascal and Modula (80's) C++ (90's) Java (2000 and beyond) Why Java? Pascal a teaching language C++ a developer's language Java a bit of both – For teaching • Smaller, simpler syntax than C++ – For developer's • Safe, portable, vast supporting libraries C++ I/O Stream I/O – – – – – Simple, flexible Supports both terminal and files cin, cout for console Stream objects for files Suitable for introductory course GUI's – Platform dependent – Complex – Not suitable for introductory course Java I/O Stream I/O – Moderately difficult – Several simple patterns cover basic situations – Somewhat suitable for introductory course GUIs – Platform independent – Complex • but several complex patterns cover basic situations – Doable but not really suitable for introductory course AP I/O Requirements Terminal output with System.out Package supported stream input – Basic read functions for intrinsic data types Advantage of AP Approach Leaves more time for everything else Including some I/O that is – Enjoyable – Meaningful – Non-distracting Most Basic Program Structure import …; public class <ProgramName> { public static void main(String [] args) { … statements… } } Console Applications Temperature Conversion User Interface Enter degrees Fahrenheit: 212 The equivalent in Celsius is 100.0 Implementation import TerminalIO.KeyboardReader; public class Convert { public static void main(String [] args) { double fahrenheit; double celsius; KeyboardReader reader = new KeyboardReader(); fahrenheit = reader.readDouble("Enter degrees Fahrenheit: "); celsius = (fahrenheit - 32.0) * 5.0 / 9.0; System.out.println("The equivalent in Celsius is " + celsius); } } Menu Driven Conversion 1) Convert from Fahrenheit to Celsius 2) Convert from Celsius to Fahrenheit 3) Quit Enter your option: 1 Enter degrees Fahrenheit: 212 Degrees Celsius = 100.0 1) Convert from Fahrenheit to Celsius 2) Convert from Celsius to Fahrenheit 3) Quit Enter your option: 2 Etc… Implementation (1 of 2) import TerminalIO.*; public class ConvertWithMenu { public static void main (String [] args) { KeyboardReader reader = new KeyboardReader(); double fahrenheit, celsius; String menu; //The multiline menu int menuOption; //The user's menu selection menu = "\n1) Convert from Fahrenheit to Celsius" + "\n2) Convert from Celsius to Fahrenheit" + "\n3) Quit" + "\nEnter your option: "; Implementation (2 of 2) do { menuOption = reader.readInt(menu); System.out.println (""); if (menuOption == 1){ fahrenheit = reader.readDouble("Enter degrees Fahrenheit: "); celsius = (fahrenheit - 32.0) * 5.0 / 9.0; System.out.println ("Degrees Celsius = " + celsius); }else if (menuOption == 2){ celsius = reader.readDouble("Enter degrees Celsius: "); fahrenheit = celsius * 9.0 / 5.0 + 32.0; System.out.println ("Degrees Fahrenheit = " + fahrenheit); }else if (menuOption != 3){ System.out.println ("Invalid option"); } } while (menuOption != 3); } } Formatted Output The The The The The The The The The The number number number number number number number number number number with with with with with with with with with with precision precision precision precision precision precision precision precision precision precision 0: 1 1: 1.2 2: 1.23 3: 1.235 4: 1.2346 5: 1.23456 6: 1.234560 7: 1.2345600 8:1.23456000 9:********** Implementation import BreezySwing.Format; public class TerminalFormatDemo { public static void main (String [] args) { double number = 1.23456; for (int i = 0; i <= 9; i++){ String str = "The number with precision " + i + ":" + Format.justify ('r', number, 10, i); System.out.println (str); } } } Temperature Conversion Revisited User Interface Enter degrees Fahrenheit: 212 The equivalent in Celsius is 100.0 Native Implementation (1 of 2) import java.io.*; public class Convert{ public static void main (String[] args){ … try{ InputStreamReader reader = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(reader); … = Double.parseDouble(buffer.readLine()); … = Integer.parseInt(buffer.readLine()); … }catch(Exception e){ System.err.println("Input error -- " + e.toString()); } } } Native Implementation (2 of 2) import java.io.*; public class Convert{ public static void main (String[] args){ double fahrenheit; double celsius; try{ InputStreamReader reader = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(reader); System.out.print("Enter degrees Fahrenheit: "); fahrenheit = Double.parseDouble(buffer.readLine()); celsius = (fahrenheit - 32.0) * 5.0 / 9.0; System.out.println("The equivalent in Celsius is " + celsius); }catch(Exception e){ System.err.println("Input error -- " + e.toString()); } } } Factoring Out the Complexity with a static method (1 of 2) import java.io.*; public class Convert2{ public static void main (String[] args){ double fahrenheit; double celsius; fahrenheit = readDouble("Engter degrees Fahrehheit: "); celsius = (fahrenheit - 32.0) * 5.0 / 9.0; System.out.println("The equivalent in Celsius is " + celsius); } Factoring Out the Complexity with a static method (2 of 2) public static double readDouble(String prompt){ double theNumber; try{ InputStreamReader reader = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(reader); System.out.print(prompt); theNumber = Double.parseDouble(buffer.readLine()); return theNumber; }catch(Exception e){ System.err.println("Input error -- " + e.toString()); return 0; } } } Factoring Out the Complexity with a supporting class (1 of 2) public class Convert3 { public static void main(String [] args) { double fahrenheit; double celsius; KeyboardReader reader = new KeyboardReader(); fahrenheit = reader.readDouble("Enter degrees Fahrenheit: "); celsius = (fahrenheit - 32.0) * 5.0 / 9.0; System.out.println("The equivalent in Celsius is " + celsius); } } Factoring Out the Complexity with a supporting class (2 of 2) import java.io.*; public class KeyboardReader{ public double readDouble(String prompt){ double theNumber; try{ InputStreamReader reader = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(reader); System.out.print(prompt); theNumber = Double.parseDouble(buffer.readLine()); return theNumber; }catch(Exception e){ System.err.println("Input error -- " + e.toString()); return 0; } } } Illustrating Concepts with Turtle Graphics Draw a Square Instantiating and sending messages to an object import TurtleGraphics.StandardPen; public class DrawSquare { public static void main (String [] args) { Implementation // Instantiate a pen object StandardPen pen = new StandardPen(); // Lift the pen, move it to the square's top left corner, // and lower it again pen.up(); pen.move(25); pen.turn(90); pen.move(25); pen.down(); // Draw the square pen.turn(90); pen.move(50); pen.turn(90); pen.move(50); pen.turn(90); pen.move(50); pen.turn(90); pen.move(50); } } Draw a 100-gon Using for-statements Implementation import TurtleGraphics.StandardPen; public class Draw100gon { public static void main (String [] args) { int i; StandardPen pen = new StandardPen(); // Lift, move to top of circle, lower pen.up(); pen.move(25); pen.turn(90); pen.move(0.8); pen.down(); // Draw the 100gon for (i = 1; i <= 100; i++){ pen.turn(3.6); pen.move(1.6); } } } Smiley Face User defined classes Outline of Class public class SmilingFace { public SmilingFace(){...} public SmilingFace(double x, double y){...} public void draw(){ public void erase(){ public void move(double x, double y){...} private void drawCircle(double x, double y, double r){...} private void drawLine(double x1, double y1, double x2, double y2){...} private StandardPen pen; private double xPosition, yPosition; } import TurtleGraphics.*; import TerminalIO.*; public class TestSmilingFace { public static void main (String[] args){ KeyboardReader reader = new KeyboardReader(); double x, y, radius; Using the Class x = reader.readDouble("Initial x position: "); y = reader.readDouble("Initial y position: "); SmilingFace face = new SmilingFace(x, y); face.draw (); while (true){ x = reader.readDouble("New x position: "); y = reader.readDouble("New y position: "); face.erase(); face.move(x, y); face.draw(); } } Implementation of Class (1 of 4) import TurtleGraphics.*; import java.awt.Color; public class SmilingFace { private StandardPen pen; private double xPosition, yPosition; public SmilingFace(){ xPosition = 0; yPosition = 0; pen = new StandardPen(); pen.setColor(Color.red); } public SmilingFace(double x, double y){ this(); xPosition = x; yPosition = y; } Implementation of Class (2 of 4) public void erase(){ pen.setColor(Color.white); draw(); pen.setColor(Color.red); } public void move(double x, double y){ xPosition = x; yPosition = y; } public void draw(){ double radius = 50.0; Implementation of Class (3 of 4) // Draw the outline of the face drawCircle(xPosition, yPosition, radius); // Draw the left and right eye. drawCircle(xPosition - radius / 2.5, yPosition + radius / 3, radius / 4); drawCircle(xPosition + radius / 2.5, yPosition + radius / 3, radius / 4); // Draw the horizontal part of the mouth drawLine(xPosition - radius / 3, yPosition - radius / 2, xPosition + radius / 3, yPosition - radius / 2); // Draw the left and right smile line drawLine(xPosition - radius / 3 , yPosition - radius / 2, xPosition - radius / 3 - 5, yPosition - radius / 2 + 5); drawLine(xPosition + radius / 3 , yPosition - radius / 2, xPosition + radius / 3 + 5, yPosition - radius / 2 + 5); } Implementation of Class (4 of 4) private void drawCircle(double x, double y, double r){ double side = 2.0 * Math.PI * r / 120.0; pen.up(); pen.move(x + r, y - side / 2.0); pen.setDirection(90); pen.down(); for (int i = 0; i < 120; i++){ pen.move(side); pen.turn(3); } } private void drawLine(double x1, double y1, double x2, double y2){ pen.up(); pen.move(x1, y1); pen.down(); pen.move(x2, y2); } } Fractals Recursion Implementation (1 of 2) import java.awt.Color; import TurtleGraphics.*; public class Recursion { public static void main (String [] args) { Pen pen = new StandardPen(); pen.setWidth(1); for (int i = 1; i <= 6; i++){ pen.up(); pen.move(-100, 245 - 70 * i); pen.down(); pen.setDirection(0); drawFractal(i, pen, 200); } } Implementation (2 of 2) private static void drawFractal(int depth, Pen pen, double length){ if (depth <= 1) pen.move(length); else{ drawFractal(depth - 1, pen, length / 3); pen.turn(60); drawFractal(depth - 1, pen, length / 3); pen.turn(-120); drawFractal(depth - 1, pen, length / 3); pen.turn(60); drawFractal(depth - 1, pen, length / 3); } } } Drawing in Applets import java.applet.Applet; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; Implementation public class Shapes extends Applet{ public void paint(Graphics g){ Graphics2D g2 = (Graphics2D)g; Rectangle rectangle = new Rectangle(50, 50, 100, 50); Ellipse2D.Double ellipse = new Ellipse2D.Double(50, 50, 100, 50); Point2D.Double point1 = new Point2D.Double(50, 50); Point2D.Double point2 = new Point2D.Double(150, 100); Line2D.Double line = new Line2D.Double(point1, point2); g2.draw(rectangle); g2.draw(ellipse); g2.draw(line); } } GUIs A Simple GUI Breezy Implementation (1 of 4) import javax.swing.*; import BreezySwing.*; public class ConvertWithGUI extends GBFrame{ private JLabel private JLabel private DoubleField private DoubleField private JButton private JButton fahrenheitLabel; celsiusLabel; fahrenheitField; celsiusField; fahrenheitButton; celsiusButton; Breezy Implementation (2 of 4) public ConvertWithGUI(){ fahrenheitLabel = addLabel ("Fahrenheit" ,1,1,1,1); celsiusLabel = addLabel ("Celsius" ,1,2,1,1); fahrenheitField = addDoubleField (32.0 ,2,1,1,1); celsiusField = addDoubleField (0.0 ,2,2,1,1); fahrenheitButton = addButton (">>>>>>" ,3,1,1,1); celsiusButton = addButton ("<<<<<<" ,3,2,1,1); } Breezy Implementation (3 of 4) public void buttonClicked (JButton buttonObj){ double fahrenheit, celsius; if (buttonObj == fahrenheitButton){ fahrenheit = fahrenheitField.getNumber(); celsius = (fahrenheit - 32.0) * 5.0 / 9.0; celsiusField.setNumber (celsius); }else{ celsius = celsiusField.getNumber(); fahrenheit = celsius * 9.0 / 5.0 + 32.0; fahrenheitField.setNumber (fahrenheit); } } Breezy Implementation (4 of 4) public static void main (String[] args){ ConvertWithGUI theGUI = new ConvertWithGUI(); theGUI.setSize (250, 100); theGUI.setVisible (true); } Native Implementation (1 of 6) import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ConversionWithSwing extends JFrame{ private JLabel fahrenheitLabel; private JTextField fahrenheitField; private JLabel celsiusLabel; private JTextField celsiusField; private JButton fahrenheitButton; private JButton celsiusButton; Native Implementation (2 of 6) public ConversionWithSwing(){ fahrenheitLabel = new JLabel ("Fahrenheit"); celsiusLabel = new JLabel ("Celsius"); fahrenheitField = new JTextField ("212", 6); // 6 columns wide celsiusField = new JTextField ("100", 6); // 6 columns wide fahrenheitButton = new JButton (">>>>>>"); celsiusButton = new JButton ("<<<<<<"); Native Implementation (3 of 6) Container contentPane = getContentPane(); contentPane.setLayout (new FlowLayout()); contentPane.add (fahrenheitLabel); contentPane.add (celsiusLabel); contentPane.add (fahrenheitField); contentPane.add (celsiusField); contentPane.add (fahrenheitButton); contentPane.add (celsiusButton); fahrenheitButton.addActionListener(new MyActionListener()); celsiusButton.addActionListener(new MyActionListener()); addWindowListener(new MyWindowAdapter()); } Native Implementation (4 of 6) public static void main (String[] args){ ConversionWithSwing theGUI = new ConversionWithSwing(); theGUI.setSize (200, 125); theGUI.setVisible (true); } Native Implementation (5 of 6) private class MyActionListener implements ActionListener{ public void actionPerformed (ActionEvent event){ double fahrenheit, celsius; String str; Object source = event.getSource(); if (source == fahrenheitButton){ str = fahrenheitField.getText().trim(); fahrenheit = Double.parseDouble(str); celsius = (fahrenheit - 32) * 5 / 9; celsiusField.setText ("" + celsius); }else{ str = celsiusField.getText().trim(); celsius = Double.parseDouble(str); fahrenheit = celsius * 9 / 5 + 32; fahrenheitField.setText ("" + fahrenheit); } } } Native Implementation (6 of 6) private class MyWindowAdapter extends WindowAdapter{ public void windowClosing (WindowEvent e){ System.exit(0); } } } Drawback of Flow Layout Fields move around when window resized Solution – use a gridbag layout – Unfortunately, considerably more complex Summary AP Java has minimal I/O requirements Take advantage of this to – Have fun and – Add interest While – providing useful skills and – Avoiding unnecessary complexity