Java/2D Graphics GUI/Stroke
Содержание
- 1 A component for choosing a stroke from a list of available strokes.
- 2 A dashed stroke
- 3 Basic stroke
- 4 Cancel the effects of the zoom on a particular Stroke
- 5 Changing the Thickness of the Stroking Pen
- 6 Custom Strokes
- 7 Dashed rectangle
- 8 Dashed stroke
- 9 Serialises a Stroke object
- 10 Smokey effect
- 11 Stroke with iron effect
- 12 Stroking or Filling with a Texture
- 13 Thick stroke demo
- 14 Tries to deduct the stroke-type from the given stroke object.
- 15 Tries to extract the stroke-width from the given stroke object.
A component for choosing a stroke from a list of available strokes.
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* StrokeChooserPanel.java
* -----------------------
* (C) Copyright 2000-2009, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): Dirk Zeitz;
*
* $Id: StrokeChooserPanel.java,v 1.8 2009/02/27 13:58:41 mungady Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 16-Mar-2004 : Fix for focus problems (DZ);
* 27-Feb-2009 : Fixed bug 2612649, NullPointerException (DG);
*
*/
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
* A component for choosing a stroke from a list of available strokes.
*
* @author David Gilbert
*/
public class StrokeChooserPanel extends JPanel {
/** A combo for selecting the stroke. */
private JComboBox selector;
/**
* Creates a panel containing a combo-box that allows the user to select
* one stroke from a list of available strokes.
*
* @param current the current stroke sample.
* @param available an array of "available" stroke samples.
*/
public StrokeChooserPanel(StrokeSample current, StrokeSample[] available) {
setLayout(new BorderLayout());
// we"ve changed the behaviour here to populate the combo box
// with Stroke objects directly - ideally we"d change the signature
// of the constructor too...maybe later.
DefaultComboBoxModel model = new DefaultComboBoxModel();
for (int i = 0; i < available.length; i++) {
model.addElement(available[i].getStroke());
}
this.selector = new JComboBox(model);
this.selector.setSelectedItem(current.getStroke());
this.selector.setRenderer(new StrokeSample(null));
add(this.selector);
// Changes due to focus problems!! DZ
this.selector.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent evt) {
getSelector().transferFocus();
}
});
}
/**
* Returns the selector component.
*
* @return Returns the selector.
*/
protected final JComboBox getSelector() {
return this.selector;
}
/**
* Returns the selected stroke.
*
* @return The selected stroke (possibly <code>null</code>).
*/
public Stroke getSelectedStroke() {
return (Stroke) this.selector.getSelectedItem();
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------
* StrokeSample.java
* -----------------
* (C) Copyright 2000-2009, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: StrokeSample.java,v 1.5 2009/02/27 13:58:41 mungady Exp $
*
* Changes (from 26-Oct-2001)
* --------------------------
* 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
* 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 21-Mar-2003 : Fixed null pointer exception, bug 705126 (DG);
*
*/
/**
* A panel that displays a stroke sample.
*
* @author David Gilbert
*/
class StrokeSample extends JComponent implements ListCellRenderer {
/** The stroke being displayed (may be null). */
private Stroke stroke;
/** The preferred size of the component. */
private Dimension preferredSize;
/**
* Creates a StrokeSample for the specified stroke.
*
* @param stroke the sample stroke (<code>null</code> permitted).
*/
public StrokeSample(final Stroke stroke) {
this.stroke = stroke;
this.preferredSize = new Dimension(80, 18);
setPreferredSize(this.preferredSize);
}
/**
* Returns the current Stroke object being displayed.
*
* @return The stroke (possibly <code>null</code>).
*/
public Stroke getStroke() {
return this.stroke;
}
/**
* Sets the stroke object being displayed and repaints the component.
*
* @param stroke the stroke (<code>null</code> permitted).
*/
public void setStroke(final Stroke stroke) {
this.stroke = stroke;
repaint();
}
/**
* Returns the preferred size of the component.
*
* @return the preferred size of the component.
*/
public Dimension getPreferredSize() {
return this.preferredSize;
}
/**
* Draws a line using the sample stroke.
*
* @param g the graphics device.
*/
public void paintComponent(final Graphics g) {
final Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
final Dimension size = getSize();
final Insets insets = getInsets();
final double xx = insets.left;
final double yy = insets.top;
final double ww = size.getWidth() - insets.left - insets.right;
final double hh = size.getHeight() - insets.top - insets.bottom;
// calculate point one
final Point2D one = new Point2D.Double(xx + 6, yy + hh / 2);
// calculate point two
final Point2D two = new Point2D.Double(xx + ww - 6, yy + hh / 2);
// draw a circle at point one
final Ellipse2D circle1 = new Ellipse2D.Double(one.getX() - 5,
one.getY() - 5, 10, 10);
final Ellipse2D circle2 = new Ellipse2D.Double(two.getX() - 6,
two.getY() - 5, 10, 10);
// draw a circle at point two
g2.draw(circle1);
g2.fill(circle1);
g2.draw(circle2);
g2.fill(circle2);
// draw a line connecting the points
final Line2D line = new Line2D.Double(one, two);
if (this.stroke != null) {
g2.setStroke(this.stroke);
g2.draw(line);
}
}
/**
* Returns a list cell renderer for the stroke, so the sample can be
* displayed in a list or combo.
*
* @param list the list.
* @param value the value.
* @param index the index.
* @param isSelected selected?
* @param cellHasFocus focussed?
*
* @return the component for rendering.
*/
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (value instanceof Stroke) {
setStroke((Stroke) value);
}
else {
setStroke(null);
}
return this;
}
}
A dashed stroke
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new MyComponent());
frame.setSize(300, 300);
frame.setVisible(true);
}
}
class MyComponent extends JComponent {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
float strokeThickness = 5.0f;
float miterLimit = 10f;
float[] dashPattern = { 10f };
float dashPhase = 5f;
BasicStroke stroke = new BasicStroke(strokeThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
miterLimit, dashPattern, dashPhase);
g2d.setStroke(stroke);
g2d.draw(new Rectangle(20,20,200,200));
}
}
Basic stroke
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BasicStrokeDemo extends JPanel {
public void init() {
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(3.0f));
g2.setPaint(Color.blue);
Rectangle r = new Rectangle(5,5,200,200);
g2.draw(r);
}
public static void main(String s[]) {
JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
BasicStrokeDemo p = new BasicStrokeDemo();
f.getContentPane().add("Center", p);
p.init();
f.pack();
f.setSize(new Dimension(250, 250));
f.show();
}
}
Cancel the effects of the zoom on a particular Stroke
/*
* Java2DUtils.java
*
* Created on Aug 30, 2007, 11:40:18 AM
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
//Revised from jaspersoft ireport designer
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.util.Stack;
/**
*
* @author gtoffoli
*/
public class Java2DUtils
{
/**
* This function provides a way to cancel the effects of the zoom on a particular Stroke.
* All the stroke values (as line width, dashes, etc...) are divided by the zoom factor.
* This allow to have essentially a fixed Stroke independent by the zoom.
* The returned Stroke is a copy.
* Remember to restore the right stroke in the graphics when done.
*
* It works only with instances of BasicStroke
*
* zoom is the zoom factor.
*/
public static Stroke getInvertedZoomedStroke(Stroke stroke, double zoom)
{
if (stroke == null || !(stroke instanceof BasicStroke )) return stroke;
BasicStroke bs = (BasicStroke)stroke;
float[] dashArray = bs.getDashArray();
float[] newDashArray = null;
if (dashArray != null)
{
newDashArray = new float[dashArray.length];
for (int i=0; i<newDashArray.length; ++i)
{
newDashArray[i] = (float)(dashArray[i] / zoom);
}
}
BasicStroke newStroke = new BasicStroke(
(float)(bs.getLineWidth() / zoom),
bs.getEndCap(),
bs.getLineJoin(),
bs.getMiterLimit(),
//(float)(bs.getMiterLimit() / zoom),
newDashArray,
(float)(bs.getDashPhase() / zoom)
);
return newStroke;
}
}
Changing the Thickness of the Stroking Pen
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
public static void main(String[] args) {
new BasicDraw();
}
BasicDraw() {
JFrame frame = new JFrame();
frame.add(new MyComponent());
frame.setSize(300, 300);
frame.setVisible(true);
}
}
class MyComponent extends JComponent {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
float strokeThickness = 5.0f;
BasicStroke stroke = new BasicStroke(strokeThickness);
g2d.setStroke(stroke);
g2d.draw(new Rectangle(20,20,200,200));
}
}
Custom Strokes
/*
* Copyright (c) 2000 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 2nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book (recommended),
* visit http://www.davidflanagan.ru/javaexamples2.
*/
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.GlyphVector;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** A demonstration of writing custom Stroke classes */
public class CustomStrokes extends JPanel{
static final int WIDTH = 750, HEIGHT = 200; // Size of our example
public String getName() {
return "Custom Strokes";
}
public int getWidth() {
return WIDTH;
}
public int getHeight() {
return HEIGHT;
}
// These are the various stroke objects we"ll demonstrate
Stroke[] strokes = new Stroke[] { new BasicStroke(4.0f), // The standard,
// predefined
// stroke
new NullStroke(), // A Stroke that does nothing
new DoubleStroke(8.0f, 2.0f), // A Stroke that strokes twice
new ControlPointsStroke(2.0f), // Shows the vertices & control
// points
new SloppyStroke(2.0f, 3.0f) // Perturbs the shape before stroking
};
/** Draw the example */
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D)g1;
// Get a shape to work with. Here we"ll use the letter B
Font f = new Font("Serif", Font.BOLD, 200);
GlyphVector gv = f.createGlyphVector(g.getFontRenderContext(), "B");
Shape shape = gv.getOutline();
// Set drawing attributes and starting position
g.setColor(Color.black);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.translate(10, 175);
// Draw the shape once with each stroke
for (int i = 0; i < strokes.length; i++) {
g.setStroke(strokes[i]); // set the stroke
g.draw(shape); // draw the shape
g.translate(140, 0); // move to the right
}
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setContentPane(new CustomStrokes());
f.setSize(750,200);
f.setVisible(true);
}
}
/**
* This Stroke implementation does nothing. Its createStrokedShape() method
* returns an unmodified shape. Thus, drawing a shape with this Stroke is the
* same as filling that shape!
*/
class NullStroke implements Stroke {
public Shape createStrokedShape(Shape s) {
return s;
}
}
/**
* This Stroke implementation applies a BasicStroke to a shape twice. If you
* draw with this Stroke, then instead of outlining the shape, you"re outlining
* the outline of the shape.
*/
class DoubleStroke implements Stroke {
BasicStroke stroke1, stroke2; // the two strokes to use
public DoubleStroke(float width1, float width2) {
stroke1 = new BasicStroke(width1); // Constructor arguments specify
stroke2 = new BasicStroke(width2); // the line widths for the strokes
}
public Shape createStrokedShape(Shape s) {
// Use the first stroke to create an outline of the shape
Shape outline = stroke1.createStrokedShape(s);
// Use the second stroke to create an outline of that outline.
// It is this outline of the outline that will be filled in
return stroke2.createStrokedShape(outline);
}
}
/**
* This Stroke implementation strokes the shape using a thin line, and also
* displays the end points and Bezier curve control points of all the line and
* curve segments that make up the shape. The radius argument to the constructor
* specifies the size of the control point markers. Note the use of PathIterator
* to break the shape down into its segments, and of GeneralPath to build up the
* stroked shape.
*/
class ControlPointsStroke implements Stroke {
float radius; // how big the control point markers should be
public ControlPointsStroke(float radius) {
this.radius = radius;
}
public Shape createStrokedShape(Shape shape) {
// Start off by stroking the shape with a thin line. Store the
// resulting shape in a GeneralPath object so we can add to it.
GeneralPath strokedShape = new GeneralPath(new BasicStroke(1.0f)
.createStrokedShape(shape));
// Use a PathIterator object to iterate through each of the line and
// curve segments of the shape. For each one, mark the endpoint and
// control points (if any) by adding a rectangle to the GeneralPath
float[] coords = new float[6];
for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i
.next()) {
int type = i.currentSegment(coords);
Shape s = null, s2 = null, s3 = null;
switch (type) {
case PathIterator.SEG_CUBICTO:
markPoint(strokedShape, coords[4], coords[5]); // falls through
case PathIterator.SEG_QUADTO:
markPoint(strokedShape, coords[2], coords[3]); // falls through
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
markPoint(strokedShape, coords[0], coords[1]); // falls through
case PathIterator.SEG_CLOSE:
break;
}
}
return strokedShape;
}
/** Add a small square centered at (x,y) to the specified path */
void markPoint(GeneralPath path, float x, float y) {
path.moveTo(x - radius, y - radius); // Begin a new sub-path
path.lineTo(x + radius, y - radius); // Add a line segment to it
path.lineTo(x + radius, y + radius); // Add a second line segment
path.lineTo(x - radius, y + radius); // And a third
path.closePath(); // Go back to last moveTo position
}
}
/**
* This Stroke implementation randomly perturbs the line and curve segments that
* make up a Shape, and then strokes that perturbed shape. It uses PathIterator
* to loop through the Shape and GeneralPath to build up the modified shape.
* Finally, it uses a BasicStroke to stroke the modified shape. The result is a
* "sloppy" looking shape.
*/
class SloppyStroke implements Stroke {
BasicStroke stroke;
float sloppiness;
public SloppyStroke(float width, float sloppiness) {
this.stroke = new BasicStroke(width); // Used to stroke modified shape
this.sloppiness = sloppiness; // How sloppy should we be?
}
public Shape createStrokedShape(Shape shape) {
GeneralPath newshape = new GeneralPath(); // Start with an empty shape
// Iterate through the specified shape, perturb its coordinates, and
// use them to build up the new shape.
float[] coords = new float[6];
for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i
.next()) {
int type = i.currentSegment(coords);
switch (type) {
case PathIterator.SEG_MOVETO:
perturb(coords, 2);
newshape.moveTo(coords[0], coords[1]);
break;
case PathIterator.SEG_LINETO:
perturb(coords, 2);
newshape.lineTo(coords[0], coords[1]);
break;
case PathIterator.SEG_QUADTO:
perturb(coords, 4);
newshape.quadTo(coords[0], coords[1], coords[2], coords[3]);
break;
case PathIterator.SEG_CUBICTO:
perturb(coords, 6);
newshape.curveTo(coords[0], coords[1], coords[2], coords[3],
coords[4], coords[5]);
break;
case PathIterator.SEG_CLOSE:
newshape.closePath();
break;
}
}
// Finally, stroke the perturbed shape and return the result
return stroke.createStrokedShape(newshape);
}
// Randomly modify the specified number of coordinates, by an amount
// specified by the sloppiness field.
void perturb(float[] coords, int numCoords) {
for (int i = 0; i < numCoords; i++)
coords[i] += (float) ((Math.random() * 2 - 1.0) * sloppiness);
}
}
Dashed rectangle
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class DashedRectangleDemo2D extends JApplet {
final static float dash1[] = { 10.0f };
final static BasicStroke dashed = new BasicStroke(1.0f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
public void init() {
setBackground(Color.white);
setForeground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.gray);
int x = 5;
int y = 7;
g2.setStroke(dashed);
g2.draw(new RoundRectangle2D.Double(x, y, 200, 200,
10, 10));
g2.drawString("RoundRectangle2D", x, 250);
}
public static void main(String s[]) {
JFrame f = new JFrame("");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet applet = new DashedRectangleDemo2D();
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(300, 300));
f.show();
}
}
Dashed stroke
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DashedStrokeDemo extends JPanel {
public void init() {
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
float dash[] = { 10.0f };
g2.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f));
g2.setPaint(Color.blue);
Rectangle r = new Rectangle(5,5,200,200);
g2.draw(r);
}
public static void main(String s[]) {
JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
DashedStrokeDemo p = new DashedStrokeDemo();
f.getContentPane().add("Center", p);
p.init();
f.pack();
f.setSize(new Dimension(250, 250));
f.show();
}
}
Serialises a Stroke object
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* IOUtils.java
* ------------
* (C)opyright 2002-2004, by Thomas Morgner and Contributors.
*
* Original Author: Thomas Morgner;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: IOUtils.java,v 1.8 2009/01/22 08:34:58 taqua Exp $
*
* Changes
* -------
* 26-Jan-2003 : Initial version
* 23-Feb-2003 : Documentation
* 25-Feb-2003 : Fixed Checkstyle issues (DG);
* 29-Apr-2003 : Moved to jcommon
* 04-Jan-2004 : Fixed JDK 1.2.2 issues with createRelativeURL;
* added support for query strings within these urls (TM);
*/
public class Main {
/**
* Returns <code>true</code> if a class implements <code>Serializable</code>
* and <code>false</code> otherwise.
*
* @param c the class.
*
* @return A boolean.
*/
public static boolean isSerializable(final Class c) {
/**
final Class[] interfaces = c.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].equals(Serializable.class)) {
return true;
}
}
Class cc = c.getSuperclass();
if (cc != null) {
return isSerializable(cc);
}
*/
return (Serializable.class.isAssignableFrom(c));
}
/**
* Reads a <code>Stroke</code> object that has been serialised by the
* {@link SerialUtilities#writeStroke(Stroke, ObjectOutputStream)} method.
*
* @param stream the input stream (<code>null</code> not permitted).
*
* @return The stroke object (possibly <code>null</code>).
*
* @throws IOException if there is an I/O problem.
* @throws ClassNotFoundException if there is a problem loading a class.
*/
public static Stroke readStroke(final ObjectInputStream stream)
throws IOException, ClassNotFoundException {
if (stream == null) {
throw new IllegalArgumentException("Null "stream" argument.");
}
Stroke result = null;
final boolean isNull = stream.readBoolean();
if (!isNull) {
final Class c = (Class) stream.readObject();
if (c.equals(BasicStroke.class)) {
final float width = stream.readFloat();
final int cap = stream.readInt();
final int join = stream.readInt();
final float miterLimit = stream.readFloat();
final float[] dash = (float[]) stream.readObject();
final float dashPhase = stream.readFloat();
result = new BasicStroke(
width, cap, join, miterLimit, dash, dashPhase
);
}
else {
result = (Stroke) stream.readObject();
}
}
return result;
}
/**
* Serialises a <code>Stroke</code> object. This code handles the
* <code>BasicStroke</code> class which is the only <code>Stroke</code>
* implementation provided by the JDK (and isn"t directly
* <code>Serializable</code>).
*
* @param stroke the stroke object (<code>null</code> permitted).
* @param stream the output stream (<code>null</code> not permitted).
*
* @throws IOException if there is an I/O error.
*/
public static void writeStroke(final Stroke stroke,
final ObjectOutputStream stream)
throws IOException {
if (stream == null) {
throw new IllegalArgumentException("Null "stream" argument.");
}
if (stroke != null) {
stream.writeBoolean(false);
if (stroke instanceof BasicStroke) {
final BasicStroke s = (BasicStroke) stroke;
stream.writeObject(BasicStroke.class);
stream.writeFloat(s.getLineWidth());
stream.writeInt(s.getEndCap());
stream.writeInt(s.getLineJoin());
stream.writeFloat(s.getMiterLimit());
stream.writeObject(s.getDashArray());
stream.writeFloat(s.getDashPhase());
}
else {
stream.writeObject(stroke.getClass());
stream.writeObject(stroke);
}
}
else {
stream.writeBoolean(true);
}
}
}
Smokey effect
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Overlap extends JPanel {
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new Overlap());
f.setSize(300, 200);
f.setVisible(true);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
double x = 15, y = 50, w = 70, h = 70;
Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
g2.setStroke(new BasicStroke(8));
Color smokeyColor = new Color(128, 128, 128, 128);
g2.setPaint(smokeyColor);
g2.fill(e);
g2.draw(e);
e.setFrame(x + 100, y, w, h);
g2.setPaint(Color.black);
g2.draw(e);
g2.setPaint(Color.gray);
g2.fill(e);
e.setFrame(x + 200, y, w, h);
g2.setPaint(Color.gray);
g2.fill(e);
g2.setPaint(Color.black);
g2.draw(e);
}
}
Stroke with iron effect
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PaintingAndStroking extends JPanel{
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
double x = 15, y = 50, w = 70, h = 70;
Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
GradientPaint gp = new GradientPaint(75, 75, Color.white, 95, 95,
Color.gray, true);
// Fill with a gradient.
g2.setPaint(gp);
g2.fill(e);
// Stroke with a solid color.
e.setFrame(x + 100, y, w, h);
g2.setPaint(Color.black);
g2.setStroke(new BasicStroke(8));
g2.draw(e);
// Stroke with a gradient.
e.setFrame(x + 200, y, w, h);
g2.setPaint(gp);
g2.draw(e);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new PaintingAndStroking());
f.setSize(350, 250);
f.show();
}
}
Stroking or Filling with a Texture
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new MyComponent());
frame.setSize(300, 300);
frame.setVisible(true);
}
}
class MyComponent extends JComponent {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int x = 10;
int y = 10;
int width = 50;
int height = 25;
BufferedImage bi = new BufferedImage(20,20,BufferedImage.TYPE_INT_RGB);
TexturePaint texture = new TexturePaint(bi, new Rectangle(x, y, width, height));
g2d.setPaint(texture);
}
}
Thick stroke demo
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThickStrokeDemo extends JPanel {
public void init() {
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(8.0f));
g2.setPaint(Color.blue);
Rectangle r = new Rectangle(5,5,200,200);
g2.draw(r);
}
public static void main(String s[]) {
JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
ThickStrokeDemo p = new ThickStrokeDemo();
f.getContentPane().add("Center", p);
p.init();
f.pack();
f.setSize(new Dimension(250, 250));
f.show();
}
}
Tries to deduct the stroke-type from the given stroke object.
/**
*
* JFreeReport : a free Java reporting library
*
*
* Project Info: http://reporting.pentaho.org/
*
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* StrokeUtility.java
* ------------
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*/
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.util.Arrays;
/**
* This class provides helper methods to work with Strokes and line-styles.
*
* @author Thomas Morgner
*/
public class StrokeUtility {
/** A constant defining a stroke-type. */
public static final int STROKE_SOLID = 0;
/** A constant defining a stroke-type. */
public static final int STROKE_DASHED = 1;
/** A constant defining a stroke-type. */
public static final int STROKE_DOTTED = 2;
/** A constant defining a stroke-type. */
public static final int STROKE_DOT_DASH = 3;
/** A constant defining a stroke-type. */
public static final int STROKE_DOT_DOT_DASH = 4;
/** A constant defining a stroke-type. */
public static final int STROKE_NONE = 5;
/**
* Default Constructor. Private to prevent Object-creation.
*/
private StrokeUtility() {
}
/**
* Creates a new Stroke-Object for the given type and with.
*
* @param type
* the stroke-type. (Must be one of the constants defined in this
* class.)
* @param width
* the stroke"s width.
* @return the stroke, never null.
*/
public static Stroke createStroke(final int type, final float width) {
final boolean useWidthForStrokes = true;
final float effectiveWidth;
if (useWidthForStrokes) {
effectiveWidth = width;
} else {
effectiveWidth = 1;
}
switch (type) {
case STROKE_DASHED:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
new float[] { 6 * effectiveWidth, 6 * effectiveWidth }, 0.0f);
case STROKE_DOTTED:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 5.0f,
new float[] { 0.0f, 2 * effectiveWidth }, 0.0f);
case STROKE_DOT_DASH:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
new float[] { 0, 2 * effectiveWidth, 6 * effectiveWidth, 2 * effectiveWidth }, 0.0f);
case STROKE_DOT_DOT_DASH:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
new float[] { 0, 2 * effectiveWidth, 0, 2 * effectiveWidth, 6 * effectiveWidth,
2 * effectiveWidth }, 0.0f);
default:
return new BasicStroke(width);
}
}
/**
* Tries to extract the stroke-width from the given stroke object.
*
* @param s
* the stroke.
* @return the stroke"s width.
*/
public static float getStrokeWidth(final Stroke s) {
if (s instanceof BasicStroke) {
final BasicStroke bs = (BasicStroke) s;
return bs.getLineWidth();
}
return 1;
}
/**
* Tries to deduct the stroke-type from the given stroke object. This will
* result in funny return values if the stroke was not created by the
* {@link #createStroke(int, float)} method.
*
* @param s
* the stroke.
* @return the stroke"s width.
*/
public static int getStrokeType(final Stroke s) {
if (s instanceof BasicStroke == false) {
return STROKE_SOLID;
}
final BasicStroke bs = (BasicStroke) s;
if (bs.getLineWidth() <= 0) {
return STROKE_NONE;
}
final float[] dashes = bs.getDashArray();
if (dashes == null) {
return STROKE_SOLID;
}
if (dashes.length < 2) {
return STROKE_SOLID;
}
if (dashes.length == 3 || dashes.length == 5) {
return STROKE_SOLID;
}
if (dashes.length == 2) {
// maybe dashed or dotted ...
// if (dashes[0] < 2 && dashes[1] < 2) {
// return STROKE_DOTTED;
// }
final float factor = dashes[0] / dashes[1];
if (factor > 0.9 && factor < 1.1) {
return STROKE_DASHED;
} else if (factor < 0.1) {
return STROKE_DOTTED;
}
// else ... not recognized ...
return STROKE_SOLID;
} else if (dashes.length == 4) {
// maybe a dot-dashed stroke ...
final float[] copyDashes = (float[]) dashes.clone();
Arrays.sort(copyDashes);
// the first value should be near zero ..
if (Math.abs(copyDashes[0] / bs.getLineWidth()) > 0.5) {
// not recognized ..
return STROKE_SOLID;
}
// test that the first two values have the same size
final float factor1 = (2 * bs.getLineWidth()) / copyDashes[1];
final float factor2 = (2 * bs.getLineWidth()) / copyDashes[2];
final float factorBig = (2 * bs.getLineWidth()) / copyDashes[3];
if ((factor1 < 0.9 || factor1 > 1.1) || (factor2 < 0.9 || factor2 > 1.1)) {
// not recognized ...
return STROKE_SOLID;
}
if (factorBig < 0.4 || factorBig > 2.5) {
return STROKE_DOT_DASH;
}
if (factorBig < 0.9 || factorBig > 1.1) {
return STROKE_DOTTED;
}
return STROKE_DASHED;
} else if (dashes.length == 6) {
// maybe a dot-dashed stroke ...
final float[] copyDashes = (float[]) dashes.clone();
Arrays.sort(copyDashes);
// test that the first three values have the same size
// the first two values should be near zero ..
if (Math.abs(copyDashes[0] / bs.getLineWidth()) > 0.5) {
// not recognized ..
return STROKE_SOLID;
}
if (Math.abs(copyDashes[1] / bs.getLineWidth()) > 0.5) {
// not recognized ..
return STROKE_SOLID;
}
final float factor2 = (2 * bs.getLineWidth()) / copyDashes[2];
final float factor3 = (2 * bs.getLineWidth()) / copyDashes[3];
final float factor4 = (2 * bs.getLineWidth()) / copyDashes[4];
final float factorBig = (2 * bs.getLineWidth()) / copyDashes[5];
if ((factor2 < 0.9 || factor2 > 1.1) || (factor3 < 0.9 || factor3 > 1.1)
|| (factor4 < 0.9 || factor4 > 1.1)) {
return STROKE_SOLID;
}
if (factorBig < 0.4 || factorBig > 2.5) {
return STROKE_DOT_DOT_DASH;
}
if ((factorBig < 0.9 || factorBig > 1.1)) {
return STROKE_DOTTED;
}
return STROKE_DASHED;
}
// not recognized ...
return STROKE_SOLID;
}
}
Tries to extract the stroke-width from the given stroke object.
/**
*
* JFreeReport : a free Java reporting library
*
*
* Project Info: http://reporting.pentaho.org/
*
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* StrokeUtility.java
* ------------
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*/
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.util.Arrays;
/**
* This class provides helper methods to work with Strokes and line-styles.
*
* @author Thomas Morgner
*/
public class StrokeUtility {
/** A constant defining a stroke-type. */
public static final int STROKE_SOLID = 0;
/** A constant defining a stroke-type. */
public static final int STROKE_DASHED = 1;
/** A constant defining a stroke-type. */
public static final int STROKE_DOTTED = 2;
/** A constant defining a stroke-type. */
public static final int STROKE_DOT_DASH = 3;
/** A constant defining a stroke-type. */
public static final int STROKE_DOT_DOT_DASH = 4;
/** A constant defining a stroke-type. */
public static final int STROKE_NONE = 5;
/**
* Default Constructor. Private to prevent Object-creation.
*/
private StrokeUtility() {
}
/**
* Creates a new Stroke-Object for the given type and with.
*
* @param type
* the stroke-type. (Must be one of the constants defined in this
* class.)
* @param width
* the stroke"s width.
* @return the stroke, never null.
*/
public static Stroke createStroke(final int type, final float width) {
final boolean useWidthForStrokes = true;
final float effectiveWidth;
if (useWidthForStrokes) {
effectiveWidth = width;
} else {
effectiveWidth = 1;
}
switch (type) {
case STROKE_DASHED:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
new float[] { 6 * effectiveWidth, 6 * effectiveWidth }, 0.0f);
case STROKE_DOTTED:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 5.0f,
new float[] { 0.0f, 2 * effectiveWidth }, 0.0f);
case STROKE_DOT_DASH:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
new float[] { 0, 2 * effectiveWidth, 6 * effectiveWidth, 2 * effectiveWidth }, 0.0f);
case STROKE_DOT_DOT_DASH:
return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
new float[] { 0, 2 * effectiveWidth, 0, 2 * effectiveWidth, 6 * effectiveWidth,
2 * effectiveWidth }, 0.0f);
default:
return new BasicStroke(width);
}
}
/**
* Tries to extract the stroke-width from the given stroke object.
*
* @param s
* the stroke.
* @return the stroke"s width.
*/
public static float getStrokeWidth(final Stroke s) {
if (s instanceof BasicStroke) {
final BasicStroke bs = (BasicStroke) s;
return bs.getLineWidth();
}
return 1;
}
/**
* Tries to deduct the stroke-type from the given stroke object. This will
* result in funny return values if the stroke was not created by the
* {@link #createStroke(int, float)} method.
*
* @param s
* the stroke.
* @return the stroke"s width.
*/
public static int getStrokeType(final Stroke s) {
if (s instanceof BasicStroke == false) {
return STROKE_SOLID;
}
final BasicStroke bs = (BasicStroke) s;
if (bs.getLineWidth() <= 0) {
return STROKE_NONE;
}
final float[] dashes = bs.getDashArray();
if (dashes == null) {
return STROKE_SOLID;
}
if (dashes.length < 2) {
return STROKE_SOLID;
}
if (dashes.length == 3 || dashes.length == 5) {
return STROKE_SOLID;
}
if (dashes.length == 2) {
// maybe dashed or dotted ...
// if (dashes[0] < 2 && dashes[1] < 2) {
// return STROKE_DOTTED;
// }
final float factor = dashes[0] / dashes[1];
if (factor > 0.9 && factor < 1.1) {
return STROKE_DASHED;
} else if (factor < 0.1) {
return STROKE_DOTTED;
}
// else ... not recognized ...
return STROKE_SOLID;
} else if (dashes.length == 4) {
// maybe a dot-dashed stroke ...
final float[] copyDashes = (float[]) dashes.clone();
Arrays.sort(copyDashes);
// the first value should be near zero ..
if (Math.abs(copyDashes[0] / bs.getLineWidth()) > 0.5) {
// not recognized ..
return STROKE_SOLID;
}
// test that the first two values have the same size
final float factor1 = (2 * bs.getLineWidth()) / copyDashes[1];
final float factor2 = (2 * bs.getLineWidth()) / copyDashes[2];
final float factorBig = (2 * bs.getLineWidth()) / copyDashes[3];
if ((factor1 < 0.9 || factor1 > 1.1) || (factor2 < 0.9 || factor2 > 1.1)) {
// not recognized ...
return STROKE_SOLID;
}
if (factorBig < 0.4 || factorBig > 2.5) {
return STROKE_DOT_DASH;
}
if (factorBig < 0.9 || factorBig > 1.1) {
return STROKE_DOTTED;
}
return STROKE_DASHED;
} else if (dashes.length == 6) {
// maybe a dot-dashed stroke ...
final float[] copyDashes = (float[]) dashes.clone();
Arrays.sort(copyDashes);
// test that the first three values have the same size
// the first two values should be near zero ..
if (Math.abs(copyDashes[0] / bs.getLineWidth()) > 0.5) {
// not recognized ..
return STROKE_SOLID;
}
if (Math.abs(copyDashes[1] / bs.getLineWidth()) > 0.5) {
// not recognized ..
return STROKE_SOLID;
}
final float factor2 = (2 * bs.getLineWidth()) / copyDashes[2];
final float factor3 = (2 * bs.getLineWidth()) / copyDashes[3];
final float factor4 = (2 * bs.getLineWidth()) / copyDashes[4];
final float factorBig = (2 * bs.getLineWidth()) / copyDashes[5];
if ((factor2 < 0.9 || factor2 > 1.1) || (factor3 < 0.9 || factor3 > 1.1)
|| (factor4 < 0.9 || factor4 > 1.1)) {
return STROKE_SOLID;
}
if (factorBig < 0.4 || factorBig > 2.5) {
return STROKE_DOT_DOT_DASH;
}
if ((factorBig < 0.9 || factorBig > 1.1)) {
return STROKE_DOTTED;
}
return STROKE_DASHED;
}
// not recognized ...
return STROKE_SOLID;
}
}