滚动面板 --- CusScrollPane
一、背景
Swing 原生 JScrollPane 的滚动条样式是系统默认的,不同操作系统下风格不一致,且无法自定义颜色、圆角、宽度等。在追求统一 UI 风格的应用中,原生滚动条往往显得格格不入。
CusScrollPane 的作用就是:通过自定义 BasicScrollBarUI 美化滚动条外观,支持圆角滑块、自定义颜色、隐藏增减按钮、调整滚动条宽度等功能。
二、核心设计
CusScrollPane 继承 JScrollPane,内部定义 CusScrollBar 类继承 BasicScrollBarUI,重写以下方法实现自定义:
createDecreaseButton/createIncreaseButton:返回空按钮,隐藏默认的增减箭头getPreferredSize:设置滚动条宽度/高度paintThumb:绘制滑块(圆角矩形)paintTrack:绘制滑轨(圆角矩形)
三、类源码
java
import cn.hutool.core.thread.ThreadUtil;
import javax.swing.*;
import javax.swing.plaf.basic.BasicScrollBarUI;
import java.awt.*;
import java.util.concurrent.CompletableFuture;
/**
* 自定义滚动面板
* 通过自定义 BasicScrollBarUI 美化滚动条,支持圆角、自定义颜色、隐藏增减按钮
*
* 使用示例:
* CusScrollPane scrollPane = new CusScrollPane(table);
* scrollPane.verticalScrollBar(null, Color.LIGHT_GRAY, Color.GRAY, 8);
*/
public class CusScrollPane extends JScrollPane {
public CusScrollPane() {
super();
scrollBar();
getVerticalScrollBar().setUnitIncrement(32);
getViewport().setOpaque(false);
}
public CusScrollPane(Component view) {
super(view);
scrollBar();
getVerticalScrollBar().setUnitIncrement(32);
getViewport().setOpaque(false);
}
public CusScrollPane(int vsbPolicy, int hsbPolicy) {
super(vsbPolicy, hsbPolicy);
scrollBar();
getVerticalScrollBar().setUnitIncrement(32);
getViewport().setOpaque(false);
}
public CusScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
super(view, vsbPolicy, hsbPolicy);
scrollBar();
getVerticalScrollBar().setUnitIncrement(32);
getViewport().setOpaque(false);
}
/**
* 隐藏滚动条(不显示)
*/
public void scrollBar() {
scrollBar(null, null, null, 0, 0);
}
/**
* 设置纵向滚动条样式
* @param bg 滚动条背景色(整体)
* @param trackColor 滑轨颜色
* @param thumbColor 滑块颜色
* @param width 滚动条宽度
*/
public void verticalScrollBar(Color bg, Color trackColor, Color thumbColor, int width) {
int height = 0 == width ? 0 : getPreferredSize().height;
scrollBar(bg, trackColor, thumbColor, width, height);
}
/**
* 设置横向滚动条样式
* @param bg 滚动条背景色(整体)
* @param trackColor 滑轨颜色
* @param thumbColor 滑块颜色
* @param height 滚动条高度
*/
public void horizontalScrollBar(Color bg, Color trackColor, Color thumbColor, int height) {
int width = 0 == height ? 0 : getPreferredSize().width;
scrollBar(bg, trackColor, thumbColor, width, height);
}
/**
* 设置滚动条样式(完整参数)
* @param bg 滚动条背景色(整体)
* @param trackColor 滑轨颜色
* @param thumbColor 滑块颜色
* @param width 垂直滚动条宽度
* @param height 水平滚动条高度
*/
public void scrollBar(Color bg, Color trackColor, Color thumbColor, int width, int height) {
JScrollBar verticalScrollBar = getVerticalScrollBar();
verticalScrollBar.setUI(new CusScrollBar(bg, trackColor, thumbColor, width, height));
JScrollBar horizontalScrollBar = getHorizontalScrollBar();
horizontalScrollBar.setUI(new CusScrollBar(bg, trackColor, thumbColor, width, height));
}
/**
* 滚动到底部
*/
public void scrollToBottom() {
CompletableFuture.runAsync(() -> {
ThreadUtil.sleep(100);
JScrollBar verticalScrollBar = getVerticalScrollBar();
verticalScrollBar.setValue(verticalScrollBar.getMaximum());
});
}
/**
* 自定义滚动条 UI
*/
static class CusScrollBar extends BasicScrollBarUI {
private Color thumbColor = new Color(77, 74, 74);
private final Color trackColor;
private final int width;
private final int height;
/** 固定圆角半径 */
private static final int ARC = 15;
public CusScrollBar(Color bg, Color trackColor, Color thumbColor, int width, int height) {
UIManager.put("ScrollBar.background", bg);
this.trackColor = trackColor;
if (thumbColor != null) {
this.thumbColor = thumbColor;
}
this.width = width;
this.height = height;
}
@Override
protected JButton createDecreaseButton(int orientation) {
return createZeroButton();
}
@Override
protected JButton createIncreaseButton(int orientation) {
return createZeroButton();
}
private JButton createZeroButton() {
JButton button = new JButton();
button.setPreferredSize(new Dimension(0, 0));
button.setMinimumSize(new Dimension(0, 0));
button.setMaximumSize(new Dimension(0, 0));
return button;
}
@Override
public Dimension getPreferredSize(JComponent c) {
return new Dimension(this.width, this.height);
}
@Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
if (!thumbBounds.isEmpty() && scrollbar.isEnabled()) {
drawRoundRect(thumbColor, g, thumbBounds);
}
}
@Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
if (trackColor != null) {
drawRoundRect(trackColor, g, trackBounds);
}
}
private void drawRoundRect(Color color, Graphics g, Rectangle rectangle) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2.setColor(color);
g2.fillRoundRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height, ARC, ARC);
g2.dispose();
}
}
}
四、核心功能说明
滚动条样式定制:
verticalScrollBar/horizontalScrollBar:分别设置纵向/横向滚动条样式scrollBar:统一设置两个方向的滚动条样式scrollBar():隐藏滚动条(宽度/高度设为0)
CusScrollBar 核心重写:
createDecreaseButton/createIncreaseButton:返回零尺寸按钮,隐藏默认箭头getPreferredSize:返回自定义滚动条尺寸paintThumb:绘制滑块(圆角矩形)paintTrack:绘制滑轨(圆角矩形)
其他功能:
scrollToBottom:异步滚动到底部(适用于聊天、日志等场景)setUnitIncrement(32):鼠标滚轮滚动步长
五、使用示例
5.1 基本用法
java
CusScrollPane scrollPane = new CusScrollPane(table);
panel.add(scrollPane);
5.2 自定义滚动条样式
java
CusScrollPane scrollPane = new CusScrollPane(table);
// 设置纵向滚动条:滑轨浅灰色,滑块灰色,宽度8px
scrollPane.verticalScrollBar(null, Color.LIGHT_GRAY, Color.GRAY, 8);
5.3 隐藏滚动条
java
CusScrollPane scrollPane = new CusScrollPane(table);
scrollPane.scrollBar(); // 不显示滚动条
5.4 滚动到底部
java
scrollPane.scrollToBottom();
5.5 完整配置示例
java
CusScrollPane scrollPane = new CusScrollPane(table);
scrollPane.verticalScrollBar(Color.WHITE, new Color(220, 220, 220), new Color(180, 180, 180), 10);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
六、注意事项
- 宽度/高度为0时隐藏滚动条 :
scrollBar()方法将宽高设为0,滚动条不可见 - 异步滚动 :
scrollToBottom使用CompletableFuture异步执行,延迟100ms,避免滚动条未就绪 - 滑轨颜色 :
trackColor为null时不绘制滑轨(透明) - 背景色设置 :
UIManager.put("ScrollBar.background", bg)可设置整体背景色 - 单位增量 :构造函数中设置了
setUnitIncrement(32),可根据需要调整
七、小结
CusScrollPane 通过自定义 BasicScrollBarUI 实现了滚动条样式美化,核心要点:
- 继承
BasicScrollBarUI,重写paintThumb/paintTrack绘制圆角滑块和滑轨 - 重写
createDecreaseButton/createIncreaseButton隐藏默认箭头按钮 - 重写
getPreferredSize控制滚动条尺寸