【问题标题】:I can't center text in java swing我无法在 java swing 中居中文本
【发布时间】:2020-08-25 13:48:54
【问题描述】:

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

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

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

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

【问题讨论】:

  • 请将代码发布为文本,而不是文本图像。您应该发布您的一项尝试(有人可能会帮助您修复)。
  • 您可以发布您正在创建的自定义组件的代码吗?另外,为什么要构建自定义组件,为什么不使用 JLabel 或 JTextField?
  • 你是如何绘制按钮的?请将代码贴在原帖中。
  • 您是否尝试过按照此处的建议使用 fm.getStringBounds() 的宽度和高度:stackoverflow.com/a/14284949/9560885
  • 发布正确的minimal reproducible example 来演示问题。那就是我们需要框架和带有自定义绘画的JPanel。我们应该能够复制/粘贴/编译//测试您发布的任何代码。

标签: java swing graphics2d fontmetrics


【解决方案1】:

这就接近了,你需要将 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);

【讨论】:

  • 我得到了同样的结果
  • 已更新,立即查看@RonDev
  • 还是一样的结果。
  • 非常感谢,效果很好。问题确实出在我的代码中。
  • @RonDev 您的原始公式是正确的。大多数人不会除以 2 两次。这个答案提出了 2 处更改。只有在获取 FontMetrics 之前设置字体的建议是必要的。修复错误时的提示。一次只进行一项更改,然后是文本。
猜你喜欢
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
  • 2011-06-04
  • 2017-05-15
  • 1970-01-01
  • 1970-01-01
  • 2015-02-05
  • 1970-01-01
相关资源
最近更新 更多