我有一个Java编程,它显示10x10个单元格的网格。在每个单元格中,我想画一个字符并让它占据整个单元格。
我目前正在使用以下代码,但它的大小不太合适。
graphics.setFont(new Font("monospaced", Font.PLAIN, 12));
for(int x = 0; x < GRID_WIDTH; x++) {
for(int y = 0; y < GRID_HEIGHT; y++) {
graphics.drawString(Character.toString(grid[x][y]), x * CELL_WIDTH, (y + 1) * CELL_HEIGHT);
}
}
在Java中有什么方法可以绘制10x10(或CELL_WIDTH
x CELL_HEIGHT
)字符吗?
我在阅读这个问题时碰巧打开的项目 =D 中构建了这些方法。请注意,方法pickOptimalFontSize应该适合您的特定情况。默认大小为 130,对于您的情况来说,这可能太高了。您可以根据需要对其进行调整,但这演示了基础知识。在您的情况下,像这样使用它们:
Font baseFont = new Font("monospaced", Font.PLAIN, 12);
for(int x = 0; x < GRID_WIDTH; x++) {
for(int y = 0; y < GRID_HEIGHT; y++) {
graphics.setFont(pickOptimalFontSize(graphics, Character.toString(grid[x][y]), CELL_WIDTH, CELL_HEIGHT, baseFont));
drawString(graphics, Character.toString(grid[x][y]), x * CELL_WIDTH, (y + 1) * CELL_HEIGHT, "left", "center");
}
}
public static void drawString(Graphics g, String str, double x, double y, String hAlign, String vAlign) {
FontMetrics metrics = g.getFontMetrics();
double dX = x;
double dY = y;
if(hAlign == null || "left".equals(hAlign.toLowerCase())) {
} else if("center".equals(hAlign.toLowerCase())) {
dX -= metrics.getStringBounds(str, g).getWidth()/2;
} else if("right".equals(hAlign.toLowerCase())) {
dX -= metrics.getStringBounds(str, g).getWidth();
}
if(vAlign == null || "bottom".equals(vAlign.toLowerCase())) {
} else if("center".equals(vAlign.toLowerCase())) {
dY += metrics.getAscent()/2;
} else if("top".equals(vAlign.toLowerCase())) {
dY += metrics.getAscent();
}
g.drawString(str, (int)dX, (int)dY);
}
private static Font pickOptimalFontSize (Graphics2D g, String title, int width, int height, Font baseFont) {
Rectangle2D rect = null;
float fontSize = 130; //initial value
Font font;
do {
fontSize-=1;
font = baseFont.deriveFont(fontSize);
rect = getStringBoundsRectangle2D(g, title, font);
} while (rect.getWidth() >= width || rect.getHeight() >= height);
return font;
}
public static Rectangle2D getStringBoundsRectangle2D (Graphics g, String title, Font font) {
g.setFont(font);
FontMetrics fm = g.getFontMetrics();
Rectangle2D rect = fm.getStringBounds(title, g);
return rect;
}
我找到了一个我想要的解决方案:我创建了一个名为CharacterImageGenerator
的类,它生成(和缓存)Image
个字符。然后,每当我想画一个角色时,我都会绘制和缩放这些图像。
public class CharacterImageGenerator {
private FontMetrics metrics;
private Color color;
private Map<Character, Image> images;
public CharacterImageGenerator(FontMetrics metrics, Color color) {
this.metrics = metrics;
this.color = color;
images = new HashMap<Character, Image>();
}
public Image getImage(char c) {
if(images.containsKey(c))
return images.get(c);
Rectangle2D bounds = new TextLayout(Character.toString(c), metrics.getFont(), metrics.getFontRenderContext()).getOutline(null).getBounds();
if(bounds.getWidth() == 0 || bounds.getHeight() == 0) {
images.put(c, null);
return null;
}
Image image = new BufferedImage((int)bounds.getWidth(), (int)bounds.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = image.getGraphics();
g.setColor(color);
g.setFont(metrics.getFont());
g.drawString(Character.toString(c), 0, (int)(bounds.getHeight() - bounds.getMaxY()));
images.put(c, image);
return image;
}
}
然后我用大字体初始化以获得看起来不错的字符。
// During initialization
graphics.setFont(new Font("monospaced", Font.PLAIN, 24));
characterGenerator = new CharacterImageGenerator(graphics.getFontMetrics(), Color.WHITE);
然后缩放并绘制到我想要的大小。
private void drawCharacter(int x, int y, char c) {
graphics.drawImage(characterGenerator.getImage(c), PADDING + (x * TILE_WIDTH), PADDING + (y * TILE_HEIGHT), TILE_WIDTH, TILE_HEIGHT, null);
}