0

我有一个显示 10x10 单元格网格的 Java 编程。在每个单元格中,我想绘制一个字符并让它占据整个单元格。

我目前正在使用以下代码,但它的大小不太合适。

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_WIDTHx CELL_HEIGHT)字符吗?

4

2 回答 2

0

我在阅读此问题时碰巧打开的项目中构建了这些方法=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;
}
于 2013-10-30T21:51:27.097 回答
0

我找到了一个我想要的解决方案:我创建了一个名为的类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);
}
于 2013-10-30T23:58:49.333 回答