Java Swing 自定义组件库分享(十一)

滚动面板 --- 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());

六、注意事项

  1. 宽度/高度为0时隐藏滚动条scrollBar() 方法将宽高设为0,滚动条不可见
  2. 异步滚动scrollToBottom 使用 CompletableFuture 异步执行,延迟100ms,避免滚动条未就绪
  3. 滑轨颜色trackColornull 时不绘制滑轨(透明)
  4. 背景色设置UIManager.put("ScrollBar.background", bg) 可设置整体背景色
  5. 单位增量 :构造函数中设置了 setUnitIncrement(32),可根据需要调整

七、小结

CusScrollPane 通过自定义 BasicScrollBarUI 实现了滚动条样式美化,核心要点:

  • 继承 BasicScrollBarUI,重写 paintThumb / paintTrack 绘制圆角滑块和滑轨
  • 重写 createDecreaseButton / createIncreaseButton 隐藏默认箭头按钮
  • 重写 getPreferredSize 控制滚动条尺寸
相关推荐
好家伙VCC1 小时前
Qdrant + LangChain 实战:构建毫秒级语义检索服务
java·langchain
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第93题】【Mysql篇】第23题:从查找速度来看,聚集索引和非聚集索引哪个更快?
java·开发语言·数据库·mysql·面试
摇滚侠1 小时前
JDBC 基础到高级一套通关!高级篇 28-40
java
bbaydnog1 小时前
FreeRTOS学习笔记 18:调试方法论——HardFault排查、栈溢出检测、运行时统计,RTOS调试三板斧
笔记·单片机·freertos
掘金一周2 小时前
问卷调查:如果现在收到裁员通知,你手里的现金流能支撑多久? | 沸点周刊6.4
前端·人工智能·后端
Smoothcloud润云2 小时前
5大功能精修,重构AI算力使用体验!
java·人工智能·windows·算法·重构·编辑器·sublime text
我是唐青枫2 小时前
Java MyBatis-Flex 实战指南:从 BaseMapper 到 QueryWrapper 的轻量 ORM 用法
java·开发语言·mybatis
顺风尿一寸2 小时前
Java Native 方法底层原理深度解析:从 JNI 注册到 Native Wrapper 生成
java
极客先躯2 小时前
高级java每日一道面试题-2026年01月18日-实战篇[Docker]-如何清理仓库中的旧镜像?
java·运维·docker·容器