A bit of ad : OOP ask a effort in the beginnings ...
If you want to put a windows in a wall, you don't say :
"Let's use a hammer to make a hole in that wall, then let's measure the size of the hole, then lets buy some piece of wood that we will put together, then ...
You say : Let's decide to have a windows in that wall
You know first what you want and then you think of the way you will get it
isn't it easier to list the actions that you can do with a car (to buy, to sell, ...to drive°) than to list all the object you can buy ... and forget lots of them ?
is a relationship
with lots of "if then else" statements
Object-Oriented Design | Procedural Design |
---|---|
From general architecture towards details |
From details towards construction of complex buildings |
void processShape(Shape s) { s.setColor(Color.red); // ... do stuff s.draw(); } Circle c = new Circle(x, y, r); Point2D v1 = new Point2D(x1, y1);Point2D v2 = new Point2D(x2, y2);Point2D v3 = new Point2D(x3, y3);Triangle t = new Triangle(v1, v2, v3); Point2D c1 = new Point2D(u1, v1);Point2D c2 = new Point2D(u2, v2);Triangle r = new Rectangle(c1, c2); processShape(c);processShape(t);processShape(r); |
{ White space is a very important part of any Java program { has no effect on the code's meaning enhances readability and communicates structure includes : spaces, tabs, and new lines. typically, tabs or indention set off blocks of code new-lines separate statements }}
Make sure that readers could easily find beginning and end of your blocks
A Java source program is composed of white space, comments, declarations, and statements.
White space is a very important part of any Java program. While it has no effect on the meaning of the code, white space, more than any other factor, contributes to the readability and signals the structure of a code fragment. White space includes, spaces, tabs, and new lines. Typically, tabs or indention is used to set off blocks of code, and new lines are used to separate statements. There are no hard-fast rules how and when to use white space, all I suggest is that you adopt a consistent style.
answer = 42; // valid independent of the input
/*... This next bit of code is so obvious that I hesitated to comment it a first. For those whom intergalactic culture is limited, please refer to the textbook : "the hitch hicker guide for the galaxy" by Douglas Adams. tip : 42 is the answer for life, the universe and everything*/ answer = 42;
Next to white space, the most important part of any Java program is comments. Keep in mind the syntax of a language is designed for communicating a program's design to a computer. Comments, on the other hand, are the primary mechanism for communicating a program's design to humans. Java has three types of comments.
/** The Universe and Everything * * @version 0.9999 Date : This must be Thursday * @author Ford Prefect * @author Arthur Dent * @see <A HREF="http://users.milliways.mg-net.de/BSAFH/guide/">the book</A> */ public class theUnivers { public static String getTheAnswer() { return("42"); } /** * @deprecated Remember a important thing about that question ... * "It is said that if both the question and the answer to Life, * the Universe and Everything ever exist in the same dimention * it will dissappear and be replaced by something even more strange * and unexplicable" -Hitch Hicker Guide To The Galaxy */ private String getTheQuestion() { while(true) { sleep(1); } }}
Notes:
boolean likeeScience = true; /* boolean likewise have values {true, false} they can never be mixed up with integer or other type */byte teeth = 32; // bytes go from -128 to 127if (!likeeScience) teeth = teeth - 1;float pi = 3.141592f; // you need the "f" hereshort classes = 0xbad; // hexadecimal
byte buffer[]; // array declaration (buffer = null)buffer = new byte[1024]; // array creation (contents initialised to zeros)int table[] = new int[10]; // declaration and creation combined int sqrs[] = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81 }; // with an initializerbuffer[5] = sqrs[sqrs.length-1]; // array references int triangle[][] = new int[3][]; // 2D Arrays do not have to be matrixtriangle[0] = new int[3];triangle[1] = new int[2];triangle[2] = new int[1];
class Circle // object definition{ static double pi = 3.141592; // class variable double radius; // instance variable public Circle(double r) // constructor method { radius = r; } public double circumference() { return 2*pi*radius; } public double area() { return pi*radius*radius; } public static getPi() { return pi; } // class method} Circle c; // object declarationc = new Circle(4.0); // object creationdouble a = c.area(); // object method call
. [] ()++ -- ! ~ instanceof* / %+ -<< >> >>>< > <= >=== !=&^|&&||?:= *= /= %= += -= <<= >>= >>>= &= ^= |=
The final component of a Java program is its statements. Individual statements are terminated by semicolons. Groups of statements and declarations enclosed within braces, { and }, are called block statements and they act like an individual statement. Block statements do not require a terminating semicolon. The simplest type of statement is the expression.
An expression is a string of variables and constants separated by operators. A common type of expression is the assignment where a variable is given the value of the expression to the left of an equal sign. If one of the operator-assignment forms is used, the variable is given the value of expression to the left of the equals sign combined with it previous value of the variable as determined by the operator to the left of the equals sign. For more specific details on operators and the types of arguments that they allow see the textbooks.
Really classical structure, especially easy to understand for english speaking programmer.
NB : BoolleanExpression are Boolean Expressions)
Break, continue, Label ...
Loop : be sure to get out of it
if (BooleanExpression) Statement if (BooleanExpression) Statement else Statement while (BooleanExpression) Statement do Statement while (BooleanExpression) for (Expression; BooleanExpression; Expression) Statement break <Label> continue <Label> Label: Statement switch (IntegerExpression){ case IntegerValue: Statements default: Statements}return Expression
In these examples reserved keywords are shown in bold.
new create a new object from a class. It allocates memory and call the adequate constructor method of the class to initialise field values.
Let the students talk ...
This : the object instance of a class (constructors)
super : the parent class
final : method can't be overwritten, class can not be subclassed
static : a class thing. No object instance is needed.
This week exercise
public : accessible anywhere
private : member accessible only within the class that defines it
protected : member accessible only within package and within subclasses.
A way to deal with things that should not happen (better than the if then else)
Each time there is an input from outside of the program
abstract : a method implementation is missing somewhere
/** Simple Java 2D Example * * @version 0.9 12/07/2001 * @author Pascal Vuylsteker */ import javax.swing.*; public class HelloWordSimple{ public static void main(String[] args) { HelloWordFrame frame = new HelloWordFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); }}class HelloWordFrame extends JFrame { public HelloWordFrame() { setTitle("Hello World !! "); setSize(300,200); HelloPanel panel = new HelloPanel(); Container contentPane = getContentPane(); contentPane.add(panel); }}class HelloPanel extends JPanel{ public void paintComponent(Graphics g) { super.paintComponent(g); g.drawString("Hello again...", 20, 20); }}
All Java source code files should end with a .java extension. When a Java program is compiled one or more .class files are generated. The number of .class files generated by a compile depends on how many objects are defined in the source file.
Let's test it first
/** Simple Java 2D Example * * @version 0.9 12/07/2001 * @author Pascal Vuylsteker */ // to tell to the compiler where to look for class definition// class that are not in the default package nor in java.langimport javax.swing.*;// that was missing...import java.awt.*;//Since all Java code must be contained within an object, // an object called HelloWordSimple is defined in this file.// "There should be only one"... public class per filepublic class HelloWordSimple{ // in order to run a program, the public class should contain // a main method which is static public static void main(String[] args) { HelloWordFrame frame = new HelloWordFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); }}// You don't even need to know any of the details of how a class works, // beyond the interfaces to methods, in order to modify the original code. This // is a simple example of the power of object-oriented programming. class HelloWordFrame extends JFrame { public HelloWordFrame() { setTitle("Hello World !! "); setSize(300,200); HelloPanel panel = new HelloPanel(); Container contentPane = getContentPane(); contentPane.add(panel); }}// JPanel has to be extented : the main method contain all// the work.class HelloPanel extends JPanel{ public void paintComponent(Graphics g) { super.paintComponent(g); g.drawString("Hello again...", 20, 20); }}
NB : what is wrong with ?
It is not object oriented programming...
See the
It is one of the few ``non-painted'' graphics components.
Frames are examples of containers and we will study ways of inserting graphics objects into them.
The 'x' stands for 'extension'.
By default JFrame has 0x0 pixels! You need to define your own frame class which extends it and which is bigger. Use the setSize() method to increase its size.
Units of size are pixels.
defines what happens when you close the frame
In other programs you would want to change this so that the program did not exit whenever the user closed a window. By default a frame is ``hidden'' when a user closes it but the program does not terminate.
Frames start their life invisible! You must call show to display them.
Note that the main program exits after the show call.
This just terminates the main thread.
Graphics is in a separate thread.
Many of the useful JFrame methods are inherited from other classes further up the hierarchy
| +-- | +-- | +-- | +-- | +--javax.swing.JFrame
setLocation(x,y)
This method can move the frame around. Note that y measures the number of pixels down from the top left corner of the screen. Also note that both arguments are integers.
Note that the coordinates in JFrame methods are with respect to the whole screen. In other swing classes they are usually with respect to a specific container.
It is possible to get the dimensions of the screen you are using by creating an object of class Toolkit and calling its getScreenSize() method. This returns the width and height as fields in a dimension object. The pattern is
Toolkit kit = Toolkit.getDefaultToolkit(); Dimension screenSize = kit.getScreenSize(); int screenHeight = screenSize.height; int screenWidth = screenSize.width;
The glass paneHidden, by default. If you make the glass pane visible, then it's like a sheet of glass over all the other parts of the root pane. It's completely transparent unless you implement the glass pane's paint method so that it does something, and it intercepts input events for the root pane. The layered paneServes to position its contents, which consist of the content pane and the optional menu bar. Can also hold other components in a specified Z order. The content paneThe container of the root pane's visible components, excluding the menu bar. For information on using the content pane, see Using Top-Level Containers. The optional menu barThe home for the root pane's container's menus. If the container has a menu bar, you generally use the container's setJMenuBar method to put the menu bar in the appropriate place. For more information on using menus and menu bars, see How to Use Menus. |
Although it is possible to draw directly onto a JFrame this is considered to be bad programming practice. The thing most swing programmers do is to add components to the content pane which is part of the JFrame. (See fig 7-7.) The thing to do is to call the getContentPane() method of your JFrame to create a Container object and then to add Componentto this.
Container contentPane = getContentPane(); HelloPanel panel = new HelloPanel(); contentPane.add(panel);
Why do you extend JPanel? Because the basic panel is very boring. You need to override its paintComponent method so that the system will draw interesting objects.
g.drawString("Hello World!", MESSAGE_X, MESSAGE_Y);will draw a string at the specified position.
super.paintComponent(g);
For example, you could use the Java 2D API to display complex charts and graphs that use various line and fill styles to distinguish sets of data, like those shown in the following figure.
The Java 2D API also enables you to store and to manipulate image data--for example, you can easily perform image-filter operations, such as blur and sharpen, as shown in the following figure.
The Java 2D API introduced in JDK 1.2 provides enhanced two-dimensional graphics, text, and imaging capabilities for Java programs through extensions to the Abstract Windowing Toolkit (AWT). This comprehensive rendering package supports line art, text, and images in a flexible, full-featured framework for developing richer user interfaces, sophisticated drawing programs and image editors.
The basic rendering mechanism is the same as in previous versions of the JDK--the drawing system controls when and how programs can draw. When a component needs to be displayed, its paint
or update
method is automatically invoked with an appropriate Graphics
context.
The Java 2D API introduces , a new type of Graphics
object. Graphics2D
extends the class to provide access to the enhanced graphics and rendering features of the Java 2D API.
To use Java 2D API features, you cast the Graphics
object passed into a
component's rendering method to a Graphics2D
object.
public void Paint (Graphics g) { Graphics2D g2 = (Graphics2D) g; ...}
The collection of state attributes associated with a Graphics2D
object is referred to as the draw
or fill
. As the following figure shows, the Graphics2D
rendering context contains several attributes.
Graphics2D
rendering context, you use the set
Attribute
methods
The pen style :
setStroke
that is applied to the outline of a shape. This stroke attribute enables you to draw lines with any point size and dashing pattern and to apply end-cap and join decorations to a line.
The fill style :
setPaint
that is applied to a shape's interior. This paint attribute enables you to fill shapes with solid colors, gradients, and patterns.
The compositing style :
setComposite
that is used when rendered objects overlap existing objects.
The transform :
setTransform
that is applied during rendering to convert the rendered object from user space to device-space coordinates. Optional translation, rotation, scaling, or shearing transforms can also be applied through this attribute.
The clip :
setClip
which restricts rendering to the area within the outline of the
Shape
used to define the clipping path. AnyShape
can be used to define the clip.The font :
setFont
used to convert text strings to glyphs.
Rendering hints :
setRenderingHints
that specify preferences in the trade-offs between speed and quality. For example, you can specify whether antialiasing should be used, if it's available.
When you set an attribute, you pass in the appropriate attribute object. For example, to change the paint attribute to a blue-green gradient fill, you would construct a GradientPaint
object and then call setPaint
.
gp = new GradientPaint(0f,0f,blue,0f,30f,green);g2.setPaint(gp);
Graphics2D
holds references to its attribute objects--they are not cloned. If you alter an attribute object that is part of the Graphics2D
context, you need to call the appropriate set
method to notify the context. Modifying an attribute object during rendering causes unpredictable behavior.
Graphics2D
provides the following general rendering methods that can be used to draw any geometry primitive, text, or image:
draw
fill
--renders any geometry primitive by filling its interior with the color or pattern specified by the paint attribute. drawString
--renders any text string. The font attribute is used to convert the string to glyphs, which are then filled with the color or pattern specified by the paint attribute. drawImage
--renders the specified image. In addition, Graphics2D
supports the Graphics
rendering methods for particular shapes, such as drawOval
and fillRect
.
User space is a device-independent logical coordinate system : the coordinate space that your program uses.
All geometries passed into Java 2D rendering routines are specified in user-space coordinates.
When the default transformation from user space to device space is used, the origin of user space is the upper-left corner of the component's drawing area. The x coordinate increases to the right, and the y coordinate increases downward, as shown in the following figure.
Device space is a device-dependent coordinate system that varies according to the target rendering device. Although the coordinate system for a window or the screen might be very different from that of a printer, these differences are invisible to Java programs. The necessary conversions between user space and device space are performed automatically during rendering.
The classes in the java.awt.geom package define common graphics primitives, such as points, lines, curves, arcs, rectangles, and ellipses.
Arc2D | Ellipse2D | QuadCurve2D |
Area | GeneralPath | Rectangle2D |
CubicCurve2D | Line2D | RectangularShape |
Dimension2D | Point2D | RoundRectangle2D |
Shape
interfaceExcept for Point2D
and Dimension2D
, each of the geometry classes (geometries) implements the Shape
interface, which provides a common set of methods for describing and inspecting two-dimensional geometric objects.
With these classes you can create virtually any geometric shape and render it through Graphics2D
by calling the draw
method or the fill
method.
For example, the geometric shapes in the following ShapesDemo2D
applet are defined by using basic Java 2D geometries.
Example : .
The Rectangle2D
, RoundRectangle2D
, Arc2D
, and Ellipse2D
primitives are all derived from RectangularShape
, which defines methods for Shape
objects that can be described by a rectangular bounding box. The geometry of a RectangularShape
can be extrapolated from a rectangle that completely encloses the outline of the Shape
.
The QuadCurve2D
class allows you to create quadratic parametric curve segments. A quadratic curve is defined by two endpoints and one control point.
The CubicCurve2D
class allows you to create cubic parametric curve segments. A cubic curve is defined by two endpoints and two control points. The following figures demonstrate examples of quadratic and cubic curves.
See to see implementations of cubic and quadratic curves.
The GeneralPath
class enables you to construct an arbitrary shape by specifying a series of positions along the shape's boundary. These positions can be connected by line segments, quadratic curves, or cubic (Bézier) curves. The shape pictured below can be created with three line segments and a cubic curve.
See to see the implementation of this shape.
With the Area
class you can perform boolean operations, such as union, intersection, and subtraction, on any two Shape
objects. This technique, often referred to as constructive area geometry, enables you to quickly create complex Shape
objects without having to describe each line segment or curve.
How to draw and fill shapes is described in the next lesson, .
Example : .
By changing the stroke and paint attributes in the Graphics2D
context before rendering, you can easily apply fancy line styles and fill patterns to graphics primitives. For example, you can draw a dashed line by creating an appropriate Stroke
object and calling setStroke
to add it to the Graphics2D
context before you render the line. Similarly, you can apply a gradient fill to a Shape
by creating a GradientPaint
object and adding it to the Graphics2D
context by calling setPaint
before you render the Shape
.
The following applet demonstrates how you can render basic geometries by using the Graphics2D
draw
and fill
methods.
contains the complete code for this applet.
Each of the shapes drawn by the applet is constructed from one of the geometries and is then rendered through Graphics2D
. The rectHeight
and rectWidth
variables in this example define the dimensions of the space where each shape is drawn, in pixels. The x and y variables change for each shape so that they are drawn in a grid formation.
// draw Line2D.Doubleg2.draw(new Line2D.Double(x, y+rectHeight-1, x + rectWidth, y)); // draw Rectangle2D.Doubleg2.setStroke(stroke);g2.draw(new Rectangle2D.Double(x, y, rectWidth, rectHeight)); // draw RoundRectangle2D.Doubleg2.setStroke(dashed);g2.draw(new RoundRectangle2D.Double(x, y, rectWidth, rectHeight, 10, 10)); // draw Arc2D.Doubleg2.setStroke(wideStroke);g2.draw(new Arc2D.Double(x, y, rectWidth, rectHeight, 90, 135, Arc2D.OPEN)); // draw Ellipse2D.Doubleg2.setStroke(stroke);g2.draw(new Ellipse2D.Double(x, y, rectWidth, rectHeight)); // draw GeneralPath (polygon)int x1Points[] = {x, x+rectWidth, x, x+rectWidth};int y1Points[] = {y, y+rectHeight, y+rectHeight, y};GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, x1Points.length);polygon.moveTo(x1Points[0], y1Points[0]);for (int index = 1; index < x1Points.length; index++) { polygon.lineTo(x1Points[index], y1Points[index]);};polygon.closePath();g2.draw(polygon); // draw GeneralPath (polyline)int x2Points[] = {x, x+rectWidth, x, x+rectWidth};int y2Points[] = {y, y+rectHeight, y+rectHeight, y};GeneralPath polyline = new GeneralPath(GeneralPath.WIND_EVEN_ODD, x2Points.length);polyline.moveTo (x2Points[0], y2Points[0]);for (int index = 1; index < x2Points.length; index++) { polyline.lineTo(x2Points[index], y2Points[index]);};g2.draw(polyline); // fill Rectangle2D.Double (red)g2.setPaint(red);g2.fill(new Rectangle2D.Double(x, y, rectWidth, rectHeight)); // fill RoundRectangle2D.Doubleg2.setPaint(redtowhite);g2.fill(new RoundRectangle2D.Double(x, y, rectWidth, rectHeight, 10, 10)); // fill Arc2Dg2.setPaint(red);g2.fill(new Arc2D.Double(x, y, rectWidth, rectHeight, 90, 135, Arc2D.OPEN)); // fill Ellipse2D.Doubleg2.setPaint(redtowhite);g2.fill (new Ellipse2D.Double(x, y, rectWidth, rectHeight)); // fill and stroke GeneralPathint x3Points[] = {x, x+rectWidth, x, x+rectWidth};int y3Points[] = {y, y+rectHeight, y+rectHeight, y};GeneralPath filledPolygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD, x3Points.length);filledPolygon.moveTo(x3Points[0], y3Points[0]);for (int index = 1; index < x3Points.length; index++) { filledPolygon.lineTo(x3Points[index], y3Points[index]);};filledPolygon.closePath();g2.setPaint(red);g2.fill(filledPolygon);Note that this example uses the double-precision implementations of the geometries classes. Where applicable, float and double-precision implementations of each of the geometries are provided as inner classes.
The Cubic
and Quad
applets demonstrate how to create cubic and quadratic curves using CubicCurve2D
and QuadCurve2D
respectively. These applets also demonstrate how the curves are drawn with respect to the positioning of the control points by allowing you to interactively move both the control points and the end points.
The Quad
applet demonstrates a quadratic curve, which is a curved segment that has two endpoints and only one control point. The control point determines the shape of the curve by controlling both of the endpoint tangent vectors.
contains the complete code for this applet.
First, a new quadratic curve is created with two endpoints and a control point and the locations of the points are set with respect to the size of the window.
QuadCurve2D.Double quad = new QuadCurve2D.Double();Point2D.Double start, end, control;start = new Point2D.Double();end = new Point2D.Double();control = new Point2D.Double();quad.setCurve(start, control, end);start.setLocation(w/2-50, h/2);end.setLocation(w/2+50, h/2);control.setLocation((int)(start.x)+50, (int)(start.y)-50);
Every time the user moves one of the points, the curve is reset.
quad.setCurve(start, control, end);
The Cubic
sample demonstrates a cubic curve, which is a curved segment that has two endpoints and two control points. Each control point determines the shape of the curve by controlling one of the endpoint tangent vectors. In the Cubic
sample, colored squares are drawn where the control points and endpoints are located. The blue control point controls the tangent vector of the red endpoint and the green control point controls the tangent vector of the magenta endpoint.
contains the complete code for this applet.
A new cubic curve is created with two endpoints and a two control points and the locations of the points are set with respect to the size of the window.
CubicCurve2D.Double cubic = new CubicCurve2D.Double(); Point2D.Double start, end, one, two;start = new Point2D.Double();one = new Point2D.Double();two = new Point2D.Double();end = new Point2D.Double();cubic.setCurve(start, one, two, end);...start.setLocation(w/2-50, h/2);end.setLocation(w/2+50, h/2);one.setLocation((int)(start.x)+25, (int)(start.y)-25);two.setLocation((int)(end.x)-25, (int)(end.y)+25);
As in the Quad
example, the curve is reset every time the points are moved.
cubic.setCurve(start, one, two, end);
TheShapesDemo
example usesGeneralPath
to make the hourglass-shaped polygons, but you can also useGeneralPath
to make arbitrary shapes with both straightand curved lines.Example: Odd_Shape
TheOdd_Shape
sample usesGeneralPath
to create thearbitrary shape shown in the section.contains the complete code for this applet.
The following code creates a new
GeneralPath
and adds thefirst point to the path.After the first point is added to the path, three straight lines areadded to the path.GeneralPath oddShape = new GeneralPath();...x = w/2 + 50;y = h/2 - 25;x2 = x; y2 = y;oddShape.moveTo(x, y);Finally, a cubic curve is added to the path.x -= 100;oddShape.lineTo(x, y);y += 50;oddShape.lineTo(x, y);x += 100;oddShape.lineTo(x, y);x += 10;y -= 10;x1 = x - 20;y1 = y - 20;oddShape.curveTo(x, y, x1, y1, x2, y2);
You probably noticed that in the previous example some of the shapes have thicker outlines or are filled with a two-color gradient. Using the Java 2D Stroke
and Paint
classes, you can easily define fancy line styles and fill patterns.
Line Styles
Line styles are defined by the stroke attribute in theGraphics2D
rendering context. To set the stroke attribute, you create aBasicStroke
object and pass it into theGraphics2D
setStroke
method.A
BasicStroke
object holds information about the line width, join style, end-cap style, and dash style. This information is used when aShape
is rendered with thedraw
method.The line width is the thickness of the line measured perpendicular to its trajectory. The line width is specified as a
float
value in user coordinate units, which are roughly equivalent to 1/72 inch when the default transform is used.The join style is the decoration that is applied where two line segments meet.
BasicStroke
supports three join styles:
JOIN_BEVEL
JOIN_MITER
JOIN_ROUND
The end-cap style is the decoration that is applied where a line segment ends.
BasicStroke
supports three end-cap styles:
CAP_BUTT
CAP_ROUND
CAP_SQUARE
The dash style defines the pattern of opaque and transparent sections applied along the length of the line. The dash style is defined by a dash array and a dash phase. The dash array defines the dash pattern. Alternating elements in the array represent the dash length and the length of the space between dashes in user coordinate units. Element 0 represents the first dash, element 1 the first space, and so on. The dash phase is an offset into the dash pattern, also specified in user coordinate units. The dash phase indicates what part of the dash pattern is applied to the beginning of the line.
Fill Patterns
Fill patterns are defined by the paint attribute in theGraphics2D
rendering context. To set the paint attribute, you create an instance of an object that implements thePaint
interface and pass it into theGraphics2D
setPaint
method.Three classes implement the
Paint
interface:Color
,GradientPaint
, andTexturePaint
.GradientPaint
andTexturePaint
are new in JDK 1.2.To create a GradientPaint, you specify a beginning position and color and an ending position and color. The gradient changes proportionally from one color to the other along the line connecting the two positions.
The pattern for a
TexturePaint
is defined by aBufferedImage
. To create aTexturePaint
, you specify the image that contains the pattern and a rectangle that is used to replicate and anchor the pattern.
Example: StrokeAndFill
TheStrokeAndFill
applet allows the user to select a graphics primitive, a line style, and a paint style and to either stroke the object's outline, fill it with the selected paint, or stroke the object in black and then fill it with the selected paint.
This is a picture of the applet's GUI. To run the applet, click the picture. The applet will appear in a new browser window.contains the complete code for this applet.
The primitives are initialized and entered into an array of
Shape
objects. The following code creates aRectangle
and anEllipse2D.Double
and enters them into theshapes
array.
shapes[0] = new Rectangle(0, 0, 100, 100);shapes[1] = new Ellipse2D.Double(0.0, 0.0, 100.0, 100.0);To create a
Shape
object from a text string, you must first create aTextLayout
object from the text string.
TextLayout textTl = new TextLayout("Text", new Font("Helvetica", 1, 96), new FontRenderContext(null, false, false));The following lines transform the
TextLayout
so that it is centered on the origin and then enter theShape
object resulting from the call togetOutline
into theshapes
array.
AffineTransform textAt = new AffineTransform();textAt.translate(0, (float)textTl.getBounds().getHeight());shapes[2] = textTl.getOutline(textAt);You can choose a primitive by accessing the appropriate index into the
shapes
array.
Shape shape = shapes[Transform.primitive.getSelectedIndex()];How rendering is performed depends on which rendering option is chosen.
- When the user chooses stroke,
Graphics2D.draw
is called to perform the rendering. If text is chosen as the primitive, the glyph outlines are retrieved and then rendered with thedraw
method.- When the user chooses fill,
Graphics2D.fill
orGraphics2D.drawString
is called to perform the rendering.- When the user chooses stroke and fill,
fill
ordrawString
is called to fill theShape
, and thendraw
is called to stroke its outline.
Note: To both fill and stroke a graphics primitive, you need to make two separate method calls:fill
ordrawString
to fill its interior anddraw
to stroke its outline.
The three line styles used in this example--thin, thick, and dashed--are instances of
BasicStroke
.// Sets the Stroke....case 0 : g2.setStroke(new BasicStroke(3.0f)); break;case 1 : g2.setStroke(new BasicStroke(8.0f)); break;case 2 : float dash[] = {10.0f}; g2.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f)); break;The dash style in this example has 10 unit dashes alternating with 10 unit spaces. The beginning of the dash pattern is applied to the beginning of the line--the dash phase is set to 0.0.
Three paint styles are used in this example--solid, gradient, and polka. The solid-color paint style is an instance of
Color
, the gradient an instance ofGradientPaint
, and the pattern an instance ofTexturePaint
.// Sets the Paint....case 0 : g2.setPaint(Color.blue); break;case 1 : g2.setPaint(new GradientPaint(0, 0, Color.lightGray, w-250, h, Color.blue, false)); break;case 2 : BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB); Graphics2D big = bi.createGraphics(); big.setColor(Color.blue); big.fillRect(0, 0, 5, 5); big.setColor(Color.lightGray); big.fillOval(0, 0, 5, 5); Rectangle r = new Rectangle(0,0,5,5); g2.setPaint(new TexturePaint(bi, r)); break;
The Java 2D API implements a new imaging model that supports the manipulation of fixed-resolution images stored in memory. A new Image class in the java.awt.image package, BufferedImage, can be used to hold and to manipulate image data retrieved from a file or a URL. For example, a BufferedImage can be used to implement double buffering--the graphic elements are rendered off-screen to the BufferedImage and are then copied to the screen through a call to Graphics2D drawImage. The classes BufferedImage and BufferedImageOp also enable you to perform a variety of image-filtering operations, such as blur and sharpen. The producer/consumer imaging model providedin previous versions of the JDK is supported for backward compatibility.
bi = new BufferedImage[4]; String s[] = { "bld.jpg", "bld.jpg", "boat.gif", "boat.gif"}; for ( int i = 0; i < bi.length; i++ ) { Image img = getImage(getURL("images/" + s[i])); try { MediaTracker tracker = new MediaTracker(this); tracker.addImage(img, 0); tracker.waitForID(0); } catch ( Exception e ) {} int iw = img.getWidth(this); int ih = img.getHeight(this); bi[i] = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB); Graphics2D big = bi[i].createGraphics(); big.drawImage(img,0,0,this); }