12-Painting.ppt

download 12-Painting.ppt

of 93

Transcript of 12-Painting.ppt

  • Universidad Nacional de ColombiaFacultad de IngenieraDepartamento de Sistemasertificacin enAVA

  • 12. PAINTING The paint() method and the Graphics Context The Visual Components The Container Components The Menu Components

  • Objectives Many types of AWT components (buttons and scroll bars, for example) have their appearance dictated by the underlying window system. Other component types, notably applets, frames, panels, and canvases, have no intrinsic appearance. If you use any of these classes and want your component to look at all useful, you will have to provide the code that implements thecomponent's appearance

    Java's painting mechanism provides the way for you to render your components. The mechanism is robust, and if you use it correctly you can create good, scaleable, reusable code. The best approach is to understand how Java's painting really works.

  • Objectives The fundamental concepts of painting areThe paint() method and the graphics contextThe GUI thread and the repaint() methodSpontaneous paintingPainting to images

    This chapter will take you through the steps necessary to understand and apply these concepts. And while the topics covered here are not explicitly mentioned many exam objectives, you may well find this information useful or essential

  • The paint() method and the Graphics Contextexample of the paint() method:

  • A very simple painting applet

  • One interesting point about this applet is that no calls are made to the paint() method. The method is simply provided

    The environment seems to do a good job of calling paint() at the right moment

    Exactly when the environment chooses to call paint() is the subject of "Spontaneous Painting," later in this chapter

  • Painting on a component is accomplished by making calls to a graphics context, which is an instance of the Graphics class

    A graphics context knows how to render onto a single target

    The three media a graphics context can render onto are:ComponentsImagesPrinters

  • Any kind of component can be associated with a graphics context

    The association is permanent; a context cannot be reassigned to a new component

    Although you can use graphics contexts to paint onto any kind of component, it is unusual to do so with components that already have an appearance

  • Buttons, choices, check boxes, labels, scroll bars, text fields, and text areas do not often require programmer-level rendering

    Most often, these components just use the version of paint() that they inherit from the Component superclass. This version does nothing; the components are rendered by the underlying window system

  • However, there are four classes of "blank" components that have no default appearance and will show up as empty rectangles, unless they are subclassed and given paint() methodsThese four component classes are:AppletCanvasFramePanel

  • The four major operations provided by the Graphics class are:Selecting a colorSelecting a fontDrawing and fillingClipping

  • Selecting a Color

    Colors are selected by calling the setColor() method

    The argument is an instance of the Color class

    There are 13 predefined colors, accessible as static final variables of the Color class

    The variables are themselves instances of the Color class, which makes some people uneasy, but java has no trouble with such things

  • Predefined colors Color.yellow Color.blue Color.green Color.orange Color.magenta Color.cyan Color.pink Color.lightGray Color.darkGray Color.gray Color.white Color.black Color.red

  • If you want a color that is not on this list, you can construct your own

    There are several versions of the Color constructor; the simplest isColor( int redLevel, int greenLevel, int blueLevel )

  • Selecting a Font

    Setting the font of a graphics context is like setting the color:

    subsequent string-drawing operations will use the new font, while previously drawn strings are not affected

  • The first parameter is the name of the font

    Font availability is platform dependentFont( String fontname, int style, int size )Before you can set a font, you have to create one

  • You can get a list of available font names, returned as an array of strings, by calling the getFontList() method on your toolkit

  • "Serif""SansSerif""Monospaced"There are three font names that you can always count on, no matter what platform you are running on:On releases of the JDK before 1.1, these were called, respectively, "TimesRoman", "Helvetica", and "Courier

  • The style parameter of the Font constructor should be one of the following three ints:Font.PLAINFont.BOLDFont.ITALICYou can specify a bold italic font by passing Font.BOLD+Font.ITALIC as the style parameter to the Font constructor

  • All the rendering methods of the Graphics class specify pixel coordinate positions for the shapes they render

    Every component has its own coordinate space, with the origin in the component's upper-left corner, x increasing to the right, and y increasing downwardDrawing and Filling

  • Every component has its own coordinate space, with the origin in the component's upper-left corner, x increasing to the right, and y increasing downward

  • drawLine() drawRect() and fillRect() drawOvalQ and fillOval() drawArc() and fillArc() drawPolygon() and fillPolygon() drawPolyline() drawString() Graphics contexts do not have an extensive repertoire of painting methods

    Sophisticated rendering is handled by extended APIs such as 2D, 3D, and Animation

  • drawLine() The drawLine() method draws a line from point (x0, y0) to point (x1, y1)public void drawLine( int x0, int y0, int x1, int y1 );

  • drawRect() and fillRect() The drawRect() and fillRect() methods respectively draw and fill rectanglespublic void drawRect( int x, int y, int width, int height );public void fillRect( int x, int y, int width, int height );The x and y parameters are the coordinates of the upper-left corner of the rectangle

    Width and height must be positive numbers, or nothing will be drawn

  • drawOval() and fillOval() The drawOval() and fillOval() methods respectively draw and fill ovals

    An oval is specified by a rectangular bounding box

    To draw a circle, use a square bounding box

  • The oval lies inside the bounding box and is tangent to each of the box's sides at the midpoint

  • The two oval-drawing methods require you to specify a bounding box in exactly the same way that you specified a rectangle in the drawRect() and fillRect() methods:public void drawOval( int x, int y, int width, int height ); public void fillOval( int x, int y, int width, int height );

  • drawArc() and fillArc()An arc is a segment of an oval

    To specify an arc, you first specify the oval's bounding box, just as you do with drawOval() and fillOval()

    You also need to specify the starting and ending points of the arc, which you do by specifying a starting angle and the angle swept out by the arc

  • Angles are measured in degrees. For the starting angle, 0 degrees is to the right, 90 degrees is upward, and so on, increasing counterclockwise

    A filled arc is the region bounded by the arc itself and the two radii from the center of the oval to the endpoints of the arc public void drawArc( int x, int y, int width, int height, int startDegrees, int arcDegrees ); public void fillArc( int x, int y, int width, int height, int startDegrees, int arcDegrees );

  • drawPolygon() and fillPolygon()A polygon is a closed figure with an arbitrary number of vertices

    The vertices are passed to the drawPolygon() and fillPolygon() methods as two int arrays

  • The first array contains the x coordinates of the verticesthe second array contains the y coordinatesA third parameter specifies the number of verticespublic void drawPolygon( int[] xs, int[] ys, int numPoints ); public void fill Polygon( int[] xs, int[] ys, int numPoints );

  • drawPolyline()A polyline is similar to a polygon, but it is open rather than closed:

    there is no line segment connecting the last vertex to the first

    There is no fillPolyline() method, since fillPolygon() achieves the same result

  • The parameters to drawPolyline() are the same as those to drawPolygon():

    a pair of int arrays representing vertices and an int that tells how many vertices there arepublic void drawPolyline( int[] xs, int[] ys, int numPoints );

  • drawString()The x and y parameters specify the left edge of the baseline of the string

    Characters with descenders (g, j, p, q, and y in most fonts) extend below the baselinepublic void drawString( String s, int x, int y );The drawString() method paints a string of text

  • By default, a graphics context uses the font of the associated component

    However, you can set a different font by calling the graphics context's setFont() method

  • drawImage()An Image is an off-screen representation of a rectangular collection of pixel values

    Java's image support is complicated

    The section "Images" discusses what you need to know about creating and manipulating imagesFor now, assume that you have somehow obtained an image (that is, an instance of class java.awt.Image) that you want to render to the screen using a certain graphics context

  • im is the image to be rendered, and x and y are the coordinates within the destination component of the upper-left corner of the imageThere are other versions of the method, but this is the most common formvoid drawlmage( Image im, int x, int y, ImageObserver observer ); call the graphics context's drawlmage() method

  • The image observer must be an object that implements the ImageObserver interface and can be null

  • ClippingMost calls that programmers make on graphics contexts involve color selection or drawing and filling. A less common operation is clipping.

    Clipping is simply restricting the region that a graphics context can modifyEvery graphics context (that is, every instance of the Graphics class) has a clip region, which defines all or part of the associated component

  • When you call one of the drawXXX() or fillXXX() methods of the Graphics class, only those pixels that lie within the graphics context's clip region are modifiedThe default clip region for a graphics context is the entire associated component

    Methods that retrieve and modify a clip region

  • If an applet or a frame contains components that have their own paint() methods, then all the paint() methods will be called by the environment when necessary.

    For example, if a frame contains a panel and a canvas, then at certain times the environment will call the frame's paint(), the panel's paint(), and the canvas' paint().Painting a Contained Component

  • The frame uses a Grid layout manager with three rows and one columnThe panel is added to the frame first, so it appears in the top third of the frameThe canvas is added second, so it appears in the middle thirdSince there is no component in the last grid cell, what you see in the bottom third of the frame is the frame itself (that is, you see whatever the frame itself draws in its own paint() method)

  • paint() method and the graphics context(summary) A graphics context is dedicated to a single component

    To paint on a component, you call the graphics context's drawXXX () and fillXXX() methods

    To change the color of graphics operations, you call the graphics contexts setColor() method

  • The GUI Thread and the repaint() MethodThe runtime environment creates and controls its own threads that operate behind the scenes, and one of these threads is responsible for GUI management

    This GUI thread is the environment's tool for accepting user input events and for calling the paint() method of components that need painting

  • Calls to paint() are not all generated by the environment

    Java programs can of course make their own calls, either directly (which is not recommended) or indirectly (via the repaint() method)

    paint() calls can be generated by: Spontaneous painting, initiated by the environment Programmer-initiated painting

  • Spontaneous Painting is not an official Java term, but it gets the point across

    Some painting happens all by itself, with no impetus from the program

    For example, when a browser starts up an applet, shortly after the init() method completes, a call is made to the paint() methodSpontaneous Painting

  • Also, when part or all of a browser or a frame is covered by another window and then becomes exposed, a call is made to the paint() methodIt is the GUI thread that makes these calls to paint().

    Every applet, and every application that has a GUI, has a GUI thread

  • The GUI thread spontaneously calls paint() under four circumstances, two of which are only applicable for applets:After exposureAfter de-iconificationShortly after init() returns (applets only)When a browser returns to a previously displayed page containing an applet, provided the applet is at least partially visible

  • When the GUI thread calls paint(), it must supply a graphics context, since the paint() method's input parameter is an instance of the Graphics classThe GUI thread makes sure that the graphics contexts that get passed to paint() have their clip regions appropriately set

  • Most often, the default clip region is appropriate. Recall that the default clip region is the entire component

    However, when a component is exposed, the clip region is set to be just that portion of the component that requires repair

    If only a small piece of the component was exposed, then the clip region insures that no time is wasted on drawing pixels that are already the correct color

  • The repaint() MethodThere are times when the program, not the environment, should initiate painting. This usually happens in response to input eventsSuppose you have an applet that wants to draw a red dot at the point ot the most recent mouse click. The remainder of the applet should be yellow

  • Assume that the applet is handling its own mouse events. Your event handler might look like this:

  • There are two reasons why this approach is far from optimalFirst, if the applet ever gets covered and exposed, the GUI thread will call paint(). Unfortunately, paint() does not know about the red circle that was drawn in mousedClicked(), so the red circle will not be repaired It is a good rule of thumb to do all drawing operations in paint(), or in a method called from paint(), so that the GUI thread will be able to repair exposure damage. The GUI thread expects paint() to be able to correctly reconstruct the screen at anv arbitrary moment

  • The way to give the GUI thread what it expects is to remove all drawing code from event handlers

    Event handlers such as mousedClicked() above should store state information in instance variables, and then cause a call to paint()

  • The paint() method should use the values of the instance variables as instructions on what to draw

    In our example, mousedClicked() should be modified as shown below, assuming that the class has instance variables m_mouseX and m_mouseY:

  • The paint() method should be as follows:Much better! Now if a dot gets covered and exposed, the damage will be repaired automatically. There remains, however, a second problem, and it is a bit subtler than the spontaneous painting issue.

  • The program can be simplified a bit.

    There is a method of the Component class called update(), which clears the component to its background color and then calls paint().

    The input parameter to update() is a graphics context The applet's init() method could set the background color to yellow:

  • Now the event handler should call update() rather than paint(), and update() only needs to draw the red dot:

  • In the real world, programs often need to track many different kinds of events: action events, adjustment events, key events, focus events, mouse events, mouse-motion events, and so on. It may be that every event requires painting the screen anew Consider what happens if a large number of events of different type are generated in rapid succession: this is not unusual; moving or dragging the mouse can create a lot of mouse-moved and mouse-dragged events in very short order

    Time after time, an event will be generated, event handlers will modify instance variables, and paint() will modify the screen, only to have the cycle repeat and repeat

  • Most of the screen-drawing operations will instantly get clobbered by other screen-drawing operations triggered by more recent events. Many compute cycles will be wasted

    The more compute-intensive the paint() method is, the worse the situation becomes. If the user can generate events faster than paint() can handle them, then the program will tail farther and farther behindIt would be ideal if the event handlers could just modify the instance variables and have paint() run from time to time, often enough that the screen stays up to date, but not so often that compute cycles are wasted

    This is where the repaint() method comes in

  • The repaint() method schedules a call to the update() method

    All this means that a request flag is set in the GUI thread. Every 100 milliseconds (on most platforms), the GUI thread checks the flag

    If the flag is set, thell thread calls update() and clears the flag

    No matter how many requests are made during any 100-millisecond period, only a single call is made to update()

  • The code above shows the preferred approach to handling events that cause the screen to be changed:

    event handlers store information in instance variables and then call repaint(), and paint() draws the screen according to the information in the instance variables

    The two benefits of this approach are: The screen is correctly repaired when the environment spontaneously calls paint()

    The Virtual Machine never gets overwhelmed by events

  • If you want to accumulate dots, rather than have each dot cleared away when a new one is to be drawn, you can always override update() so that it does not clear

    All update() needs to do in this case is call paint(), as shown below:This is a standard technique

  • ImagesImages are off-screen representations of rectangular pixel patterns

    There are three things you can do with images: Create them Modify them Draw them to the screen or to other images

  • There are two ways to create an image

    You can create an empty one, or

    2. you can create one that is initialized from a .gif or a .jpg file

  • To create an empty' image, call the createlmage() method of the Component class and pass in the desired width and height

    For example, the following line creates an image called im that is 400 pixels wide by 250 pixels high; it might appear in the init() method of an applet:Image im = createlmage( 400, 250 );

  • An image can be created based on the information in a .gif or a .jpg file

    The Applet and Toolkit classes both have a method called getlmage(), which has two common forms: getImage( URL fileURL )

    getImage( URL dirURL, String path )

  • The code fragment below shows an applet's init() method; it loads an image from a file that resides in the same server directory as the page that contains the applet:

  • If you load an image from a file, you may want to modify it; you will definitely want to modify any image that you create via createlmage()

    Fortunately, images have graphics contexts. All you need to do is obtain a graphics context for the image you wish to modify and make the calls that were discussed earlier in this chapter in "Drawing and Filling."

    To obtain a graphics context, just call the getGraphics() method of the image

  • The code below implements an applet whose init() method creates an image and then obtains a graphics context in order to draw a blue circle on a yellow background

    The applet's paint() method renders the image onto the screen using the drawImage() method