在 Java 中绘制具有特定大小的字符



我有一个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);
}

相关内容

  • 没有找到相关文章

最新更新