如何使文本在 JTextPane 中出现延迟?
How to make text appear delayed in JTextPane?
public class Frame2 扩展 JFrame {
private JPanel contentPane;
Frame1 frms = new Frame1();
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(); // final because listener requires this
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.setText("Some text dasdasdasdasdasdas");
pnText1.setBounds(60, 343, 527, 111);
contentPane.add(pnText1);
//...
backgroundLabel.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent arg0) {
pnText1.setVisible(true);
}
});
// ...
}
为 JTextPane 选择图像的方法
public class JTextPanePlus 扩展了 JTextPane {
Image image;
int x,y,width,height;
public JTextPanePlus(){
super();
}
public JTextPanePlus(String text){
super();
}
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 paint(Graphics g){
g.drawImage(image, x, y, width, height, null);
super.paint(g);
}
}
我无法让 JTextPane (JTextPanePlus) 的文本在每个字符之间出现轻微延迟。基本上我想为小说或冒险创造一种效果。如果用户不想等待整个文本出现,我可以添加一个“mouseListener”并立即显示文本(停止该方法)。
现在的问题是我不知道该怎么做。这里的大多数主题都涵盖了 JTextArea 的内容,我不确定是否可以为 JTextPane 做同样的事情。
我试着做“for(char c : s.toCharArray())”,但后来我不知道如何处理“c”,而且这种方法似乎只适用于打印。尝试使用“Thread.sleep”,但这会冻结整个 JFrame。 Java.swing.timer 可以工作,但 JTextPane 在使用时不支持“.append”。
我 运行 别无选择,而且我不是这方面的专家。这是我第一次从事如此艰巨的工作。另外,如果这没有得到最好的解释,我真的很抱歉。
JTextPane
和 JTextArea
的基本思路相同。问题是,JTextPane
在渲染功能方面更强大,并且不提供 JTextArea
提供的一些辅助方法,例如 append
,相反,您将拥有自己做。
话虽如此,这是一个非常基本的示例。此示例从嵌入式文件资源加载“星球大战,新希望”脚本并打印它,就像打字机一样。
如果您点击 停止,它将停止 Timer
并为当前行附加剩余的文本。有趣的是,如果你再次启动它,它会从中断的地方继续,整洁的副作用。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.Timer;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextPane textPane;
private Timer timer;
private List<String> lines;
private String currentLine;
private int currentLinePosition;
public TestPane() {
setLayout(new BorderLayout());
textPane = new JTextPane();
add(new JScrollPane(textPane));
JPanel actionsPane = new JPanel(new GridBagLayout());
JButton makeItSo = new JButton("Make it so");
JButton stop = new JButton("Stop");
actionsPane.add(makeItSo);
makeItSo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
makeItSo();
makeItSo.setEnabled(false);
stop.setEnabled(true);
}
});
actionsPane.add(stop);
stop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stopTimer();
makeItSo.setEnabled(true);
stop.setEnabled(false);
}
});
add(actionsPane, BorderLayout.SOUTH);
loadScript();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void loadScript() {
lines = new ArrayList<>(128);
try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/scripts/StarWarANewHope.txt")))) {
for (String line = br.readLine(); line != null; line = br.readLine()) {
lines.add(line);
}
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected int startPosition(String text) {
if (text.isEmpty() || text.isBlank()) {
return 0;
}
int index = 0;
while (Character.isWhitespace(text.charAt(index))) {
index++;
}
return index;
}
protected void insertWithOutError(String text) {
try {
insert(text);
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected void insert(String text) throws BadLocationException {
Document document = textPane.getDocument();
document.insertString(document.getLength(), text, null);
}
protected void stopTimer() {
if (timer != null) {
timer.stop();
timer = null;
}
if (currentLine != null) {
if (currentLinePosition < currentLine.length()) {
String text = currentLine.substring(currentLinePosition);
try {
insert(text);
insertWithOutError("\n");
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
currentLine = null;
}
protected void makeItSo() {
stopTimer();
if (lines.isEmpty()) {
return;
}
try {
// Pop the first line
currentLine = lines.remove(0);
int offset = startPosition(currentLine);
if (currentLine.isBlank() || offset == currentLine.length()) {
insertWithOutError("\n");
} else {
String leading = currentLine.substring(0, offset);
insert(leading);
}
currentLinePosition = 0;
currentLine = currentLine.trim();
timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (currentLinePosition < currentLine.length()) {
try {
String next = currentLine.substring(currentLinePosition, currentLinePosition + 1);
insert(next);
currentLinePosition++;
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
stopTimer();
}
} else {
insertWithOutError("\n");
makeItSo();
}
}
});
timer.start();
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
现在,JTextPane
可以支持 StyledDocument
s,这使它变得有些复杂。你会注意到我什至没有尝试支持“属性”,你必须自己解决这个问题
public class Frame2 扩展 JFrame {
private JPanel contentPane;
Frame1 frms = new Frame1();
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(); // final because listener requires this
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.setText("Some text dasdasdasdasdasdas");
pnText1.setBounds(60, 343, 527, 111);
contentPane.add(pnText1);
//...
backgroundLabel.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent arg0) {
pnText1.setVisible(true);
}
});
// ...
}
为 JTextPane 选择图像的方法
public class JTextPanePlus 扩展了 JTextPane {
Image image;
int x,y,width,height;
public JTextPanePlus(){
super();
}
public JTextPanePlus(String text){
super();
}
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 paint(Graphics g){
g.drawImage(image, x, y, width, height, null);
super.paint(g);
}
}
我无法让 JTextPane (JTextPanePlus) 的文本在每个字符之间出现轻微延迟。基本上我想为小说或冒险创造一种效果。如果用户不想等待整个文本出现,我可以添加一个“mouseListener”并立即显示文本(停止该方法)。
现在的问题是我不知道该怎么做。这里的大多数主题都涵盖了 JTextArea 的内容,我不确定是否可以为 JTextPane 做同样的事情。
我试着做“for(char c : s.toCharArray())”,但后来我不知道如何处理“c”,而且这种方法似乎只适用于打印。尝试使用“Thread.sleep”,但这会冻结整个 JFrame。 Java.swing.timer 可以工作,但 JTextPane 在使用时不支持“.append”。
我 运行 别无选择,而且我不是这方面的专家。这是我第一次从事如此艰巨的工作。另外,如果这没有得到最好的解释,我真的很抱歉。
JTextPane
和 JTextArea
的基本思路相同。问题是,JTextPane
在渲染功能方面更强大,并且不提供 JTextArea
提供的一些辅助方法,例如 append
,相反,您将拥有自己做。
话虽如此,这是一个非常基本的示例。此示例从嵌入式文件资源加载“星球大战,新希望”脚本并打印它,就像打字机一样。
如果您点击 停止,它将停止 Timer
并为当前行附加剩余的文本。有趣的是,如果你再次启动它,它会从中断的地方继续,整洁的副作用。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.Timer;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextPane textPane;
private Timer timer;
private List<String> lines;
private String currentLine;
private int currentLinePosition;
public TestPane() {
setLayout(new BorderLayout());
textPane = new JTextPane();
add(new JScrollPane(textPane));
JPanel actionsPane = new JPanel(new GridBagLayout());
JButton makeItSo = new JButton("Make it so");
JButton stop = new JButton("Stop");
actionsPane.add(makeItSo);
makeItSo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
makeItSo();
makeItSo.setEnabled(false);
stop.setEnabled(true);
}
});
actionsPane.add(stop);
stop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stopTimer();
makeItSo.setEnabled(true);
stop.setEnabled(false);
}
});
add(actionsPane, BorderLayout.SOUTH);
loadScript();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void loadScript() {
lines = new ArrayList<>(128);
try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/scripts/StarWarANewHope.txt")))) {
for (String line = br.readLine(); line != null; line = br.readLine()) {
lines.add(line);
}
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected int startPosition(String text) {
if (text.isEmpty() || text.isBlank()) {
return 0;
}
int index = 0;
while (Character.isWhitespace(text.charAt(index))) {
index++;
}
return index;
}
protected void insertWithOutError(String text) {
try {
insert(text);
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected void insert(String text) throws BadLocationException {
Document document = textPane.getDocument();
document.insertString(document.getLength(), text, null);
}
protected void stopTimer() {
if (timer != null) {
timer.stop();
timer = null;
}
if (currentLine != null) {
if (currentLinePosition < currentLine.length()) {
String text = currentLine.substring(currentLinePosition);
try {
insert(text);
insertWithOutError("\n");
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
currentLine = null;
}
protected void makeItSo() {
stopTimer();
if (lines.isEmpty()) {
return;
}
try {
// Pop the first line
currentLine = lines.remove(0);
int offset = startPosition(currentLine);
if (currentLine.isBlank() || offset == currentLine.length()) {
insertWithOutError("\n");
} else {
String leading = currentLine.substring(0, offset);
insert(leading);
}
currentLinePosition = 0;
currentLine = currentLine.trim();
timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (currentLinePosition < currentLine.length()) {
try {
String next = currentLine.substring(currentLinePosition, currentLinePosition + 1);
insert(next);
currentLinePosition++;
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
stopTimer();
}
} else {
insertWithOutError("\n");
makeItSo();
}
}
});
timer.start();
} catch (BadLocationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
现在,JTextPane
可以支持 StyledDocument
s,这使它变得有些复杂。你会注意到我什至没有尝试支持“属性”,你必须自己解决这个问题