使用Timer在JTextArea中实现打字机效果? [英] Using Timer to achieve typewriter Effect in JTextArea?

查看:182
本文介绍了使用Timer在JTextArea中实现打字机效果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作文字冒险游戏并遇到了一个问题,我无法以我想要的方式展示我的一些文字。当输入一些单词时,玩家可以开始引入新房间。我希望这个介绍有打字机的效果。此事件需要在我的程序ActionPerformed方法中进行。例如,当用户键入Move然后按Enter键时,我希望生成的文本一次打印一个字符。



这是我使用的当前方法在ActionPerformed之外实现此效果:

  public void slowPrint(String message,long millisPerChar)
{
//使得播放器在显示文本时无法输入
userinput.setEditable(false);
String o;
for(int i = 0; i< message.length(); i ++)
{
//逐个添加每个字母
o =+ message .charAt(ⅰ);
output.append(o);

//将JTextArea移动到底部
output.setCaretPosition(output.getDocument()。getLength());

//延迟,这样你就可以看到每个字母被加上
try {
Thread.sleep(millisPerChar);;
} catch(InterruptedException e){
// TODO自动生成的catch块
e.printStackTrace();显示文本后,
}
//允许用户再次输入
userinput.setEditable(true);
}

如何使用类似的方法来使用Timer类因此它不会阻止我的线程更新GUI。



这是我使用相关方法执行的操作:

  public void actionPerformed(ActionEvent e)
{
s = userinput.getText();
output.append(\ n);
userinput.setText();

for(int i = 0; i< whatRoom.length; i ++)
{
if(whatRoom [i])
{
switch( i)
{
case 0:
controlOne(s);
休息;
案例1:
休息;
案例2:
休息;
案例3:
休息;
案例4:
休息;
案例5:
休息;
}
}
}

}

controlOne()方法:

  private void controlOne(String s)
{
if(one.getHasLight()== true)
{
if(!one.getPushYes())
{
output.append(one.dealWithLight(s,输出));
}

else output.append(one.commands(s));
}
else output.append(one.commands(s));
}

而不是一直追加我想要使用类似于我的东西slowPrint方法。



希望这有一定道理,任何帮助都会非常感激。

解决方案






修改 slowPrint 方法的示例:

  import java.awt.BorderLayout; 
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.Timer;

公共类Foo {

私有JTextField输入;
私有JTextArea输出;

public static void main(String [] args)throws IOException {
EventQueue.invokeLater(() - > new Foo()。createAndShowGUI());
}

public void createAndShowGUI(){
output = new JTextArea();
output.setEditable(false);

input = new JTextField();
input.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
slowPrint(这是一个测试答案。\ n,100 );
}
});

JPanel contentPane = new JPanel(new BorderLayout(5,5));
contentPane.add(input,BorderLayout.NORTH);
contentPane.add(输出);

JFrame frame = new JFrame(Example);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(contentPane);
frame.setSize(800,600);
frame.setVisible(true);
}

public void slowPrint(String message,int millisPerChar){
input.setEditable(false);
input.setFocusable(false);

定时器定时器=新定时器(millisPerChar,null);
timer.addActionListener(new ActionListener(){
int counter = 0;

@Override
public void actionPerformed(ActionEvent e){
output。 append(String.valueOf(message.charAt(counter ++)));
output.setCaretPosition(output.getDocument()。getLength());
if(counter> = message.length()) {
timer.stop();
input.setEditable(true);
input.setFocusable(true);
input.requestFocusInWindow();
}
}
});
timer.start();
}

}


I am making a text adventure game and have run into an issue where I cannot get some of my text display in the fashion I want it to. When entering some words the player could initiate the introduction of a new room. I would want this introduction to have the "typewriter" effect. This event would need to take place in my programs ActionPerformed method. For example when the user types "Move" and then hits enter, I would want the resulting text to print one character at a time.

Here is the current method I use outside of ActionPerformed to achieve this effect:

public void slowPrint(String message, long millisPerChar)
{
    //makes it so that the player cannot input while the text is being displayed
    userinput.setEditable(false);
     String o;
        for (int i = 0; i < message.length(); i++)
        {
            //adds each letter one-by-one
            o = "" + message.charAt(i);
            output.append(o);

            //moves the JTextArea to the bottom
            output.setCaretPosition (output.getDocument ().getLength ());

            //delay so that you can see each letter being added
            try {
                Thread.sleep(millisPerChar);;
                } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace(); }
        }
    //after the text is displayed allow the user to input again
    userinput.setEditable(true);
  }

How can I get a similar method to work with the use of the Timer class so that it does not prevent my thread from updating the GUI.

This is what my action performed looks like with relevant methods:

public void actionPerformed(ActionEvent e)
{
        s = userinput.getText();
        output.append("\n");
        userinput.setText("");

        for (int i = 0; i<whatRoom.length; i++)
        {
            if (whatRoom[i])
            {
                switch(i)
                {
                    case 0:
                        controlOne(s);
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                    case 3:
                        break;
                    case 4:
                        break;
                    case 5:
                        break;
                }
            }
        }

    }

And the "controlOne()" method:

private void controlOne(String s)
{   
    if(one.getHasLight() == true)
    {
        if(!one.getPushYes())
        {
            output.append(one.dealWithLight(s, output));
        }

        else output.append(one.commands(s));
    }
    else output.append(one.commands(s));
}

Instead of appending all the time I would want to use something similar to my "slowPrint" method.

Hopefully this made some sense and any help would be greatly appreciated.

解决方案

The two essential values of a Timer are

  1. The delay
  2. The ActionListener

If you create the timer inside your slowPrint method, it is important to keep a reference to it, so you can stop it later. Therefore you must add the ActionListener later. Inside the ActionListener you could keep track of the current text position by an additional variable (forget about the for-loop). Then you just have to check manually if all text has been printed, and stop the timer accordingly.

If you want the delay to also take place initially, just call timer.setInitialDelay(delay).


Example with your slowPrint method modified:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.Timer;

public class Foo {

    private JTextField input;
    private JTextArea output;

    public static void main(String[] args) throws IOException {
        EventQueue.invokeLater(() -> new Foo().createAndShowGUI());
    }

    public void createAndShowGUI() {
        output = new JTextArea();
        output.setEditable(false);

        input = new JTextField();
        input.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                slowPrint("This is a test answer.\n", 100);
            }
        });

        JPanel contentPane = new JPanel(new BorderLayout(5, 5));
        contentPane.add(input, BorderLayout.NORTH);
        contentPane.add(output);

        JFrame frame = new JFrame("Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(contentPane);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    public void slowPrint(String message, int millisPerChar) {
        input.setEditable(false);
        input.setFocusable(false);

        Timer timer = new Timer(millisPerChar, null);
        timer.addActionListener(new ActionListener() {
            int counter = 0;

            @Override
            public void actionPerformed(ActionEvent e) {
                output.append(String.valueOf(message.charAt(counter++)));
                output.setCaretPosition(output.getDocument().getLength());
                if (counter >= message.length()) {
                    timer.stop();
                    input.setEditable(true);
                    input.setFocusable(true);
                    input.requestFocusInWindow();
                }
            }
        });
        timer.start();
    }

}

这篇关于使用Timer在JTextArea中实现打字机效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆