本文目录导读:

在 Java Swing 中,BasicButtonUI 是 所有 Swing 按钮外观(ButtonUI)的基类,它位于 javax.swing.plaf.basic 包下,定义了按钮绘制、布局、事件处理的通用行为,而具体的外观差异(如颜色、边框、渐变)则由其子类(如 MetalButtonUI、WindowsButtonUI、NimbusButtonUI 等)或自定义 UI 实现。
以下是关于 BasicButtonUI 的详细解析:
核心职责
BasicButtonUI 主要负责三件事:
- 渲染:绘制按钮的背景、边框、文本和图标。
- 布局:计算按钮中文本和图标的位置(通过
SwingUtilities.layoutCompoundLabel)。 - 事件:处理鼠标按下/释放、键盘焦点、启用/禁用等状态变化,并触发重绘。
关键方法
| 方法 | 说明 |
|---|---|
installUI(JComponent c) |
初始化UI,安装默认属性、监听器等。 |
uninstallUI(JComponent c) |
卸载UI,清理监听器和属性。 |
paint(Graphics g, JComponent c) |
主绘制入口,调用 paintButtonBackground、paintFocus、paintButtonBorder、paintText、paintIcon。 |
paintButtonBackground(...) |
绘制背景,默认使用 ButtonUI.paintBackground 颜色。 |
paintFocus(...) |
绘制焦点虚线框。 |
paintButtonBorder(...) |
绘制按钮边框(默认为 BorderFactory.createRaisedBevelBorder() 等)。 |
paintText(...) |
绘制文本,包含禁用状态下的灰色效果。 |
paintIcon(...) |
绘制图标。 |
getPreferredSize(JComponent c) |
返回按钮的最佳大小(基于文本+图标+边距)。 |
典型使用场景
1 继承并自定义按钮外观
如果你想创建一个扁平风格的按钮,可以重写 BasicButtonUI 的关键绘制方法:
import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
public class FlatButtonUI extends BasicButtonUI {
@Override
public void paint(Graphics g, JComponent c) {
AbstractButton b = (AbstractButton) c;
ButtonModel model = b.getModel();
// 1. 绘制自定义背景
if (model.isPressed()) {
g.setColor(new Color(180, 200, 230)); // 按下时颜色
} else if (model.isRollover()) {
g.setColor(new Color(220, 240, 255)); // 悬停时颜色
} else {
g.setColor(b.getBackground());
}
g.fillRect(0, 0, b.getWidth(), b.getHeight());
// 2. 绘制文本和图标(调用父类方法)
super.paint(g, c);
}
@Override
protected void paintButtonBorder(Graphics g, AbstractButton b, int x, int y, int w, int h) {
// 不绘制任何边框(扁平风格)
}
@Override
protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
// 不绘制焦点虚线
}
}
// 使用
JButton btn = new JButton("扁平按钮");
btn.setUI(new FlatButtonUI());
2 修改默认行为
你可以通过重写 installUI 来改变按钮的默认属性(如边距、字体颜色等):
public class CustomButtonUI extends BasicButtonUI {
@Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
b.setMargin(new Insets(10, 20, 10, 20)); // 更大的内边距
b.setFont(b.getFont().deriveFont(Font.BOLD)); // 加粗字体
}
}
与系统外观的集成
BasicButtonUI 是所有平台外观的基类,但每个 LookAndFeel 会提供自己的子类:
WindowsButtonUI(com.sun.java.swing.plaf.windows) — Windows 原生风格。MetalButtonUI(javax.swing.plaf.metal) — Metal 默认风格。NimbusButtonUI(javax.swing.plaf.nimbus) — Nimbus 风格。SynthButtonUI(javax.swing.plaf.synth) — 可配置皮肤风格。
直接使用 BasicButtonUI 通常意味着你希望完全自定义外观,而不是使用任何系统风格。
注意事项
- 状态感知:
BasicButtonUI内部会检查ButtonModel的状态(pressed、rollover、armed、enabled、selected等),并在绘制时做出相应变化,如果你完全重写paint方法,可能丢失这些状态处理。 - 计算位置:
BasicButtonUI使用SwingUtilities.layoutCompoundLabel来计算文本和图标的位置,这个计算已考虑了水平/垂直对齐、边距、图标文本间隙等,推荐在自定义时复用此逻辑。 - 性能:由于
BasicButtonUI不自带任何缓存,如果频繁重绘(如动画),可能会产生性能问题,复杂的自定义 UI 可以考虑双缓冲或预渲染。
简单示例:完整扁平按钮 UI
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
public class FlatButtonUI2 extends BasicButtonUI {
private final Color normalColor = new Color(70, 130, 180);
private final Color hoverColor = new Color(100, 160, 210);
private final Color pressedColor = new Color(50, 100, 150);
@Override
public void installUI(JComponent c) {
super.installUI(c);
AbstractButton b = (AbstractButton) c;
b.setOpaque(false);
b.setBorder(new EmptyBorder(8, 16, 8, 16));
}
@Override
public void paint(Graphics g, JComponent c) {
AbstractButton b = (AbstractButton) c;
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int w = b.getWidth();
int h = b.getHeight();
// 绘制圆角矩形背景
ButtonModel model = b.getModel();
if (model.isPressed()) {
g2.setColor(pressedColor);
} else if (model.isRollover()) {
g2.setColor(hoverColor);
} else {
g2.setColor(normalColor);
}
g2.fillRoundRect(0, 0, w, h, 8, 8);
// 绘制文本(白色,居中)
g2.setColor(Color.WHITE);
FontMetrics fm = g2.getFontMetrics();
String text = b.getText();
int x = (w - fm.stringWidth(text)) / 2;
int y = (h + fm.getAscent()) / 2 - 2;
g2.drawString(text, x, y);
g2.dispose();
}
}
BasicButtonUI是 Swing 按钮 UI 的 骨架,提供了标准流程但很少直接使用。- 当需要完全自定义按钮外观(颜色、形状、动画)时,继承
BasicButtonUI并重写paint及辅助方法是常用做法。 - 若只需轻微调整,应考虑继承特定 LookAndFeel 的 ButtonUI(如
MetalButtonUI),以保留系统原生风格。