410 likes | 512 Views
Intro to SWING. The Shape Object Painting Shapes Frames and Panels Composite Shapes Rotation Animation Window wrap-around. A Long Long Time Ago….
E N D
Intro to SWING • The Shape Object • Painting Shapes • Frames and Panels • Composite Shapes • Rotation • Animation • Window wrap-around Intro to Graphics
A Long Long Time Ago… • Sun provided the Abstract Window Toolkit (AWT), a collection of classes (java files) that make displaying graphics easy for the programmer • object-oriented • reusable and extensible • but, AWT is very complex… • for our course, relies too much on low-level processing • Sun then released Swing on top of AWT • new and improved! • easier to use and more powerful! • some AWT classes are still in use… • java.awt.Color • java.awt.Dimension • java.awt.Shape • and more… Intro to Graphics
Let’s talk about shapes • What is a Shape? • it is an Object, just like everything else in Java • So it must have attributes… • size • location • border color • fill color • rotation angle • And capabilities… • all attributes can change (mutators) • can draw itself • more to come later… • mouse interaction • animation • window wrap-around • How to keep track of the attributes? Intro to Graphics
RectangularShape • Use AWT’s utility classes to store geometric information about a shape: • java.awt.geom.RectangularShape • Class is abstract - use subclasses in practice • all subclasses can be bound by a rectangular bounding box: • java.awt.geom.Rectangle2D.Double • java.awt.geom.RoundRectangle2D.Double • java.awt.geom.Ellipse2D.Double • java.awt.geom.Arc2D.Double • Define your own shape class • contains a RectangularShape for geometric data • these store Locations and Dimensions • Other instance variables provide additional data • colors, rotation angle Size Location Intro to Graphics
ColorShape public abstract class ColorShape { private java.awt.geom.RectangularShape _shape; public ColorShape (java.awt.geom.RectangularShape s) { _shape = s; } //accessors/mutators and other //attributes to follow.. } • Our shape contains a RectangularShape Intro to Graphics
(40, 40) Y X X bounding box location of shape shape Location/Dimension • The screen is a grid of pixels(tiny dots) • “picture elements” • Unlike a Cartesian plane! • the origin is in the upper-left corner • the y-axis increases downward • The location of any shape is described by the upper-left corner of it’s bounding box Y (0, 0) Pixel Art Intro to Graphics
RectangularShape – Mutators/Accessors • To set location and size: _shape.setFrame(xLoc, yLoc, width, height); • use this method to initialize and reset location and size on a RectangularShape • To get geometric data: _shape.getX(); _shape.getY(); _shape.getWidth(); _shape.getHeight(); Intro to Graphics
ColorShape class Accessors/Mutators • Accessors to make RectangularShape data available to external classes: public double getX(){ return _shape.getX(); } • Create mutators so external classes can change location and size independently: public void setLocation (double x, double y){ // Change only x and y, preserve the width and height _shape.setFrame(x, y, _shape.getWidth(), _shape.getHeight()); } public void setSize (double w, double h) { // Change only the width and height, preserve the x and y coordinates _shape.setFrame(_shape.getX(), _shape.getY(), w, h); } Intro to Graphics
Storing Color • additional data in Instance Variables • Use accessors/mutators: public void setFillColor(java.awt.Color c){ _fillColor = c; } public java.awt.Color getFillColor(){ return _fillColor; } • Ditto for border color • Or use one method to change both fill and border color at once: public void setColor(java.awt.Color c){ _fillColor = c; _borderColor = c; } Intro to Graphics
Red Green Blue Alpha Value new java.awt.Color(239, 174, 45, 200) Color • java.awt.Color stores color • RGB format • Colors are determined by concentrations of Red, Green and Blue • each is given a value between 0-255 • how many combinations are there? • 16,777,216 • Basic colors come preset • Colors can be • specify the alpha value [0-255]… • 0 = completely transparent • new • java.awt.Color(0, 255, 0) (255, 0, 0) = (0, 255, 0) = (0, 0, 255) = (200, 0, 200)= java.awt.Color.green java.awt.Color.orange java.awt.Color.gray transparent Intro to Graphics
ColorShape again! public abstract class ColorShape { private java.awt.geom.RectangularShape _shape; private java.awt.Color _borderColor, _fillColor; public ColorShape (java.awt.geom.RectangularShape s) { _shape = s; // initialize attributes… this.setLocation(50, 50); this.setSize(100, 100); this.setBorderColor (java.awt.Color.black); this.setFillColor(java.awt.Color.blue); } // accessors/mutators } Intro to Graphics
Painting Shapes • Now we know what our ColorShape is… • a collection of data (geometric and non-geometric) • How do we paint it on the screen? • Shapes will have a paint method, to paint themselves • Nothing can paint without a paintbrush! Intro to Graphics
Graphics • Our brush is brilliantly named a “Graphics” • thanks, Java designers! • Actually, use Graphics2D – Its more powerful subclass • Think of it as a parameterized brush • Each time ColorShapepaints itself, it… • sets the colorof the brush brush.setColor(_borderColor); • tells brush to draw outline of a geometric shape brush.draw(_shape); • sets the color of the brush brush.setColor(_fillColor); • tells brush to fill geometric shape brush.fill(_shape); Intro to Graphics
ColorSubclass • ColorShape is abstract… • what should the subclass do? • ColorShape takes a RectangularShape in constructor • pass in subclass of RectangularShape • Like so… public class ColorRectangle extends ColorShape { public ColorRectangle () { super(new java.awt.geom.Rectangle2D.Double()); } } • Same for other RectangularShapes • except for Arc2D… • see book for details Intro to Graphics
Frames • Most Swing applications start with a Frame • it’s actually called a javax.swing.JFrame • J is for Java • public class App extends javax.swing.JFrame • { • public App() { • super(“xterm”); • this.setSize(500, 450); //size varies • this.setDefaultCloseOperation( • EXIT_ON_CLOSE); • //add code for top-level object • this.setVisible(true); • } • public static void main(String[] argv) { • App app = new App(); • } • } • When you draw graphics, you always need to • draw onto some kind of container • - a frame, like the one above, holds containers… Fvwm (Sunlab) Frame Microsoft Windows Frame Mac OS X Frame Intro to Graphics
sub-panels Panels • JFrames hold JPanels • think of a JFrame as a window frame • think of a JPanel as a window pane • Panels are the canvas for your program • in Swing, they are called javax.swing.JPanels • draw graphical shapes and GUI elements on a panel • Add panels to a frame, then add shapes and GUI elements to the panels Frame Panel Intro to Graphics
Drawing Panels • Specialized panels hold specific types of objects • some hold buttons, sliders and text boxes • some hold shapes • some hold other panels • Subclass a JPanel to specialize it • we want to specialize a JPanel to hold shapes • To paint anything on any JPanel, you must partially override its special method: paintComponent(Graphics g) • remember that a Graphics is our “brush” • won’t call this method explicitly; Java does • call paint on your shape from this method • pass the brush to your shape • there’s one small complication… • you need to pass your shape a Graphics2D • the parameter of paintComponent is a Graphics Intro to Graphics
Class Cast and Repaint • Only Cast to another variable type when ABSOLUTELY Necessary • Cast like so: public void method (GenericType g){ SpecificType sub = (SpecificType) g; } • Apply this pattern to get a Graphics2D public void paintComponent(Graphics g){ Graphics2D brush = (Graphics2D) g; //tell shape to paint itself } Intro to Graphics
PaintComponent • Whenever you want to execute the code in paintComponent(…), call repaint() on the JPanel instead _drawingPanel.repaint(); • Java calls paintComponent(…) for you and also creates the brushfor you • Let’s clarify with a little animation… Intro to Graphics
? Someone JPanel Repaint! Graphics repaint() (In JPanel) paintComponent( g) { super.paintComponent(g); Graphics2D brush = (Graphics2D) g; _rectangle.paint(brush); } Graphics2D (In Shape) paint( brush) { brush.setColor(_borderColor); brush.draw(_shape); brush.setColor(_fillColor); brush.fill(_shape); } Intro to Graphics
To the Drawing Panel! • Add a rectangle to a Drawing Panel… public class DrawingPanel extends JPanel { private ColorRectangle _rectangle; public DrawingPanel(){ super(); this.setBackground(java.awt.Color.white); _rectangle = new ColorRectangle(); } public void paintComponent (Graphics g){ super.paintComponent(g); Graphics2D brush = (Graphics2D) g; _rectangle.paint(brush); } } • Wait! Don’t forget to set the size of the Panel this.setPreferredSize( new java.awt.Dimension(500, 500)); Intro to Graphics
Composite Shapes • If we make an ellipse subclass… public class ColorEllipse extends ColorShape { public ColorEllipse () { super(new java.awt.geom.Ellipse2D.Double()); } } • We can make a nice little alien: • We could make 3 ellipses…and strategically place them in a Drawing Panel • but, how to move alien? • have to change location of all 3 ellipses explicitly • Or, make Alien class… • alien class moves all 3 ellipses automatically • can change alien without changing Drawing panel • adding more aliens is easy! Intro to Graphics
_rtEye _ltEye _face Nice Alien • Nice Alien class contains 3 ellipses… public class NiceAlien { private ColorEllipse _face, _ltEye, _rtEye; private java.awt.Color _faceColor, _eyeColor; public NiceAlien () { //initializations, set size elided… _face.setLocation(100, 100); _ltEye.setLocation(133, 120); _rtEye.setLocation(164, 120); } public void setLocation (double x, double y) { _face.setLocation(x, y); // absolute position _ltEye.setLocation(x+33, y+20); //relative “ _rtEye.setLocation(x+64, y+20); } public void paint (Graphics2D brush){ _face.paint(brush); _ltEye.paint(brush); _rtEye.paint(brush); } } Intro to Graphics
Rotation • Rotating shapes is easy, but slightly counter-intuitive… • won’t rotate the java.awt.geom.RectangularShape • Instead, tell brush (Graphics2D) to rotate the canvas. • canvas automatically rotates in opposite direction • paint shape, then un-rotate No rotation 45˚ Rotation Final Product Intro to Graphics
Rotation • Need to store rotation angles… • degrees are easier conceptually, but Graphics2D needs radians • write accessors/mutators in degrees, store data in radians public void setRotation (double degrees) { _rotation = degrees*Math.PI/180; } public double getRotation(){ return _rotation*180/Math.PI; } • Rotate method requires: • angle of rotation (radians) • center point of shape • subclasses of RectangularShape store center point brush.rotate(_rotation, _shape.getCenterX(), _shape.getCenterY()); Intro to Graphics
Color Shape • Our new shape class can rotate… public abstract class ColorShape { private java.awt.geom.RectangularShape _shape; private java.awt.Color _borderColor, _fillColor; private double _rotation; public ColorShape (java.awt.geom.RectangularShape s) { //most of constructor elided… _rotation = 0; } public void setRotation(double degrees){ _rotation = degrees*Math.PI/180; } public double getRotation(){ return _rotation*180/Math.PI; } public void paint (Graphics2D brush){ // rotate canvas brush.rotate(_rotation, _shape.getCenterX(), _shape.getCenterY()); brush.setColor(this.getBorderColor()); brush.draw(_shape); brush.setColor(this.getFillColor()); brush.fill(_shape); // unrotate canvas brush.rotate(0-_rotation, _shape.getCenterX(), _shape.getCenterY()); } } Intro to Graphics
Evil Alien • Exactly the same as Nice Alien… public class EvilAlien { private ColorEllipse _face, _ltEye, _rtEye; private java.awt.Color _faceColor, _eyeColor; public EvilAlien () { //initializations, set dimensions elided… • But rotate the eyes! _face.setLocation(100, 100); _ltEye.setLocation(133, 120); _rtEye.setLocation(164, 120); } public void setLocation (double x, double y) { _face.setLocation(x, y); _ltEye.setLocation(x+33, y+20); _rtEye.setLocation(x+64, y+20); } public void paint (Graphics2D brush){ _face.paint(brush); _ltEye.paint(brush); _rtEye.paint(brush); } } _ltEye.setRotation(-33); _rtEye.setRotation(33); Intro to Graphics
Animation • How do we animate characters like our aliens (e.g. move across screen)? • As in film and video animation, create apparent motion with many small changes in position • If you move in fast enough increments, you get smooth motion • Same applies to size, orientation, shape change, etc… • all time-varying attributes are called “behaviors” • How to create incremental change? • we need a timer that emits “ticks” • We also need an object to listen for ticks from the timer and respond appropriatey Intro to Graphics
Event Model • Want object to respond to clock tick • Also want to model other types of behaviors • might want to respond to mouse click instead of timer tick • See how to use the mouse in the next lecture • Java generalizes such stimulus--response • actions, events, listeners • event gets generated by a source, which passes it to a listener • listener in turn sends a message to one or more responders Intro to Graphics
Event Model Continued • Four-part process: Java mechanisms: 1) stimulus 1) event breaks flow of control button press, timer tick, etc. 2) object response 2) actionPerformed the listening object’s (ActionListener’s) reaction to a stimulus listening object’s method; called in response to stimulus 3) communication method 3) ActionEventclass event record – record of what happened during stimulus data-only object; Contains information about stimulus (e.g., location of mouse click) 4) subscribing mechanism 4) ActionListener How are the responding object and stimulus connected? classes implementing this interface can listen for a specific kind of event Intro to Graphics
Animation Revisited • So, to get our aliens moving we need… • a timer • a class to listen for ticks • must implement ActionListener • must define actionPerformed(ActionEvent e) • should tell the alien to move (change location) • Can call setLocation() on alien at each tick • with absolute x, y values • Or, can give aliens a move() method • with relative x, y values – arbitrary movement • gives aliens added functionality, encapsulation • First, must know current location of alien • which ellipse determines location? • the face; simple in this case, but can be more complicated for a more complex shape • could make alien class subclass of ColorEllipse • advantages? disadvantages? • Store alien’s current location with new instance variables… Intro to Graphics
moves 3 pixels right and 2 pixels down Alien Revisited public class EvilAlien { private ColorEllipse _face, _ltEye, _rtEye; private java.awt.Color _faceColor, _eyeColor; private double _alienX, _alienY; //constructor elided //accessors and mutators elided public void setLocation (double x, double y) { _face.setLocation(x, y); _ltEye.setLocation(x+33, y+20); _rtEye.setLocation(x+64, y+20); _alienX = x; _alienY = y; } public void move(double deltaX, double deltaY){ this.setLocation(_alienX+deltaX, _alienY+deltaY); } } • Make the same additions to NiceAlien Intro to Graphics
The Design • There are many ways to setup the stimulus-response mechanisms for animation. This is our way: • The basic plan: • Create a Timer class with its own ActionListener “inner class” • Have our DrawingPanel contain this Timer • On each tick of the Timer, tell the DrawingPanel • DrawingPanel decides what should move, and then repaints itself • Let’s see what this looks like in code! Intro to Graphics
Motion Example public class DrawingPanel extends JPanel { private NiceAlien _alien1; private EvilAlien _alien2; private MyTimer _timer; public DrawingPanel (){ //part of constructor elided _timer = new MyTimer(this); _timer.start(); } /* * move is called by ActionListener’s * actionPerformed method. */ public void move() { _alien1.move(3, 2); _alien2.move(4, 5); //moves “faster” this.repaint(); } } Intro to Graphics
Motion Example (Continued) public class MyTimer extends javax.swing.Timer { private DrawingPanel _drawingPanel; public MyTimer(DrawingPanel panel) { super(100, new MyMoveListener()); _drawingPanel = panel; } /** * Private inner class, can only be used inside of * MyTimer. This is standard for listener classes in * Java. */ private class MyMoveListener implements java.awt.event.ActionListener { // This class does not need a constructor // More on this in section public void actionPerformed( java.awt.event.ActionEvent e) { _drawingPanel.move(); } } } approximate milliseconds between ticks create a new instance of aMyMoveListener, defined below ActionEvent is ignored in this case Intro to Graphics
Design Tradeoff • Why not have aliens implement ActionListener instead? • Pro Alien as “Smart Object”: • each object knows how to animate itself • object is completely self-contained • encapsulation to the MAX! • Pro Container: • container can pick which aliens move • easy to repaint after you move everything • more efficient as you add more shapes Intro to Graphics
Window wrap-around • What happens when the aliens reach the edge of the screen? • they disappear!!! Not very interesting. • Shapes should wrap around the screen: • First, we must know when the shape passes an edge… • If so, call shape’s wrap() method • this check can occur in setLocation() • wrap() recalculates shape’s location to fall within the bounds of the JPanel Intro to Graphics
Modular Arithmetic • Ifa shape is… • on a drawing panel of size 400x400 • of size 20x30 • at location (401, 150) • Where should the new location be? • location: (1, 150) • What formula would allow us to predict where the shape should be in all cases? • HINT: use the Mod (%) Operator!! Intro to Graphics
Wrap-around • Aliens must know size of Drawing Panel • new instance variable; initialize in constructor public class EvilAlien { private ColorEllipse _face, _ltEye, _rtEye; private java.awt.Color _faceColor, _eyeColor; private double _alienX, _alienY; private int _dpWidth, _dpHeight; public EvilAlien(int dpWidth, int dpHeight) { _dpWidth = dpWidth; _dpHeight = dpHeight; //rest of constructor elided } public void setLocation(double x, double y) { double newX = (x + _dpWidth) % _dpWidth; double newY = (y + _dpHeight) % _dpHeight; _face.setLocation(newX, newY);_ltEye.setLocation(newX+33, newY+20); _rtEye.setLocation(newX+64, newY+20); _alienX = newX; _alienY = newY; } } • The alien’s constructor now takes two ints • how to retrieve those from drawing panel? • know the size when creating the panel • or can call getSize() on the JPanel Intro to Graphics
Wrapping up! • You now have everything you need to produce graphics: • Shape superclass • contains all necessary information • non-geometric: instance variables • geometric: rectangularShape subclass • paints itself • with a Graphics2D brush • animates • wraps around the screen • you can subclass to make specific shapes • Drawing Panel • subclass of JPanel • can draw shapes • sits in a JFrame • User-interfaces are next! • Come back and learn • buttons • sliders • layouts • and more! Intro to Graphics