Peter Andreae Computer Science Victoria University of Wellington Copyright: Peter Andreae, Victoria University of Wellington Raw GUIs, ArrayLists Inheritance COMP 102 # T1
© Peter Andreae COMP :2 Outline "Raw" Gui's ArrayLists Inheritance BouncingShape with an Interface class BouncingShape with inheritance Administrivia: Thursday’s lecture will talk about the exam
© Peter Andreae COMP :3 MiniDraw: test classes Rectangle.java, Oval.java, Dot.java all have a test classes. You can run the main method in these classes to test your code for the class before you use it from MiniDraw. This is a kind of "unit test", which is very helpful for large programs. The test methods provided are not exhaustive, and passing the test method does not guarantee that your code is right!
© Peter Andreae COMP :4 Making a GUI without the UI Text input and output: use System.out and a Scanner around System.in: connected to the terminal window (or standard output and input) use print, println, etc next, nextInt, etc, but no ask… Scanner inpSc = new Scanner(System.in); System.out.print("Enter age and name: "); int age = inpSc.nextInt(); String name = inpSc.next();
© Peter Andreae COMP :5 GUI without UI: set up window Buttons, mouse, etc: construct window, panel, buttons, etc. public class StandardInterface implements ActionListener, MouseListener{ private JFrame frame;private JTextArea textPane; private JTextField inputField; public StandardInterface(){ frame = new JFrame("Eg GUI");frame.setSize(400, 600); textPane = new JTextArea(); textPane.addMouseListener(this); frame.add(textPane, BorderLayout.CENTER); JPanel panel = new JPanel(); frame.add(panel, BorderLayout.NORTH); JButton helloButton = new JButton("Hello"); helloButton.addActionListener(this);panel.add(helloButton); panel.add(new JLabel("number to double:")); inputField = new JTextField(5);panel.add(inputField); JButton calcButton = new JButton("Double"); calcButton.addActionListener(this);panel.add(calcButton); JButton quitButton = new JButton("Quit"); quitButton.addActionListener(this);panel.add(quitButton); frame.setVisible(true); }
© Peter Andreae COMP :6 GUI without UI: respond to buttons ActionPerformed is passed an ActionEvent: public void actionPerformed(ActionEvent e){ if (e.getActionCommand().equals("Hello") ){ textPane.append("Hello there,\nThis is a doubling calculator"); } else if (e.getActionCommand().equals("Double") ){ if (!inputField.getText().equals("")){ doubleNums(Integer.parseInt(inputField.getText())); } else { textPane.append("\n\n******\nEnter a number first\n******\n"); } else if (e.getActionCommand().equals("Quit") ){ frame.dispose(); }
© Peter Andreae COMP :7 GUI without UI: respond to mouse MouseListeners have six methods, passed a MouseEvent public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) { int x =e.getX(); int y =e.getY(); textPane.setText(""); textPane.append(String.format("Mouse at (%3d,%3d)\n", x, y )); } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {}
© Peter Andreae COMP :8 ArrayList Using arrays for lists of things: private static final int maxStudents = 1000; private Student[ ] students = new Student[maxStudents]; private int count = 0; What are the problems with using arrays this way? fixed size: may run out of space may waste lots of memory “just in case”. have to keep the array and the count in step hard to pass them around easy to get the count wrong can’t use the nice foreach loop: for ( Student s : students){ ……
© Peter Andreae COMP :9 Solution: ArrayList Part of the Java Collections framework. predefined class Stores a list of items, “list” = collection of items kept in a particular order. part of the java.util package ⇒ need import java.util.*; at head of file You can make an new ArrayList object, and put items in it Don’t have to specify its size Like an infinitely stretchable array Should specify the type of items. new syntax: “type parameters” or “generics” But, you have to call methods on it; you can’t use the […] notation. More in COMP103 on ArrayList and other Collection types
© Peter Andreae COMP :10 Using ArrayList: declaring List of students Array: private static final int maxStudents = 1000; private Student[ ] students = new Student[maxStudents]; private int count = 0; ArrayList: private ArrayList students = new ArrayList (); The type of values in the list is between “ ” after ArrayList. No maximum; no initial size; no explicit count Note: may not use this for MiniDraw!!
© Peter Andreae COMP :11 Using ArrayList: methods ArrayList has many methods! Most important: size():returns the number of items in the list add(item ):adds an item to the end of the list add(index, item ):inserts an item at index (moves later items up) set(index, item ):replaces the item at index with item contains(item ):true if the list contains an item that equals item get(index ):returns the item at position index remove(item ):removes an occurrence of item remove(index ):removes the item at position index (both move later items down) You can use the “for each” loop on an array list, as well as a for loop
© Peter Andreae COMP :12 Using ArrayList: using private ArrayList students = new ArrayList (); : students.add(new Student( , “Jane”, “Doe”)); while (scan.hasNext()){ Student s = new Student(scan); students.add(s); } Student lastStudent = students.get(students.size()-1); System.out.println(students.get(0) + “to” + lastStudent); for (Student st : students){ System.out.println(st); } for (int i = 0; i < students.size(); i += 10){ System.out.println(students.get(i)); }
© Peter Andreae COMP :13 How does ArrayList work? It uses an array and a count! just as you are doing for ShapeList When the array gets full, it makes new array, double the size copies the items over from the old array throws away the old array and keeps the new one. It turns out that this is very efficient! For lists of items, use ArrayList instead of arrays. (except not in MiniDraw) COMP 103 will look at this in more detail, and other kinds of collections, and other ways of implementing collections. data: count:
© Peter Andreae COMP :14 Inheritance Interfaces allow a variable to contain different subtypes The interface specifies the methods that the subtypes can perform The interface does not provide any code. Inheritance = Interface PLUS shared code. specifies what the subtypes can do provides method definitions and fields that the subtype automatically reuses. Inheritance allows “Special Cases” Shape Oval Rect Triangle
© Peter Andreae COMP :15 Bouncing Shapes ScreenSaver Consists of a collection of shapes: Move around the screen (speeding up as they go) When hit a wall, slow down and bounce off again. Each kind of shape is animated in a different way as it goes.
© Peter Andreae COMP :16 Bouncing Shapes ScreenSaver Design is a bit like BalloonGame ++ ScreenSaver has a list of BShapes Each cycle, it calls step() on each shape then calls draw(canvas) Each BShape keeps track of its position At each step, moves, and changes its speed (gradually speeds up, until hits edge) Each kind of BShape also has some other state which changes on each step: BRect changes colour, BOval changes shape, Butterfly flaps BShape BOval BRect Butterfly ScreenSaver list of BShapes
© Peter Andreae COMP :17 Bouncing Shapes public class ScreenSaver { public static final int Top = 10, Bot = 600, Left = 10, Right = 600; : public ScreenSaver(){ // set up the user interface } public void animate(){ ArrayList shapes = new ArrayList (); shapes.add(new BRect(500, 100)); shapes.add(new BOval(100, 200)); ….. while (true){ UI.clear(false); for (BShape shape : shapes){ shape.step(); shape.draw(); } UI.display(); } Using ArrayList of BShape instead of Array of BShape & count
© Peter Andreae COMP :18 BShape Interface, specifying what a BShape must be able to do. public interface BShape{ public void step(); public void draw(); } BShape BOval BRect Butterfly ScreenSaver list of BShapes
© Peter Andreae COMP :19 BRect Must have fields for state, and constructor: public class BRect implements BShape{ private double x; // position private double y; private double dx; // step size private double dy; private int size = 20; private int red; // current colour private int green; private int blue; /** Construct a new BRect */ public BRect(double x, double y){ x = x; dx = Math.random()-0.5; y = y; dy = Math.random()-0.5; red = (int)(Math.random()*255); ….. } BShape BOval BRect Butterfly ScreenSaver list of BShapes
© Peter Andreae COMP :20 BRect: step and draw methods public void draw(){ UI.setColor(new Color(red, green, blue)); UI.fillRect( x, y, size, size, false); } public void step(){ // change position and check boundary x = x + dx; y = y + dy; if (x < Left){ x =Left;dx = - dx/10;dy = dy/10; } else if (x > Right){ x =Right;dx = - dx/10;dy = dy/10; } if (y < Top ){ y =.Top;dx = dx/10;dy = - dy/10; } else if (y > Bot){ y =Bot;dx = dx/10;dy = - dy/10; } //increase speed dx = dx *( *Math.random()); dy = dy *( *Math.random()); // change the colour red = (red+1) % 255; blue = (blue+1) % 255; green= (green+1) % 255; }
© Peter Andreae COMP :21 BOval Must have fields for state, and constructor: public class BOval implements BShape{ private double x;// position private double y; private double dx;// step size private double dy; private int wd; // current shape private int ht; private int shapeChange; private Colour col;// colour /** Construct a new BOval */ public BOval(double x, double y){ x = x; dx = Math.random()-0.5; ….. } Same as BRect BShape BOval BRect Butterfly ScreenSaver list of BShapes
© Peter Andreae COMP :22 BOval public void draw(){ UI.setColor(col); UI.fillOval( x, y, wd, ht, false); } public void step(){ // change position and check boundary x = x + dx; y = y + dy; if (x < Left){ x =Left;dx = - dx/10;dy = dy/10; } else if (x > Right){ x =Right;dx = - dx/10;dy = dy/10; } if (y < Top ){ y =.Top;dx = dx/10;dy = - dy/10; } else if (y > Bot){ y =Bot;dx = dx/10;dy = - dy/10; } //increase speed dx = dx *( *Math.random()); dy = dy *( *Math.random()); // change the shape wd = wd + shapeChange; ht = ht - shapeChange; if (wd <1 || ht < 1) shapeChange = - shapeChange; } Same as BRect
© Peter Andreae COMP :23 Duplicated Code Is a pain you have to copy and paste it Leads to errors change in one place, but not the others changing takes a long time may be hard to find all the places It would be nice to put the shared code somewhere. The movement component of step is common to all the BShapes ⇒ extract the movement bit out of step() into a move() method: put move() somewhere, just once the fields (x, y, dx, dy) are common to all the BShapes ⇒ put the fields in one place. Where?
© Peter Andreae COMP :24 BRect Make step() simpler: public void step(){public void step(){ move(); move(); red = (red +1) % 255; wd = wd + shapeChange; blue = (blue+1) % 255; ht = ht - shapeChange; green= (green+1) % 255; if (wd <1 || ht < 1) } shapeChange = -shapeChange; } public void move(){ // change position and check boundary x = x + dx; y = y + dy; if (x < ScreenSaver2.Left){ x =ScreenSaver2.Left;dx = - dx/10; dy = dy/10; } else if (x > ScreenSaver2.Right){ x =ScreenSaver2.Right;dx = - dx/10; dy = dy/10; } if (y < ScreenSaver2.Top ){ y =ScreenSaver2.Top;dx = dx/10;dy = - dy/10; } else if (y > ScreenSaver2.Bot){ y =ScreenSaver2.Bot;dx = dx/10;dy = - dy/10; } //increase speed dx = dx *( *Math.random()); dy = dy *( *Math.random()); } Still need copies of move() in every shape class
© Peter Andreae COMP :25 Code shared by the subtypes Put the code in BShape: public interface BShape{ private double x; private double y; private double dx; private double dy; public void step(); public void draw(); public void move(){ x = x + dx; y = y + dy; if (x < ScreenSaver2.Left){ x =ScreenSaver2.Left;dx = - dx/10; dy = dy/10; } else if (x > ScreenSaver2.Right){ x =ScreenSaver2.Right;dx = - dx/10; dy = dy/10; } if (y < ScreenSaver2.Top ){ y =ScreenSaver2.Top;dx = dx/10; dy = - dy/10; } else if (y > ScreenSaver2.Bot){ y =ScreenSaver2.Bot;dx = dx/10; dy = - dy/10; } //increase speed dx = dx *( *Math.random()); dy = dy *( *Math.random()); } Can’t put fields or method definitions in an interface! Can ’ t do this! Can ’ t put definitions of methods in an interface Can ’ t do this! Can ’ t put fields in an interface
© Peter Andreae COMP :26 Code shared by the subtypes Make BShape be a class: public class BShape{ public double x; public double y; public double dx; public double dy; public void step(); public void draw(); public void move(){ x = x + dx; y = y + dy; if (x < ScreenSaver2.Left){ x =ScreenSaver2.Left;dx = - dx/10;dy = dy/10; } else if (x > ScreenSaver2.Right){ x =ScreenSaver2.Right;dx = - dx/10;dy = dy/10; } if (y < ScreenSaver2.Top ){ y =ScreenSaver2.Top;dx = dx/10;dy = - dy/10; } else if (y > ScreenSaver2.Bot){ y =ScreenSaver2.Bot;dx = dx/10;dy = - dy/10; } //increase speed dx = dx *( *Math.random()); dy = dy *( *Math.random()); } Must have bodies for all methods in a class Can ’ t do this! Must have bodies for methods in a class
© Peter Andreae COMP :27 Code shared by the subtypes Make BShape be a class: public class BShape{ public double x; public double y; public double dx; public double dy; public void step(){ move(); } public void draw(){ } public void move(){ x = x + dx; y = y + dy; if (x < ScreenSaver2.Left){ x =ScreenSaver2.Left; dx = - dx/10;dy = dy/10; } else ….. dx = dx *( *Math.random()); dy = dy *( *Math.random()); } But how can BRect and BOval be BShapes? Note! Fields have to be accessible to the subclasses (protected would be better)
© Peter Andreae COMP :28 Inheritance Interfaces specify just types Classes specify types specify object descriptions (fields) specify object behaviour (methods) We want all three: Declare BOval and BRect (etc) to be subclasses of BShape ⇒ are of the BShape type AND ⇒ share the BShape object descriptions (fields) AND ⇒ share the BShape methods.
© Peter Andreae COMP :29 BRect public class BRect extends BShape{ private int size = 20; private int red; private int green; private int blue; public BRect(double x, double y){ // must have own constructor x = x; dx = Math.random()-0.5; y = y; dy = Math.random()-0.5; red = (int)(Math.random()*255); ….. } public void draw(){ UI.setColor(new Color(red, green, blue)); UI.fillRect(x, y, size, size,false); } public void step(){ move(); red = (red+1) % 255; blue = (blue+1) % 255; green= (green+1) % 255; } BRect -44 x: y: dx: dy: size: red: green: blue: inherited from BShape overrides BShape ’ s step method overrides BShape ’ s draw method
© Peter Andreae COMP :30 Inheritance Inheritance = Interface PLUS shared code. superclass specifies a type: can have a variable of the supertype containing a value of any of the subtypes superclass provides method definitions and fields that the subclasses automatically reuse subclasses can override superclass: provide their own definition of methods defined in the superclass Inheritance allows “Special Cases” BShape BOval BRect Butterfly
© Peter Andreae COMP :31 Visibility specifiers private: scope of field or method (or class...) is this class only ⇒ only methods in this class can refer to it. can apply to fields and methods (and more) good practice: non-static (ordinary) fields are almost always private methods should be private if they are “helper” methods public: scope of field or name (etc) is the whole program good practice: methods essential for using an object should be public static final fields (ie, constants) may be public if relevant to rest of program no specifier: intermediate case, scope = package protected: special case, scope = package & subclasses
© Peter Andreae COMP :32 Public or Private? The principle of encapsulation says “Keep it private unless it needs to be public” ⇒ less chance of errors ⇒ easier to change this module later without affecting rest of program Keep fields private except for some static final fields (ie constants) except fields accessible to subclasses: ⇒ protected Provide public “getter & setter” methods if necessary: private int size; public int getSize(){ return size; } public void setSize(int s) { size = s; } Make “external” methods public; Make “helper” methods private