如何在JTextPane中实现文字逐字符延迟显示及点击跳过效果?
实现方案
核心逻辑说明
- 用
javax.swing.Timer做延迟触发器,避免阻塞Swing的事件调度线程(EDT)导致界面卡顿 - 通过操作JTextPane内置的
StyledDocument实现字符追加,替代JTextArea的append方法 - 增加状态控制变量和Timer实例引用,支持点击事件触发直接展示全量文本、终止逐字输出
第一步:修改自定义JTextPanePlus类
在原有基础上增加逐字输出相关的方法和变量,代码如下:
import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class JTextPanePlus extends JTextPane { Image image; int x,y,width,height; // 逐字输出相关变量 private Timer typeTimer; private String fullText; // 要显示的完整文本 private int currentCharIndex = 0; // 当前已输出的字符下标 private int typeSpeed = 50; // 逐字输出间隔,单位毫秒,可自行调整 private boolean isTyping = false; // 是否正在逐字输出 public JTextPanePlus(){ super(); initTypeListener(); // 初始化点击终止的监听器 } public JTextPanePlus(String text){ super(); initTypeListener(); } // 初始化鼠标点击终止逐字输出的监听器 private void initTypeListener() { this.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (isTyping) { stopTypingAndShowFull(); } } }); } public void setImage(ImageIcon icon, int x, int y, int width, int height) { this.image = icon.getImage(); this.x = x; this.y = y; this.width = width; this.height = height; setOpaque(false); repaint(); } // 对外暴露的逐字输出方法,传入要显示的完整文本 public void startTyping(String text) { // 如果上一次还在输出,先停止 if (isTyping) { stopTypingAndShowFull(); } this.fullText = text; this.currentCharIndex = 0; setText(""); // 清空原有内容 isTyping = true; // 初始化Timer typeTimer = new Timer(typeSpeed, e -> { if (currentCharIndex < fullText.length()) { try { StyledDocument doc = getStyledDocument(); doc.insertString(doc.getLength(), String.valueOf(fullText.charAt(currentCharIndex)), null); currentCharIndex++; } catch (BadLocationException ex) { ex.printStackTrace(); } } else { // 全部输出完毕,停止Timer stopTyping(); } }); typeTimer.start(); } // 停止逐字输出并显示完整文本 public void stopTypingAndShowFull() { stopTyping(); setText(fullText); } // 停止Timer重置状态 private void stopTyping() { if (typeTimer != null && typeTimer.isRunning()) { typeTimer.stop(); } isTyping = false; currentCharIndex = 0; } // 可自定义打字速度的方法 public void setTypeSpeed(int speedMs) { this.typeSpeed = speedMs; } @Override public void paint(Graphics g){ g.drawImage(image, x, y, width, height, null); super.paint(g); } }
第二步:修改Frame2类的调用逻辑
把原来直接setText的逻辑替换为调用startTyping方法即可,鼠标点击触发显示的地方调整如下:
import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class Frame2 extends JFrame { private JPanel contentPane; Frame1 frms = new Frame1(); // 保留你原有icon4的定义即可,此处仅为示例 private ImageIcon icon4 = new ImageIcon("你的背景图本地路径"); public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Frame2 frame = new Frame2(); frame.setVisible(true); frame.setResizable(false); } catch (Exception e) { e.printStackTrace(); } } }); } public Frame2() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(250, 100, 799, 526); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); final JTextPanePlus pnText1 = new JTextPanePlus(); pnText1.setImage(icon4, -70, -100, 600, 500); pnText1.setVisible(false); pnText1.setFont(new Font("Tahoma", Font.PLAIN , 16)); pnText1.setEditable(false); pnText1.setForeground(Color.WHITE); pnText1.setBounds(60, 343, 527, 111); contentPane.add(pnText1); // 保留你原有backgroundLabel的定义即可,此处仅为示例 JLabel backgroundLabel = new JLabel(); backgroundLabel.setBounds(0,0,799,526); contentPane.add(backgroundLabel); backgroundLabel.addMouseListener(new MouseAdapter(){ @Override public void mouseClicked(MouseEvent arg0) { pnText1.setVisible(true); // 调用逐字输出方法,传入你要显示的完整文本 pnText1.startTyping("Some text dasdasdasdasdasdas 可替换为你的小说/游戏文本内容"); // 若需调整打字速度,可提前调用pnText1.setTypeSpeed(30); 数值越小速度越快 } }); } }
效果说明
- 点击背景后,JTextPanePlus会以设置的间隔逐字输出文本
- 输出过程中点击JTextPanePlus区域,会立刻停止逐字输出,直接展示完整文本
- 全程所有UI操作都在Swing的EDT线程执行,不会出现界面卡顿的问题,符合Swing线程规范
内容的提问来源于stack exchange,提问作者Overlord99
相关产品推荐
相关产品推荐

