我熟悉如何使用各种 FontMetrics 函数将文本垂直、水平等居中。但是,我正在寻找一个支持在相对于字符串的给定 xy 位置绘制文本的库(例如,我希望字符串的中心位于 x,y,或者我希望它的右上角在这里,等等。 )
我发现了 JCommon及其声称可以做到这一点的文本锚点,但是我无法让它工作,并且论坛迄今为止没有响应。
我知道我可以自己编写所有实用程序函数,但如果可能的话,我想避免重新发明轮子。
我熟悉如何使用各种 FontMetrics 函数将文本垂直、水平等居中。但是,我正在寻找一个支持在相对于字符串的给定 xy 位置绘制文本的库(例如,我希望字符串的中心位于 x,y,或者我希望它的右上角在这里,等等。 )
我发现了 JCommon及其声称可以做到这一点的文本锚点,但是我无法让它工作,并且论坛迄今为止没有响应。
我知道我可以自己编写所有实用程序函数,但如果可能的话,我想避免重新发明轮子。
我不知道有任何库,但我猜如果你自己做,你只会使用 Graphics.translate() 将文本翻译到相对位置。
最终不得不自己做。代码如下:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestFontLayout extends JPanel {
public enum AnchorPoint{
UPPER_LEFT,
TOP_CENTER,
UPPER_RIGHT,
RIGHT_CENTER,
LOWER_RIGHT,
BOTTOM_CENTER,
LOWER_LEFT,
LEFT_CENTER,
CENTER
};
public void drawText(TextLayout text, AnchorPoint point, Graphics2D g2, float x, float y) {
float translationX = 0.0f;
float translationY = 0.0f;
Rectangle2D bounds = text.getBounds();
float midYOffset = (float) bounds.getHeight()/2;
float midXOffset = (float) -bounds.getWidth()/2;
float topYOffset = (float) bounds.getHeight();
float bottomYOffset = 0.0f;
float leftXOffset = 0.0f;
float rightXOffset = (float) -bounds.getWidth();
// Adjust x values
switch (point) {
// Left
case UPPER_LEFT:
case LOWER_LEFT:
case LEFT_CENTER:
translationX = leftXOffset;
break;
// Mid
case TOP_CENTER:
case BOTTOM_CENTER:
case CENTER:
translationX = midXOffset;
break;
// Right
case UPPER_RIGHT:
case RIGHT_CENTER:
case LOWER_RIGHT:
translationX = rightXOffset;
}
// Adjust y values
switch (point) {
// Top
case UPPER_LEFT:
case UPPER_RIGHT:
case TOP_CENTER:
translationY = topYOffset;
break;
// Mid
case LEFT_CENTER:
case CENTER:
case RIGHT_CENTER:
translationY = midYOffset;
break;
// Bottom
case LOWER_LEFT:
case BOTTOM_CENTER:
case LOWER_RIGHT:
translationY = bottomYOffset;
}
text.draw(g2, x + translationX, y + translationY);
}
public TestFontLayout() {
super();
setPreferredSize(new Dimension(400,400));
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Ensure that the default painting occurs
super.paintComponent(g);
Point2D loc = new Point2D.Double(getWidth()/2,getHeight()/2);
Font font = Font.decode("Helvetica");
FontRenderContext frc = g2.getFontRenderContext();
TextLayout layout = new TextLayout("This is a string", font, frc);
g2.setColor(Color.RED);
g2.drawRect(getWidth()/2, getHeight()/2, 1,1);
g2.setColor(Color.PINK);
drawText(layout, AnchorPoint.UPPER_LEFT, g2, 0, 0);
g2.setColor(Color.BLUE);
drawText(layout, AnchorPoint.TOP_CENTER, g2, getWidth()/2, 0);
g2.setColor(Color.ORANGE);
drawText(layout, AnchorPoint.UPPER_RIGHT, g2, getWidth(), 0);
g2.setColor(Color.CYAN);
drawText(layout, AnchorPoint.RIGHT_CENTER, g2, getWidth(), getHeight()/2);
g2.setColor(Color.ORANGE);
drawText(layout, AnchorPoint.LOWER_RIGHT, g2, getWidth(), getHeight());
g2.setColor(Color.BLACK);
drawText(layout, AnchorPoint.BOTTOM_CENTER, g2, getWidth()/2, getHeight());
g2.setColor(Color.YELLOW);
drawText(layout, AnchorPoint.LOWER_LEFT, g2, 0, getHeight());
g2.setColor(Color.DARK_GRAY);
drawText(layout, AnchorPoint.LEFT_CENTER, g2, 0, getHeight()/2);
g2.setColor(Color.MAGENTA);
drawText(layout, AnchorPoint.CENTER, g2, getWidth()/2, getHeight()/2);
}
public static void main(String[] args) {
JFrame frame = new JFrame("");
frame.add(new TestFontLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
你可能会看TextLayout
。和方法可以draw()
简化getBounds()
编码。
我发现I82MuchTestFontLayout
的代码非常有用,谢谢。垂直对齐有一个小错误。我的解决方法是使用而不是用于“偏移”计算。此外,该方法已修改为返回一个自定义类以提供绘制文本的角坐标,以便下一个绘图可以使用 Box 角来对齐更多文本。这是我的代码版本。bounds.getY()
bounds.getHeight()
drawText(...)
Box
import static java.awt.Color.BLACK;
import static java.awt.Color.BLUE;
import static java.awt.Color.CYAN;
import static java.awt.Color.DARK_GRAY;
import static java.awt.Color.MAGENTA;
import static java.awt.Color.ORANGE;
import static java.awt.Color.PINK;
import static java.awt.Color.RED;
import static java.awt.Color.YELLOW;
import static java.awt.Font.PLAIN;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestFontLayout2 extends JPanel
{
private static final long serialVersionUID = 1L;
public enum Anchor
{
UPPER_LEFT,
UPPER_CENTER,
UPPER_RIGHT,
MIDDLE_LEFT,
MIDDLE_CENTER,
MIDDLE_RIGHT,
LOWER_LEFT,
LOWER_CENTER,
LOWER_RIGHT
};
public static Box drawText(Graphics2D g2d, String text, Anchor point, float xpos, float ypos)
{
return drawText(g2d, new TextLayout(text, g2d.getFont(), g2d.getFontRenderContext()), point, xpos, ypos);
}
public static Box drawText(Graphics2D g2d, String text, Anchor point, float xpos, float ypos, Font font)
{
return drawText(g2d, new TextLayout(text, font, g2d.getFontRenderContext()), point, xpos, ypos);
}
public static Box drawText(Graphics2D g2d, TextLayout text, Anchor anchor, float xpos, float ypos)
{
Rectangle2D bounds = text.getBounds();
float xOffsetLeft = 0.0f;
float xOffsetRight = (float) -bounds.getWidth();
float xOffsetCenter = (float) -bounds.getWidth() / 2.0f;
// Bounds.getY() is the (negative) offset between the baseline and the top of the text.
// Bounds.getHeight() is the distance above plus the distance below the text baseline.
float yOffsetTop = (float) bounds.getY();
float yOffsetBottom = (float) (bounds.getHeight()+bounds.getY());
float yOffsetMiddle = (float) (-bounds.getHeight()) / 2.0f;
float xOffset = 0.0f;
float yOffset = 0.0f;
// Adjust x values
switch (anchor)
{
// Left
case UPPER_LEFT:
case MIDDLE_LEFT:
case LOWER_LEFT:
xOffset = xOffsetLeft;
break;
// Center
case UPPER_CENTER:
case MIDDLE_CENTER:
case LOWER_CENTER:
xOffset = xOffsetCenter;
break;
// Right
case UPPER_RIGHT:
case MIDDLE_RIGHT:
case LOWER_RIGHT:
xOffset = xOffsetRight;
break;
}
// Adjust y values
switch (anchor)
{
// Top
case UPPER_LEFT:
case UPPER_CENTER:
case UPPER_RIGHT:
yOffset = yOffsetTop;
break;
// Middle
case MIDDLE_LEFT:
case MIDDLE_CENTER:
case MIDDLE_RIGHT:
yOffset = yOffsetMiddle;
break;
// Bottom
case LOWER_LEFT:
case LOWER_CENTER:
case LOWER_RIGHT:
yOffset = yOffsetBottom;
break;
}
// Draw text at baseline position.
float xbase = xpos + xOffset;
float ybase = ypos - yOffset;
text.draw(g2d, xbase, ybase);
// Enclose text within a box.
int xrect = rnd(xbase + bounds.getX());
int yrect = rnd(ybase + bounds.getY());
int wrect = rnd(bounds.getWidth());
int hrect = rnd(bounds.getHeight());
Box box = new Box(xrect, yrect, xrect+wrect, yrect+hrect);
// Debug: draw rectangle around text.
// g2d.drawRect(xrect, yrect, wrect, hrect);
return box;
}
private static int rnd(double value)
{
return (int) Math.round(value);
}
public static class Box
{
private int tl[] = {0, 0}; public int[] getTL() { return tl; }
private int br[] = {0, 0}; public int[] getBR() { return br; }
private int tr[] = {0, 0}; public int[] getTR() { return tr; }
private int bl[] = {0, 0}; public int[] getBL() { return bl; }
public Box(int tlx, int tly, int brx, int bry)
{
tl[0] = tlx; tl[1] = tly;
br[0] = brx; br[1] = bry;
tr[0] = brx; tr[1] = tly;
bl[0] = tlx; bl[1] = bry;
}
}
public TestFontLayout2()
{
super();
setPreferredSize(new Dimension(600,300));
}
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
// Ensure that the default painting occurs
super.paintComponent(g);
Font font = new Font("SansSerif", PLAIN, 21);
FontRenderContext frc = g2d.getFontRenderContext();
TextLayout layout1 = new TextLayout("This is a string", font, frc);
TextLayout layout2 = new TextLayout("This is text", font, frc);
g2d.setColor(RED);
g2d.drawRect(getWidth()/2, getHeight()/2, 1,1);
g2d.setColor(PINK);
Box box = drawText(g2d, layout1, Anchor.UPPER_LEFT, 0, 0);
g2d.setColor(BLUE);
box = drawText(g2d, layout2, Anchor.UPPER_CENTER, getWidth()/2, 0);
g2d.setColor(ORANGE);
box = drawText(g2d, layout1, Anchor.UPPER_RIGHT, getWidth(), 0);
g2d.setColor(DARK_GRAY);
box = drawText(g2d, layout2, Anchor.MIDDLE_LEFT, 0, getHeight()/2);
g2d.setColor(MAGENTA);
box = drawText(g2d, layout1, Anchor.MIDDLE_CENTER, getWidth()/2, getHeight()/2);
box = drawText(g2d, layout1, Anchor.UPPER_LEFT, box.getBL()[0], box.getBL()[1]);
g2d.setColor(CYAN);
box = drawText(g2d, layout2, Anchor.MIDDLE_RIGHT, getWidth(), getHeight()/2);
g2d.setColor(YELLOW);
box = drawText(g2d, layout1, Anchor.LOWER_LEFT, 0, getHeight());
g2d.setColor(BLACK);
box = drawText(g2d, layout2, Anchor.LOWER_CENTER, getWidth()/2, getHeight());
g2d.setColor(ORANGE);
box = drawText(g2d, layout1, Anchor.LOWER_RIGHT, getWidth(), getHeight());
}
public static void main(String[] args)
{
println("Draw text at specified anchor points...");
JFrame frame = new JFrame("");
frame.add(new TestFontLayout2());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static void println(Object obj)
{
System.out.println(obj.toString());
}
}
// vi:set tabstop=4 hardtabs=4 shiftwidth=4 expandtab: