Java/2D Graphics GUI/Text Layout
Содержание
- 1 A display of text, formatted by us instead of by AWT/Swing
- 2 Another Line Break Demo
- 3 Caret action
- 4 Caret and TextLayout
- 5 Drawing a Paragraph of Text
- 6 Drawing multi-line text with AttributedString and LineBreakMeasurer
- 7 Drawing Text with Mixed Styles
- 8 Draws the string at the specified location underlining the specified character
- 9 Draw text with TextLayout
- 10 Getting the Shape from the Outline of Text
- 11 Hightlight text by drag and selection
- 12 JFreeChart: Draw String Demo
- 13 Line break for textlayout
- 14 LineMetrics: the metrics to layout characters along a line
- 15 Mouse hit and textlayout
- 16 Paragraph Layout
- 17 Renders a paragraph of text (line breaks ignored) to an image (created and returned).
- 18 TextAttribute: color and font
- 19 TextAttribute: Underline and strike through
- 20 TextHitInfo Demo: tell you which is the letter you are clicking
- 21 TextLayout demo
- 22 Unicode display
- 23 Unicode: test layout
A display of text, formatted by us instead of by AWT/Swing
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
* All rights reserved. Software written by Ian F. Darwin and others.
* $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
* cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
* pioneering role in inventing and promulgating (and standardizing) the Java
* language and environment is gratefully acknowledged.
*
* The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
* inventing predecessor languages C and C++ is also gratefully acknowledged.
*/
import java.awt.ruponent;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JFrame;
/**
* A display of text, formatted by us instead of by AWT/Swing.
* <P>
* This program is distributed under the terms of the accompanying COPYRIGHT.txt
* file (which is NOT the GNU General Public License). Please read it. Your use
* of the software constitutes acceptance of the terms in the COPYRIGHT.txt
* file.
*
* @author Ian F. Darwin
* @version $Id: TextFormat.java,v 1.3 2004/03/26 03:34:30 ian Exp $
*/
public class TextFormat extends Component {
/** The text of this line */
protected String text;
/** The Font */
protected Font font;
/** The TextLayouts corresponding to "text" */
List layouts;
public Font getFont() {
return font;
}
public void setFont(Font f) {
font = f;
}
public String getText() {
return text;
}
public void setText(String t) {
text = t;
}
public void paint(Graphics g) {
if (text == null || text.length() == 0)
return;
if (layouts == null)
getLayouts(g);
Point pen = new Point(0, 0);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(java.awt.Color.black); // or a property
g2d.setFont(font);
Iterator it = layouts.iterator();
while (it.hasNext()) {
TextLayout layout = (TextLayout) it.next();
pen.y += (layout.getAscent());
g2d.setFont(font);
layout.draw(g2d, pen.x, pen.y);
pen.y += layout.getDescent();
//pen.y += leading;
}
}
/**
* Lazy evaluation of the List of TextLayout objects corresponding to this
* MText. Some things are approximations!
*/
private void getLayouts(Graphics g) {
layouts = new ArrayList();
Point pen = new Point(10, 20);
Graphics2D g2d = (Graphics2D) g;
FontRenderContext frc = g2d.getFontRenderContext();
AttributedString attrStr = new AttributedString(text);
attrStr.addAttribute(TextAttribute.FONT, font, 0, text.length());
LineBreakMeasurer measurer = new LineBreakMeasurer(attrStr
.getIterator(), frc);
float wrappingWidth;
wrappingWidth = getSize().width - 15;
while (measurer.getPosition() < text.length()) {
TextLayout layout = measurer.nextLayout(wrappingWidth);
layouts.add(layout);
}
}
public static void main(String[] args) {
JFrame jf = new JFrame("Demo");
Container cp = jf.getContentPane();
TextFormat tl = new TextFormat();
tl.setFont(new Font("SansSerif", Font.BOLD, 42));
tl.setText("The quick brown fox jumped over the lazy cow");
cp.add(tl);
jf.setSize(300, 200);
jf.setVisible(true);
}
}
Another Line Break Demo
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
String text = "this is a test. This is a test. This is a test. This is a test";
AttributedString attribString = new AttributedString(text);
AttributedCharacterIterator attribCharIterator;
public Main() {
setSize(350, 400);
attribString.addAttribute(TextAttribute.FOREGROUND, Color.blue, 0, text
.length());
attribString.addAttribute(TextAttribute.FONT, new Font("sanserif", Font.ITALIC, 20),
0, text.length());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
attribCharIterator = attribString.getIterator();
FontRenderContext frc = new FontRenderContext(null, false, false);
LineBreakMeasurer lbm = new LineBreakMeasurer(attribCharIterator, frc);
int x = 10, y = 20;
int w = getWidth();
float wrappingWidth = w - 15;
while (lbm.getPosition() < text.length()) {
TextLayout layout = lbm.nextLayout(wrappingWidth);
y += layout.getAscent();
layout.draw(g2, x, y);
y += layout.getDescent() + layout.getLeading();
}
}
public static void main(String arg[]) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add("Center", new Main());
frame.pack();
frame.setSize(new Dimension(350, 400));
frame.setVisible(true);
}
}
Caret action
import java.awt.BasicStroke;
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.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class TextLayoutWithCarets extends JLabel {
private TextHitInfo mHit;
private TextLayout mLayout;
private boolean mInitialized = false;
public TextLayoutWithCarets() {
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_RIGHT) {
mHit = mLayout.getNextRightHit(mHit.getInsertionIndex());
if (mHit == null)
mHit = mLayout.getNextLeftHit(1);
repaint();
} else if (ke.getKeyCode() == KeyEvent.VK_LEFT) {
mHit = mLayout.getNextLeftHit(mHit.getInsertionIndex());
if (mHit == null)
mHit = mLayout.getNextRightHit(mLayout
.getCharacterCount() - 1);
repaint();
}
}
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
}
private void initialize(Graphics2D g2) {
String s = "Java Source and Support.";
// Create a plain and italic font.
int fontSize = 32;
Font font = new Font("Lucida Sans Regular", Font.PLAIN, fontSize);
Font italicFont = new Font("Lucida Sans Oblique", Font.ITALIC, fontSize);
// Create an Attributed String
AttributedString as = new AttributedString(s);
as.addAttribute(TextAttribute.FONT, font);
as.addAttribute(TextAttribute.FONT, italicFont, 2, 5);
// Get the iterator.
AttributedCharacterIterator iterator = as.getIterator();
// Create a TextLayout.
FontRenderContext frc = g2.getFontRenderContext();
mLayout = new TextLayout(iterator, frc);
mHit = mLayout.getNextLeftHit(1);
// Respond to left and right arrow keys.
mInitialized = true;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
if (mInitialized == false)
initialize(g2);
float x = 20, y = 80;
mLayout.draw(g2, x, y);
// Create a plain stroke and a dashed stroke.
Stroke[] caretStrokes = new Stroke[2];
caretStrokes[0] = new BasicStroke();
caretStrokes[1] = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_ROUND, 0, new float[] { 4, 4 }, 0);
// Now draw the carets
Shape[] carets = mLayout.getCaretShapes(mHit.getInsertionIndex());
for (int i = 0; i < carets.length; i++) {
if (carets[i] != null) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
Shape shape = at.createTransformedShape(carets[i]);
g2.setStroke(caretStrokes[i]);
g2.draw(shape);
}
}
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new TextLayoutWithCarets());
f.setSize(350, 250);
f.setVisible(true);
}
}
Caret and TextLayout
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TextLayoutPanel extends JPanel {
TextLayout layout;
FontRenderContext frc;
Font font;
Rectangle2D rect;
float rx, ry, rw, rh;
TextHitInfo hitInfo;
Color caretColor;
int hit1, hit2;
int w, h;
public TextLayoutPanel() {
setBackground(Color.white);
setForeground(Color.black);
setSize(400, 200);
addMouseListener(new MouseHandler());
addMouseMotionListener(new MouseMotionHandler());
w = getWidth();
h = getHeight();
String text = "Java Source and Support";
font = new Font("Arial", Font.PLAIN, 36);
frc = new FontRenderContext(null, false, false);
layout = new TextLayout(text, font, frc);
rx = (float) (w / 2 - layout.getBounds().getWidth() / 2);
ry = (float) 3 * h / 4;
rw = (float) (layout.getBounds().getWidth());
rh = (float) (layout.getBounds().getHeight());
rect = new Rectangle2D.Float(rx, ry, rw, rh);
caretColor = getForeground();
}
public void update(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
paintComponent(g);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = AffineTransform.getTranslateInstance(rx, ry);
Shape hilight = layout.getLogicalHighlightShape(hit1, hit2);
hilight = at.createTransformedShape(hilight);
g2.setColor(Color.lightGray);
g2.fill(hilight);
g2.setColor(Color.black);
layout.draw(g2, rx, ry);
// Draw caret
Shape[] caretShapes = layout.getCaretShapes(hit1);
Shape caret = at.createTransformedShape(caretShapes[0]);
g2.setColor(caretColor);
g2.draw(caret);
}
public int getHitLocation(int mouseX, int mouseY) {
hitInfo = layout.hitTestChar(mouseX, mouseY, rect);
return hitInfo.getInsertionIndex();
}
class MouseHandler extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
caretColor = getForeground();
hit1 = getHitLocation(e.getX(), e.getY());
hit2 = hit1;
repaint();
}
public void mousePressed(MouseEvent e) {
caretColor = getForeground();
hit1 = getHitLocation(e.getX(), e.getY());
hit2 = hit1;
repaint();
}
public void mouseReleased(MouseEvent e) {
hit2 = getHitLocation(e.getX(), e.getY());
repaint();
}
}
class MouseMotionHandler extends MouseMotionAdapter {
public void mouseDragged(MouseEvent e) {
caretColor = getBackground();
hit2 = getHitLocation(e.getX(), e.getY());
repaint();
}
}
public static void main(String arg[]) {
JFrame frame = new JFrame();
frame.setBackground(Color.white);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.getContentPane().add("Center", new TextLayoutPanel());
frame.pack();
frame.setSize(new Dimension(400, 300));
frame.setVisible(true);
}
}
Drawing a Paragraph of Text
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
drawParagraph(g2d, "adfasdfaf", 20);
}
void drawParagraph(Graphics2D g, String paragraph, float width) {
LineBreakMeasurer linebreaker = new LineBreakMeasurer(new AttributedString(paragraph)
.getIterator(), g.getFontRenderContext());
int y = 0;
while (linebreaker.getPosition() < paragraph.length()) {
TextLayout textLayout = linebreaker.nextLayout(width);
y += textLayout.getAscent();
textLayout.draw(g, 0, y);
y += textLayout.getDescent() + textLayout.getLeading();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Basic Shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Main());
frame.setSize(350, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Drawing multi-line text with AttributedString and LineBreakMeasurer
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.UIManager;
public class Main extends JFrame {
public void paint(Graphics g) {
String input = "this is a test.this is a test.this is a test.this is a test.";
AttributedString attributedString = new AttributedString(input);
attributedString.addAttribute(TextAttribute.FONT, (Font) UIManager
.get("Label.font"));
Color color = (Color) UIManager.get("Label.foreground");
attributedString.addAttribute(TextAttribute.FOREGROUND, color);
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
int width = getSize().width;
int x = 10;
int y = 30;
AttributedCharacterIterator characterIterator = attributedString
.getIterator();
FontRenderContext fontRenderContext = g2d.getFontRenderContext();
LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator,
fontRenderContext);
while (measurer.getPosition() < characterIterator.getEndIndex()) {
TextLayout textLayout = measurer.nextLayout(width);
y += textLayout.getAscent();
textLayout.draw(g2d, x, y);
y += textLayout.getDescent() + textLayout.getLeading();
}
}
public static void main(String args[]) {
JFrame frame = new Main();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(20, 200);
frame.setVisible(true);
}
}
Drawing Text with Mixed Styles
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AttributedString astr = new AttributedString("aString");
astr.addAttribute(TextAttribute.FONT, new Font("", 1, 30), 1, 2);
astr.addAttribute(TextAttribute.BACKGROUND, Color.red, 2, 3);
TextLayout tl = new TextLayout(astr.getIterator(), g2d.getFontRenderContext());
tl.draw(g2d, 10, 20);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Basic Shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Main());
frame.setSize(350, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Draws the string at the specified location underlining the specified character
/*
* Copyright (c) 2001-2009 JGoodies Karsten Lentzsch. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of JGoodies Karsten Lentzsch nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.*;
import java.awt.print.PrinterGraphics;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.plaf.basic.BasicGraphicsUtils;
/**
* Provides convenience behavior used by the JGoodies Looks.<p>
*
* <strong>Note:</strong> This class is not part of the public Looks API.
* It should be treated as library internal and should not be used by
* API users. It may be removed or changed with the Looks version
* without further notice.
*
* @author Karsten Lentzsch
* @author Andrej Golovnin
* @version $Revision: 1.12 $
*
* @since 2.0
*/
public final class RenderingUtils {
private static final String PROP_DESKTOPHINTS = "awt.font.desktophints";
private static final String SWING_UTILITIES2_NAME ="sun.swing.SwingUtilities2";
/**
* In Java 5 or later, this field holds the public static method
* <code>SwingUtilities2#drawStringUnderlinedAt</code> that has been added
* for Java 5.
*/
private static Method drawStringUnderlineCharAtMethod = null;
static {
drawStringUnderlineCharAtMethod = getMethodDrawStringUnderlineCharAt();
}
private RenderingUtils() {
// Overrides default constructor; prevents instantiation.
}
/**
* Draws the string at the specified location underlining the specified
* character.
*
* @param c JComponent that will display the string, may be null
* @param g Graphics to draw the text to
* @param text String to display
* @param underlinedIndex Index of a character in the string to underline
* @param x X coordinate to draw the text at
* @param y Y coordinate to draw the text at
*/
public static void drawStringUnderlineCharAt(JComponent c,Graphics g,
String text, int underlinedIndex, int x,int y) {
if (drawStringUnderlineCharAtMethod != null) {
try {
drawStringUnderlineCharAtMethod.invoke(null,
new Object[] {c, g, text, new Integer(underlinedIndex),
new Integer(x), new Integer(y)});
return;
} catch (IllegalArgumentException e) {
// Use the BasicGraphicsUtils as fallback
} catch (IllegalAccessException e) {
// Use the BasicGraphicsUtils as fallback
} catch (InvocationTargetException e) {
// Use the BasicGraphicsUtils as fallback
}
}
Graphics2D g2 = (Graphics2D) g;
Map oldRenderingHints = installDesktopHints(g2);
BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, underlinedIndex, x, y);
if (oldRenderingHints != null) {
g2.addRenderingHints(oldRenderingHints);
}
return;
BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, underlinedIndex, x, y);
}
// Private Helper Code ****************************************************
private static Method getMethodDrawStringUnderlineCharAt() {
try {
Class clazz = Class.forName(SWING_UTILITIES2_NAME);
return clazz.getMethod(
"drawStringUnderlineCharAt",
new Class[] {JComponent.class, Graphics.class, String.class, Integer.TYPE, Integer.TYPE, Integer.TYPE}
);
} catch (ClassNotFoundException e) {
// returns null
} catch (SecurityException e) {
// returns null
} catch (NoSuchMethodException e) {
// returns null
}
return null;
}
private static Map installDesktopHints(Graphics2D g2) {
Map oldRenderingHints = null;
Map desktopHints = desktopHints(g2);
if (desktopHints != null && !desktopHints.isEmpty()) {
oldRenderingHints = new HashMap(desktopHints.size());
RenderingHints.Key key;
for (Iterator i = desktopHints.keySet().iterator(); i.hasNext();) {
key = (RenderingHints.Key) i.next();
oldRenderingHints.put(key, g2.getRenderingHint(key));
}
g2.addRenderingHints(desktopHints);
}
return oldRenderingHints;
}
private static Map desktopHints(Graphics2D g2) {
if (isPrinting(g2)) {
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
GraphicsDevice device = g2.getDeviceConfiguration().getDevice();
Map desktopHints = (Map) toolkit.getDesktopProperty(
PROP_DESKTOPHINTS + "." + device.getIDstring());
if (desktopHints == null) {
desktopHints = (Map) toolkit.getDesktopProperty(PROP_DESKTOPHINTS);
}
// It is possible to get a non-empty map but with disabled AA.
if (desktopHints != null) {
Object aaHint = desktopHints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
if ((aaHint == RenderingHints.VALUE_TEXT_ANTIALIAS_OFF) ||
(aaHint == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) {
desktopHints = null;
}
}
return desktopHints;
}
private static boolean isPrinting(Graphics g) {
return g instanceof PrintGraphics || g instanceof PrinterGraphics;
}
}
Draw text with TextLayout
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
public Main() {
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2D;
g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
FontRenderContext frc = g2D.getFontRenderContext();
Font font1 = new Font("Courier", Font.BOLD, 24);
String str1 = new String("Java");
TextLayout tl = new TextLayout(str1, font1, frc);
g2D.setColor(Color.gray);
tl.draw(g2D, 50, 150);
}
public static void main(String s[]) {
JFrame frame1 = new JFrame("2D Text");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.getContentPane().add("Center", new Main());
frame1.pack();
frame1.setSize(new Dimension(500, 300));
frame1.setVisible(true);
}
}
Getting the Shape from the Outline of Text
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.draw(getTextShape(g2d, "asdf", new Font("", 1, 30)));
}
public Shape getTextShape(Graphics2D g2d, String str, Font font) {
FontRenderContext frc = g2d.getFontRenderContext();
TextLayout tl = new TextLayout(str, font, frc);
return tl.getOutline(null);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Basic Shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Main());
frame.setSize(350, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Hightlight text by drag and selection
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.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.font.FontRenderContext;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Highlights extends JPanel {
private TextLayout textLayout;
private TextHitInfo firstHit, secondHit;
private int x = 40, y = 80;
public Highlights(){
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
firstHit = textLayout.hitTestChar(me.getX() - x, me.getY()
- y);
secondHit = null;
}
public void mouseReleased(MouseEvent me) {
secondHit = textLayout.hitTestChar(me.getX() - x, me.getY()
- y);
repaint();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent me) {
secondHit = textLayout.hitTestChar(me.getX() - x, me.getY()
- y);
repaint();
}
});
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
String s = "Drag the text to highlight Java Source and Support.";
Font font = new Font("Serif", Font.PLAIN, 32);
if (textLayout == null) {
FontRenderContext frc = g2.getFontRenderContext();
textLayout = new TextLayout(s, font, frc);
}
// Draw the highlight.
if (firstHit != null && secondHit != null) {
Shape base = textLayout.getLogicalHighlightShape(firstHit
.getInsertionIndex(), secondHit.getInsertionIndex());
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
Shape highlight = at.createTransformedShape(base);
g2.setPaint(Color.white);
g2.fill(highlight);
}
g2.setPaint(Color.black);
textLayout.draw(g2, x, y);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new Highlights());
f.setSize(850, 250);
f.show();
}
}
JFreeChart: Draw String Demo
/* ========================================================================
* JCommon : a free general purpose class library for the Java(tm) platform
* ========================================================================
*
* (C) Copyright 2000-2004, 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., 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.]
*
* -------------------
* DrawStringDemo.java
* -------------------
* (C) Copyright 2003, 2004, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: DrawStringDemo.java,v 1.3 2005/06/01 14:12:28 taqua Exp $
*
* Changes
* -------
* 10-Jun-2003 : Version 1;
*
*/
package org.jfree.demo;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.FontChooserPanel;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.Spinner;
import org.jfree.ui.TextAnchor;
/**
* A demo of some of the string drawing methods in the JCommon class library.
*
* @author David Gilbert
*/
public class DrawStringDemo extends ApplicationFrame
implements ActionListener, PropertyChangeListener {
/** The alignment anchor for the first panel. */
private JComboBox combo1;
/** The alignment anchor for the second panel. */
private JComboBox combo2;
/** The rotation anchor for the second panel. */
private JComboBox combo3;
/** A spinner for the second panel. */
private Spinner spinner;
/** String panel 1. */
private DrawStringPanel drawStringPanel1;
/** String panel 2. */
private DrawStringPanel drawStringPanel2;
/**
* Creates a new demo instance.
*
* @param title the frame title.
*/
public DrawStringDemo(final String title) {
super(title);
setContentPane(createContentPane());
}
/**
* Receives action events.
*
* @param event the event.
*/
public void actionPerformed(final ActionEvent event) {
if (event.getActionCommand().equals("fontButton.clicked")) {
displayFontDialog();
}
if (event.getActionCommand().equals("combo1.changed")) {
handleCombo1Change();
}
if (event.getActionCommand().equals("combo2.changed")) {
handleCombo2Change();
}
if (event.getActionCommand().equals("combo3.changed")) {
handleCombo3Change();
}
}
/**
* Receives property change events.
*
* @param event the event.
*/
public void propertyChange(final PropertyChangeEvent event) {
final int r = this.spinner.getValue();
final double angle = Math.PI * 2.0 * (r / 360.0);
this.drawStringPanel2.setAngle(angle);
this.drawStringPanel2.invalidate();
this.drawStringPanel2.repaint();
}
/**
* Updates the display when combo 1 is updated.
*/
private void handleCombo1Change() {
final String text = this.rubo1.getSelectedItem().toString();
this.drawStringPanel1.setAnchor(convertStringToAnchor(text));
this.drawStringPanel1.invalidate();
this.drawStringPanel1.repaint();
}
/**
* Updates the display when combo 2 is updated.
*/
private void handleCombo2Change() {
final String text = this.rubo2.getSelectedItem().toString();
this.drawStringPanel2.setAnchor(convertStringToAnchor(text));
this.drawStringPanel2.invalidate();
this.drawStringPanel2.repaint();
}
/**
* Updates the display when combo 3 is updated.
*/
private void handleCombo3Change() {
final String text = this.rubo3.getSelectedItem().toString();
this.drawStringPanel2.setRotationAnchor(convertStringToAnchor(text));
this.drawStringPanel2.invalidate();
this.drawStringPanel2.repaint();
}
/**
* Creates the content pane for the demo frame.
*
* @return The content pane.
*/
private JPanel createContentPane() {
final JPanel content = new JPanel(new BorderLayout());
final JTabbedPane tabs = new JTabbedPane();
tabs.add("Alignment", createTab1Content());
tabs.add("Rotation", createTab2Content());
content.add(tabs);
return content;
}
/**
* Creates the content for tab 1.
*
* @return The content panel.
*/
private JPanel createTab1Content() {
final JPanel content = new JPanel(new BorderLayout());
this.rubo1 = new JComboBox();
this.rubo1.setActionCommand("combo1.changed");
populateTextAnchorCombo(this.rubo1);
this.rubo1.addActionListener(this);
final JPanel controls = new JPanel();
controls.add(this.rubo1);
final JButton fontButton = new JButton("Select Font...");
fontButton.setActionCommand("fontButton.clicked");
fontButton.addActionListener(this);
controls.add(fontButton);
content.add(controls, BorderLayout.NORTH);
this.drawStringPanel1 = new DrawStringPanel("0123456789", false);
content.add(this.drawStringPanel1);
return content;
}
/**
* Creates the content for tab 2.
*
* @return The content panel.
*/
private JPanel createTab2Content() {
final JPanel content = new JPanel(new BorderLayout());
final JPanel controls = new JPanel();
controls.add(new JLabel("Text anchor: "));
this.rubo2 = new JComboBox();
populateTextAnchorCombo(this.rubo2);
this.rubo2.setActionCommand("combo2.changed");
this.rubo2.addActionListener(this);
controls.add(this.rubo2);
controls.add(new JLabel("Rotation anchor: "));
this.rubo3 = new JComboBox();
populateTextAnchorCombo(this.rubo3);
this.rubo3.setActionCommand("combo3.changed");
this.rubo3.addActionListener(this);
controls.add(this.rubo3);
this.spinner = new Spinner(0);
this.spinner.addPropertyChangeListener(this);
controls.add(this.spinner);
content.add(controls, BorderLayout.NORTH);
this.drawStringPanel2 = new DrawStringPanel("Rotated Text", true);
content.add(this.drawStringPanel2);
return content;
}
/**
* Displays a primitive font chooser dialog to allow the user to change the font.
*/
private void displayFontDialog() {
final FontChooserPanel panel = new FontChooserPanel(this.drawStringPanel1.getFont());
final int result = JOptionPane.showConfirmDialog(this, panel, "Font Selection",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
this.drawStringPanel1.setFont(panel.getSelectedFont());
this.drawStringPanel2.setFont(panel.getSelectedFont());
}
}
/**
* Populates a combo box with the available {@link TextAnchor} options.
*
* @param combo the combo box.
*/
private void populateTextAnchorCombo(final JComboBox combo) {
combo.addItem("TextAnchor.TOP_LEFT");
combo.addItem("TextAnchor.TOP_CENTER");
combo.addItem("TextAnchor.TOP_RIGHT");
combo.addItem("TextAnchor.HALF_ASCENT_LEFT");
combo.addItem("TextAnchor.HALF_ASCENT_CENTER");
combo.addItem("TextAnchor.HALF_ASCENT_RIGHT");
combo.addItem("TextAnchor.CENTER_LEFT");
combo.addItem("TextAnchor.CENTER");
combo.addItem("TextAnchor.CENTER_RIGHT");
combo.addItem("TextAnchor.BASELINE_LEFT");
combo.addItem("TextAnchor.BASELINE_CENTER");
combo.addItem("TextAnchor.BASELINE_RIGHT");
combo.addItem("TextAnchor.BOTTOM_LEFT");
combo.addItem("TextAnchor.BOTTOM_CENTER");
combo.addItem("TextAnchor.BOTTOM_RIGHT");
}
/**
* Converts a string to a corresponding {@link TextAnchor} instance.
*
* @param text the text.
*
* @return The anchor.
*/
private TextAnchor convertStringToAnchor(final String text) {
if (text.equals("TextAnchor.TOP_LEFT")) {
return TextAnchor.TOP_LEFT;
}
else if (text.equals("TextAnchor.TOP_CENTER")) {
return TextAnchor.TOP_CENTER;
}
else if (text.equals("TextAnchor.TOP_RIGHT")) {
return TextAnchor.TOP_RIGHT;
}
else if (text.equals("TextAnchor.CENTER_LEFT")) {
return TextAnchor.CENTER_LEFT;
}
else if (text.equals("TextAnchor.CENTER")) {
return TextAnchor.CENTER;
}
else if (text.equals("TextAnchor.CENTER_RIGHT")) {
return TextAnchor.CENTER_RIGHT;
}
else if (text.equals("TextAnchor.HALF_ASCENT_LEFT")) {
return TextAnchor.HALF_ASCENT_LEFT;
}
else if (text.equals("TextAnchor.HALF_ASCENT_CENTER")) {
return TextAnchor.HALF_ASCENT_CENTER;
}
else if (text.equals("TextAnchor.HALF_ASCENT_RIGHT")) {
return TextAnchor.HALF_ASCENT_RIGHT;
}
else if (text.equals("TextAnchor.BASELINE_LEFT")) {
return TextAnchor.BASELINE_LEFT;
}
else if (text.equals("TextAnchor.BASELINE_CENTER")) {
return TextAnchor.BASELINE_CENTER;
}
else if (text.equals("TextAnchor.BASELINE_RIGHT")) {
return TextAnchor.BASELINE_RIGHT;
}
else if (text.equals("TextAnchor.BOTTOM_LEFT")) {
return TextAnchor.BOTTOM_LEFT;
}
else if (text.equals("TextAnchor.BOTTOM_CENTER")) {
return TextAnchor.BOTTOM_CENTER;
}
else if (text.equals("TextAnchor.BOTTOM_RIGHT")) {
return TextAnchor.BOTTOM_RIGHT;
}
else {
return null;
}
}
/**
* The starting point for the demo.
*
* @param args ignored.
*/
public static void main(final String[] args) {
final DrawStringDemo demo = new DrawStringDemo("DrawString Demo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
Line break for textlayout
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Hashtable;
import javax.swing.JApplet;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LineBreakSample extends JPanel {
private LineBreakMeasurer lineMeasurer;
// the first character in the paragraph.
private int paragraphStart;
// the first character after the end of the paragraph.
private int paragraphEnd;
private static final Hashtable map = new Hashtable();
static {
map.put(TextAttribute.SIZE, new Float(18.0));
}
private static AttributedString vanGogh = new AttributedString(
"Many people believe that Vincent van Gogh painted his best works "
+ "during the two-year period he spent in Provence. Here is where he "
+ "painted The Starry Night--which some consider to be his greatest "
+ "work of all. However, as his artistic brilliance reached new heights "
+ "in Provence, his physical and mental health plummeted. ",
map);
public LineBreakSample() {
AttributedCharacterIterator paragraph = vanGogh.getIterator();
paragraphStart = paragraph.getBeginIndex();
paragraphEnd = paragraph.getEndIndex();
// Create a new LineBreakMeasurer from the paragraph.
lineMeasurer = new LineBreakMeasurer(paragraph,
new FontRenderContext(null, false, false));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.white);
Graphics2D graphics2D = (Graphics2D) g;
// Set formatting width to width of Component.
Dimension size = getSize();
float formatWidth = (float) size.width;
float drawPosY = 0;
lineMeasurer.setPosition(paragraphStart);
// Get lines from lineMeasurer until the entire
// paragraph has been displayed.
while (lineMeasurer.getPosition() < paragraphEnd) {
// Retrieve next layout.
TextLayout layout = lineMeasurer.nextLayout(formatWidth);
// Move y-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
// Compute pen x position. If the paragraph is
// right-to-left, we want to align the TextLayouts
// to the right edge of the panel.
float drawPosX;
if (layout.isLeftToRight()) {
drawPosX = 0;
} else {
drawPosX = formatWidth - layout.getAdvance();
}
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(graphics2D, drawPosX, drawPosY);
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
}
}
public static void main(String[] args) {
JFrame f = new JFrame("");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
LineBreakSample controller = new LineBreakSample();
f.getContentPane().add(controller,"Center");
f.setSize(new Dimension(400, 250));
f.setVisible(true);
}
}
LineMetrics: the metrics to layout characters along a line
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LineMetricsIllustration extends JPanel{
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("Serif", Font.PLAIN, 72);
g2.setFont(font);
String s = "Java Source and Support";
float x = 50, y = 150;
// Draw the baseline.
FontRenderContext frc = g2.getFontRenderContext();
float width = (float) font.getStringBounds(s, frc).getWidth();
Line2D baseline = new Line2D.Float(x, y, x + width, y);
g2.setPaint(Color.red);
g2.draw(baseline);
// Draw the ascent.
LineMetrics lm = font.getLineMetrics(s, frc);
Line2D ascent = new Line2D.Float(x, y - lm.getAscent(), x + width, y
- lm.getAscent());
g2.draw(ascent);
// Draw the descent.
Line2D descent = new Line2D.Float(x, y + lm.getDescent(), x + width, y
+ lm.getDescent());
g2.draw(descent);
// Draw the leading.
Line2D leading = new Line2D.Float(x, y + lm.getDescent()
+ lm.getLeading(), x + width, y + lm.getDescent()
+ lm.getLeading());
g2.draw(leading);
// Render the string.
g2.setPaint(Color.black);
g2.drawString(s, x, y);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new LineMetricsIllustration());
f.setSize(850, 250);
f.show();
}
}
Mouse hit and textlayout
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import java.awt.geom.Point2D;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Hashtable;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class HitTestSample extends JPanel {
private static final Color STRONG_CARET_COLOR = Color.red;
private static final Color WEAK_CARET_COLOR = Color.black;
private TextLayout textLayout;
private int insertionIndex;
private static final FontRenderContext DEFAULT_FRC = new FontRenderContext(
null, false, false);
private static final Hashtable map = new Hashtable();
static {
map.put(TextAttribute.SIZE, new Float(18.0));
}
private static AttributedString helloWorld = new AttributedString(
"Java Source and Support.", map);
public HitTestSample() {
AttributedCharacterIterator text = helloWorld.getIterator();
// Create a new TextLayout from the given text.
textLayout = new TextLayout(text, DEFAULT_FRC);
// Initilize insertionIndex.
insertionIndex = 0;
addMouseListener(new HitTestMouseListener());
}
public Dimension getPreferredSize() {
return new Dimension(400, 250);
}
private Point2D computeLayoutOrigin() {
Dimension size = getPreferredSize();
Point2D.Float origin = new Point2D.Float();
origin.x = (float) (size.width - textLayout.getAdvance()) / 2;
origin.y = (float) (size.height - textLayout.getDescent() + textLayout
.getAscent()) / 2;
return origin;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.white);
Graphics2D graphics2D = (Graphics2D) g;
Point2D origin = computeLayoutOrigin();
graphics2D.translate(origin.getX(), origin.getY());
// Draw textLayout.
textLayout.draw(graphics2D, 0, 0);
// Retrieve caret Shapes for insertionIndex.
Shape[] carets = textLayout.getCaretShapes(insertionIndex);
graphics2D.setColor(STRONG_CARET_COLOR);
graphics2D.draw(carets[0]);
if (carets[1] != null) {
graphics2D.setColor(WEAK_CARET_COLOR);
graphics2D.draw(carets[1]);
}
}
private class HitTestMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
Point2D origin = computeLayoutOrigin();
// Compute the mouse click location relative to
// textLayout"s origin.
float clickX = (float) (e.getX() - origin.getX());
float clickY = (float) (e.getY() - origin.getY());
// Get the character position of the mouse click.
TextHitInfo currentHit = textLayout.hitTestChar(clickX, clickY);
insertionIndex = currentHit.getInsertionIndex();
// Repaint the Component so the new caret(s) will be displayed.
repaint();
}
}
public static void main(String[] args) {
JFrame f = new JFrame("HitTestSample");
HitTestSample demo = new HitTestSample();
f.getContentPane().add(demo, "Center");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(new Dimension(400, 250));
f.setVisible(true);
}
}
Paragraph Layout
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ParagraphLayout extends JPanel {
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
String s = "Java components and products Directory for Java components " +
"and applications.Hundreds of Java components and applications " +
"are organized by topic. You can find what you need easily. " +
"You may also compare your product with others. If your component " +
"is not listed, just send your url to jexp@jexp.ru. " +
"http://www.jexp.ru";
Font font = new Font("Serif", Font.PLAIN, 24);
AttributedString as = new AttributedString(s);
as.addAttribute(TextAttribute.FONT, font);
AttributedCharacterIterator aci = as.getIterator();
FontRenderContext frc = g2.getFontRenderContext();
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
Insets insets = getInsets();
float wrappingWidth = getSize().width - insets.left - insets.right;
float x = insets.left;
float y = insets.top;
while (lbm.getPosition() < aci.getEndIndex()) {
TextLayout textLayout = lbm.nextLayout(wrappingWidth);
y += textLayout.getAscent();
textLayout.draw(g2, x, y);
y += textLayout.getDescent() + textLayout.getLeading();
x = insets.left;
}
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new ParagraphLayout());
f.setSize(350, 250);
f.show();
}
}
Renders a paragraph of text (line breaks ignored) to an image (created and returned).
/*
*
* Created on March 16, 2007, 4:34 PM
*
* Copyright 2006-2007 Nigel Hughes
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at http://www.apache.org/
* licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Hashtable;
/**
* @author nigel
*/
public class Utils {
/**
* Renders a paragraph of text (line breaks ignored) to an image (created and returned).
*
* @param font The font to use
* @param textColor The color of the text
* @param text The message
* @param width The width the text should be limited to
* @return An image with the text rendered into it
*/
public static BufferedImage renderTextToImage(Font font, Color textColor, String text, int width){
Hashtable map = new Hashtable();
map.put(TextAttribute.FONT, font);
AttributedString attributedString = new AttributedString(text,map);
AttributedCharacterIterator paragraph = attributedString.getIterator();
FontRenderContext frc = new FontRenderContext(null, false, false);
int paragraphStart = paragraph.getBeginIndex();
int paragraphEnd = paragraph.getEndIndex();
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
float drawPosY=0;
//First time around, just determine the height
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout = lineMeasurer.nextLayout(width);
// Move it down
drawPosY += layout.getAscent() + layout.getDescent() + layout.getLeading();
}
BufferedImage image = createCompatibleImage(width,(int) drawPosY);
Graphics2D graphics = (Graphics2D) image.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
drawPosY=0;
lineMeasurer.setPosition(paragraphStart);
while (lineMeasurer.getPosition() < paragraphEnd) {
TextLayout layout = lineMeasurer.nextLayout(width);
// Move y-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
/* Compute pen x position. If the paragraph is
right-to-left, we want to align the TextLayouts
to the right edge of the panel.
*/
float drawPosX;
if (layout.isLeftToRight()) {
drawPosX = 0;
} else {
drawPosX = width - layout.getAdvance();
}
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(graphics, drawPosX, drawPosY);
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
}
graphics.dispose();
return image;
}
/**
* Creates an image compatible with the current display
*
* @return A BufferedImage with the appropriate color model
*/
public static BufferedImage createCompatibleImage(int width, int height) {
GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
return configuration.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
}
TextAttribute: color and font
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.TextAttribute;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class IteratorTest extends JPanel {
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
String s = "Java Source and Support";
Dimension d = getSize();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font serifFont = new Font("Serif", Font.PLAIN, 48);
Font sansSerifFont = new Font("Monospaced", Font.PLAIN, 48);
AttributedString as = new AttributedString(s);
as.addAttribute(TextAttribute.FONT, serifFont);
as.addAttribute(TextAttribute.FONT, sansSerifFont, 2, 5);
as.addAttribute(TextAttribute.FOREGROUND, Color.red, 5, 6);
as.addAttribute(TextAttribute.FOREGROUND, Color.red, 16, 17);
g2.drawString(as.getIterator(), 40, 80);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new IteratorTest());
f.setSize(850, 250);
f.show();
}
}
TextAttribute: Underline and strike through
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.TextAttribute;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class IteratorUnderStrike extends JPanel{
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
String s = "\"www.jexp.ru\" is great.";
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font plainFont = new Font("Times New Roman", Font.PLAIN, 24);
AttributedString as = new AttributedString(s);
as.addAttribute(TextAttribute.FONT, plainFont);
as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, 1,
15);
as.addAttribute(TextAttribute.STRIKETHROUGH,
TextAttribute.STRIKETHROUGH_ON, 18, 25);
g2.drawString(as.getIterator(), 24, 70);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new IteratorUnderStrike());
f.setSize(850, 250);
f.show();
}
}
TextHitInfo Demo: tell you which is the letter you are clicking
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextHitInfo;
import java.awt.font.TextLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TextHitInfoDemo extends JPanel {
private TextLayout mTextLayout;
private int mX = 40, mY = 80;
public TextHitInfoDemo() {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
TextHitInfo hit = mTextLayout.hitTestChar(me.getX() - mX, me
.getY()
- mY);
System.out.println(hit);
}
});
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
String s = "Java Source and Support";
Font font = new Font("Serif", Font.PLAIN, 32);
if (mTextLayout == null) {
FontRenderContext frc = g2.getFontRenderContext();
mTextLayout = new TextLayout(s, font, frc);
}
mTextLayout.draw(g2, mX, mY);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new TextHitInfoDemo());
f.setSize(200, 200);
f.show();
}
}
TextLayout demo
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.TextLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TextLayoutOne extends JPanel {
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
String s = "Java Source and Support.";
Font font = new Font("Serif", Font.PLAIN, 32);
TextLayout textLayout = new TextLayout(s, font, g2
.getFontRenderContext());
textLayout.draw(g2, 40, 80);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.getContentPane().add(new TextLayoutOne());
f.setSize(300, 200);
f.setVisible(true);
}
}
Unicode display
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class HelloInJapanese extends JPanel {
static JFrame frame;
static String helloInJapanese = "Hello in Japanese is konnichi wa, \u4eca\u65e5\u306f.";
public HelloInJapanese(String characters) {
Font theFont = new Font("Bitstream Cyberbit", Font.PLAIN, 20);
JTextArea area = new JTextArea(characters, 2, 30);
area.setFont(theFont);
area.setLineWrap(true);
JScrollPane scrollpane = new JScrollPane(area);
add(scrollpane);
}
public static void main(String argv[]) {
HelloInJapanese japanesePanel = new HelloInJapanese(helloInJapanese);
frame = new JFrame("Hello in Japanese");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.getContentPane().add("Center", japanesePanel);
frame.pack();
frame.setVisible(true);
}
}
Unicode: test layout
/*
Java Internationalization
By Andy Deitsch, David Czarnecki
ISBN: 0-596-00019-7
O"Reilly
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.text.*;
import javax.swing.*;
public class TextLayoutDemo extends JFrame {
String davidMessage = "David says, \"\u05E9\u05DC\u05D5\u05DD \u05E2\u05D5\u05DC\u05DD\" ";
String andyMessage = "Andy also says, \"\u05E9\u05DC\u05D5\u05DD \u05E2\u05D5\u05DC\u05DD\" ";
String textMessage = davidMessage + andyMessage + davidMessage + andyMessage +
davidMessage + andyMessage + davidMessage + andyMessage +
davidMessage + andyMessage + davidMessage + andyMessage +
davidMessage + andyMessage + davidMessage + andyMessage;
public TextLayoutDemo() {
super("TextLayoutDemo");
}
public void paint(Graphics g) {
Graphics2D graphics2D = (Graphics2D)g;
GraphicsEnvironment.getLocalGraphicsEnvironment();
Font font = new Font("LucidaSans", Font.PLAIN, 14);
AttributedString messageAS = new AttributedString(textMessage);
messageAS.addAttribute(TextAttribute.FONT, font);
AttributedCharacterIterator messageIterator = messageAS.getIterator();
FontRenderContext messageFRC = graphics2D.getFontRenderContext();
LineBreakMeasurer messageLBM = new LineBreakMeasurer(messageIterator, messageFRC);
Insets insets = getInsets();
float wrappingWidth = getSize().width - insets.left - insets.right;
float x = insets.left;
float y = insets.top;
while (messageLBM.getPosition() < messageIterator.getEndIndex()) {
TextLayout textLayout = messageLBM.nextLayout(wrappingWidth);
y += textLayout.getAscent();
textLayout.draw(graphics2D, x, y);
y += textLayout.getDescent() + textLayout.getLeading();
x = insets.left;
}
}
public static void main(String[] args) {
JFrame frame = new TextLayoutDemo();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
frame.pack();
frame.setVisible(true);
}
}