Java Swing 自定义组件实现文字滚动效果
在 Swing 开发中,如果需要在界面上实现类似跑马灯的滚动文字效果,直接操作组件往往会阻塞事件分发线程(EDT),导致界面假死。因此,最佳实践是利用独立线程来维护滚动状态,并通过 repaint 安全地刷新界面。
核心组件封装
我们创建一个继承自 JButton 的自定义组件 MyComponent。它内部维护一个标签用于显示当前文字,并通过一个独立的滚动线程来控制文字的切换和位置偏移。
import java.awt.Graphics;
import java.util.concurrent.ExecutorService;
import javax.swing.JButton;
import javax.swing.JLabel;
public class MyComponent extends JButton {
private static final long serialVersionUID = 1L;
private JLabel jl2;
private String[] msg;
private int x = 90, y = 17;
private int i = 0;
private Roll roll;
private ExecutorService pool;
public static boolean flag;
public JLabel getJl2() {
return jl2;
}
public void setJl2(JLabel jl2) {
this.jl2 = jl2;
}
public MyComponent() {
super();
this.setLayout(null);
jl2 = new JLabel();
jl2.setBounds(0, 0, 100, 30);
this.add(jl2);
}
/**
* 设置显示值
*/
public void setArrText(String[] msg) {
this.msg = msg;
if (msg != null && msg.length > 0) {
flag = true;
pool = ThreadGroupUtil.getInstance();
if (roll == null) {
roll = new Roll();
pool.execute(roll);
}
} else {
flag = false;
}
}
/**
* 滚动线程,当有业务值传进来时候,启动该线程
*/
class Roll extends Thread {
@Override
public void run() {
while (flag) {
try {
Thread.sleep(100);
if (jl2.getText() != null) {
jl2.setText(null);
}
} catch (InterruptedException e) {
// 忽略中断
}
if ((x -= 1) > -25) {
continue;
}
i = ++i % msg.length;
try {
Thread.sleep(400);
} catch (InterruptedException e) {
// 忽略中断
}
x = 90;
// 触发重绘以更新界面
repaint();
}
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (msg != null) {
if (i < msg.length) {
g.drawString(msg[i], x, y);
}
}
}
}
注意:原逻辑中在 paint 方法内调用 repaint() 会导致递归调用,这里将刷新指令移到了滚动线程的逻辑末尾,确保每次状态变更后安全触发重绘。
线程池管理工具
为了避免频繁创建销毁线程带来的开销,我们使用单例模式管理线程池。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadGroupUtil {
private static ExecutorService pool = null;
private static int size;
static {
size = 400;
System.out.println(size);
pool = Executors.newFixedThreadPool(size);
}
/**
* 得到单例的线程池
*
* @return ExecutorService 线程池
*/
public static ExecutorService getInstance() {
return pool;
}
}
测试运行
最后,编写一个简单的测试类来验证效果。
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestRoll extends JFrame {
public TestRoll() {
JPanel jp = new JPanel();
jp.setLayout(null);
MyComponent component = new MyComponent();
component.setBounds(20, 30, 100, 30);
jp.add(component);
component.setArrText(new String[]{"张三", "李四", "王五"});
this.getContentPane().add(jp);
this.setSize(300, 300);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new TestRoll();
}
}
实际运行时,你会发现文字会按照设定的间隔进行滚动切换。这种方案既保证了界面的响应速度,又实现了流畅的动画效果。

