我无法在 java swing 中将文本居中

I can't center text in java swing

我正在为我的游戏制作自定义组件,我尝试了在 Stack Overflow 中找到的所有内容,但无论如何我仍然无法将文本放在矩形的中心。我什至阅读了所有使用 java 文本 API.

的文档

任何人都可以向我解释如何在 java swing 中一劳永逸地将文本对齐到中心(矩形或框架的中心或任何东西)吗?这不是一个重复的问题,因为在 Stack Overflow 上的所有其他问题中,我没有找到有效的解决方案。

到目前为止,我使用了 FontMetrics,我使用 stringWidth() 方法测量宽度,使用 ascent 测量高度(None 是准确的)。

package com.isi.uicomponents;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;

import com.isi.core.Game;
import com.isi.states.GameState;

public class Button extends UIComponent {

    private Font font;
    private String text;
    
    public Button(Game game, GameState state, int x, int y, int width, int height, String text) {
        super(game, state, x, y, width, height);
            
        font = new Font("Arial", Font.BOLD, 20);
        this.text = text;
    }

    public Button(Game game, GameState state, int x, int y, int width, int height) {
        super(game, state, x, y, width, height);
    
        text = null;
    }
    
    public String getText() {
        return text;
    }
    
    @Override
    public void tick() {
        
    }

    @Override
    public void draw(Graphics2D g) {        
        g.setColor(fillColor);
        g.fillRect(x, y, width, height);
        
        g.setColor(boundsColor);
        g.draw(bounds);
        
        if (text != null) {
            FontMetrics fm = g.getFontMetrics();
            
            int textX = x + (width / 2) - (fm.stringWidth(text) / 2);
            int textY = y + ((height - fm.getHeight()) / 2) + fm.getAscent();
            
            g.setFont(font);
            g.setColor(Color.white);
            g.drawString(text, textX, textY);
        }
    }
}

// =============================================

package com.isi.uicomponents;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import com.isi.core.Game;
import com.isi.states.GameState;

public abstract class UIComponent {

    public final static Color DEFAULT_BOUNDS_COLOR = Color.white;
    public final static Color DEFAULT_FILL_COLOR = Color.gray;
    
    protected Game game;
    protected GameState state;
    
    protected int x;
    protected int y;
    
    protected int width;
    protected int height;
    
    protected Rectangle bounds;
    
    protected Color boundsColor;
    protected Color fillColor;

    public UIComponent(Game game, GameState state, int x, int y, int width, int height) {
        this.game = game;
        this.state = state;
        
        this.x = x;
        this.y = y;
        
        this.width = width;
        this.height = height;
        
        bounds = new Rectangle(x, y, width, height);
        
        boundsColor = DEFAULT_BOUNDS_COLOR;
        fillColor = DEFAULT_FILL_COLOR;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public Rectangle getBounds() {
        return bounds;
    }

    public void setBounds(Rectangle bounds) {
        this.bounds = bounds;
    }
    
    public Color getBoundsColor() {
        return boundsColor;
    }

    public void setBoundsColor(Color boundsColor) {
        this.boundsColor = boundsColor;
    }

    public Color getFillColor() {
        return fillColor;
    }

    public void setFillColor(Color fillColor) {
        this.fillColor = fillColor;
    }

    public abstract void tick();

    public abstract void draw(Graphics2D g);    
}

// =============================================

package com.isi.states;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import com.isi.core.Game;
import com.isi.tools.ImageLoader;
import com.isi.uicomponents.Button;
import com.isi.uicomponents.UIComponent;

public class MainMenuState extends GameState {
    
    private static BufferedImage bg = ImageLoader.load("Main Menu Background.jpg");
    
    // Background coordinates for animation
    private int x;
    private int y;
    
    // MainMenu components array
    private ArrayList<UIComponent> components;
    
    public MainMenuState(Game game) {
        super(game);
    
        x = 0;
        y = 0;
        
        components = new ArrayList<UIComponent>();      
        components.add(new Button(game, this, game.getWidth() / 2 - 80 / 2, game.getHeight() / 2 - 50 / 2, 80, 50, "Play"));    
    }

    public ArrayList<UIComponent> getComponents() {
        return components;
    }

    public void tick() {        
        y = y >= game.getHeight() ? 0 : y + 2;
    }

    public void draw(Graphics2D g) {
        g.drawImage(bg, 0, -game.getHeight() + y, game.getWidth(), game.getHeight(), null);
        g.drawImage(bg, x, y, game.getWidth(), game.getHeight(), null);
    
        for (int i = 0; i < components.size(); i++) {
            components.get(i).draw(g);
        }
    }   
}

这很接近,您需要将 x 增加一半宽度,然后将字符串宽度减少一半。您还需要在获取字体规格之前设置字体,否则您将获取现有图形字体的规格。

g.setFont(font);

FontMetrics fm = g.getFontMetrics();
        
int textX = x + (width / 2) - (fm.stringWidth(text) / 2);

int textY = y + ((height - fm.getHeight()) / 2) + fm.getAscent();
        
g.setColor(Color.white);

g.drawString(text, textX, textY);