我无法在Java Swing中将文本居中

问题描述

我正在为游戏制作自定义组件,并且尝试了在Stack Overflow中发现的所有内容,无论我仍然无法将文本放置在矩形的中心。我什至阅读了使用Java文本API的所有文档。

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

到目前为止,我已经使用了FontMetrics,并使用stringWidth()方法测量了宽度,并使用了上升(没有一个是准确的)来测量高度。

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,int height) {
        super(game,height);
    
        text = null;
    }
    
    public String getText() {
        return text;
    }
    
    @Override
    public void tick() {
        
    }

    @Override
    public void draw(Graphics2D g) {        
        g.setColor(fillColor);
        g.fillRect(x,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,int height) {
        this.game = game;
        this.state = state;
        
        this.x = x;
        this.y = y;
        
        this.width = width;
        this.height = height;
        
        bounds = new Rectangle(x,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,-game.getHeight() + y,game.getWidth(),game.getHeight(),null);
        g.drawImage(bg,null);
    
        for (int i = 0; i < components.size(); i++) {
            components.get(i).draw(g);
        }
    }   
}

enter image description here

解决方法

这很接近,您需要将x增加一半的宽度,然后再减少一半的字符串宽度。您还需要先设置字体,然后再获取字体指标,否则将获取现有Graphics字体的指标。

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);