I'm trying to draw a string (i.e. "$29.95"), where the dollar sign is
superior (aligned with the top of the price). This is similar to
superscript and that would probably be acceptable also. As far as I can
tell, setting TextAttribute.SUPERSCRIPT=TextAttribute.SUPERSCRIPT_SUPER
doesn't work (in jdk1.3).
To accomplish this, I decided to get the shape of the "$" and use the
ShapeGraphicAttribute which allows me to set the alignment for the shape
(relative to the string it is attached to). As you can see in the
attached code, I set GraphicAttribute.TOP_ALIGNMENT with the hopes of
aligning the shape to the top of the rest of the string.
first problem is that this seems to be a bit high. It may be lined up
with the max ascent, rather than the glyph visual bounds for the string.
second problem is that when a scale transform is set in the
FontRenderContext (which I use to match preview to print res output),
the alignment doesn't follow the change in font size! In fact, it seems
like it aligns with the unscaled font.
I have a clunky workaround that gives decent results, but is this
something I should file as a bug report?
Don't try this in 1.4 since that scaling I use doesn't work there. I did
file a bug for this regression problem, but still under review.
Your report has been assigned an internal review ID of: 138490 <--- for the sun
folks...
Thanks in advance for the input....
David
import java.awt.Color;
import java.awt.Component;
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.GlyphVector;
import java.awt.font.GraphicAttribute;
import java.awt.font.ShapeGraphicAttribute;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.text.AttributedString;
import java.util.Map;
import java.util.HashMap;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class TestStringAlign extends JPanel {
Map fontAttrs;
Map fontAttrs2;
public TestStringAlign() {
fontAttrs = new HashMap();
fontAttrs.put(TextAttribute.FAMILY, "Arial");
fontAttrs.put(TextAttribute.SIZE, new Float(50));
fontAttrs2 = new HashMap();
fontAttrs2.put(TextAttribute.FAMILY, "Arial");
fontAttrs2.put(TextAttribute.SIZE, new Float(21));
}
public void paint(Graphics g) {
g.setColor(Color.black);
// this draws the string at normal size
AttributedString attrStr = new AttributedString("$29.95", fontAttrs);
FontRenderContext frc = new FontRenderContext(null, true, true);
//attrStr.addAttributes(fontAttrs2, 0, 1);
GlyphVector vect = new Font(fontAttrs2).createGlyphVector(frc, "$");
ShapeGraphicAttribute sga = new ShapeGraphicAttribute(
vect.getOutline(),
GraphicAttribute.TOP_ALIGNMENT, false);
attrStr.addAttribute(TextAttribute.CHAR_REPLACEMENT, sga, 0, 1);
TextLayout tl = new TextLayout(attrStr.getIterator(), frc);
tl.draw((Graphics2D)g, 25, 100);
// this draws the string 50% smaller
AffineTransform trans = AffineTransform.getScaleInstance(0.5, 0.5);
frc = new FontRenderContext(trans, true, true);
vect = new Font(fontAttrs2).createGlyphVector(frc, "$");
sga = new ShapeGraphicAttribute(
vect.getOutline(),
GraphicAttribute.TOP_ALIGNMENT, false);
attrStr.addAttribute(TextAttribute.CHAR_REPLACEMENT, sga, 0, 1);
tl = new TextLayout(attrStr.getIterator(), frc);
tl.draw((Graphics2D)g, 25, 200);
// this draws the string 200% larger
trans = AffineTransform.getScaleInstance(2.0, 2.0);
frc = new FontRenderContext(trans, true, true);
vect = new Font(fontAttrs2).createGlyphVector(frc, "$");
sga = new ShapeGraphicAttribute(
vect.getOutline(),
GraphicAttribute.TOP_ALIGNMENT, false);
attrStr.addAttribute(TextAttribute.CHAR_REPLACEMENT, sga, 0, 1);
tl = new TextLayout(attrStr.getIterator(), frc);
tl.draw((Graphics2D)g, 25, 350);
}
public static void main(String [] args) {
JFrame f = new JFrame("Font Scale Tester");
f.setSize(400, 400);
f.setContentPane(new TestStringAlign());
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0); }
});
f.setVisible(true);
}
}