Java JButton自定义绘制背景异常,如何获取正确位置并修复?
我来帮你搞定这个问题!你猜的完全没错,问题根源就是绘制背景时用错了坐标。
问题原因
在paintComponent(Graphics g)方法里,传入的Graphics对象用的是组件自身的局部坐标系——简单说,这个坐标系的原点(0,0)就是当前按钮的左上角,和按钮在父容器里的位置没关系。你现在用getX()和getY()获取的是按钮在父面板里的绝对位置,这就导致第二个按钮的背景被画到了它自己的组件区域外面,自然就看不到了。
修复方案
把fillRoundRect的前两个参数改成0,0,让背景绘制在按钮自己的区域内就行。另外还有几个小细节可以优化,让按钮的表现更稳定:
- 不要注释掉
super.paintComponent(g):它会帮你处理按钮的状态变化(比如按下、hover效果)、透明背景等默认逻辑,如果一定要完全自定义绘制,也要记得处理isOpaque()状态。 - 优化文本居中计算:用
FontMetrics.getAscent()来计算基线位置,文本居中会更准确。
修改后的完整代码
import javax.swing.*; import java.awt.*; import org.jetbrains.annotations.NotNull; public class JRoundedButton extends JButton { private int arcRadius; public JRoundedButton(String label, int arcRadius) { super(label); this.setContentAreaFilled(false); // 设置opaque为true,避免父容器在按钮下方绘制导致闪烁 this.setOpaque(true); this.arcRadius = arcRadius; } @Override protected void paintComponent(Graphics g) { if (g instanceof Graphics2D) { // 先调用super方法处理基础绘制逻辑 super.paintComponent(g); Graphics2D graphics = (Graphics2D) g; graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 使用组件自身的局部坐标(0,0)作为起始点 graphics.setColor(getBackground()); graphics.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, arcRadius, arcRadius); // 绘制文本 this.paintText(graphics); } } protected final void paintText(@NotNull Graphics2D g) { if (this.getFont() != null && this.getText() != null) { FontMetrics fm = getFontMetrics(getFont()); g.setColor(this.getForeground()); // 更精准的文本居中计算 int x = (getWidth() - fm.stringWidth(getText())) / 2; int y = (getHeight() + fm.getAscent()) / 2 - fm.getDescent(); g.drawString(getText(), x, y); } } }
效果说明
修改后,不管GridLayout怎么布局按钮,背景都会正确绘制在按钮自身的区域内,两个按钮的背景都能正常显示,文本居中也会更美观。
内容的提问来源于stack exchange,提问作者F_Schmidt
相关产品推荐
相关产品推荐

