Java 使用线程实时更新JTextArea

Java 使用线程实时更新JTextArea,java,multithreading,swing,jtextarea,Java,Multithreading,Swing,Jtextarea,我试图随机生成一个字符串并不断更新JTextArea。我知道程序在无限循环的runTest()方法中挂起。我试图循环并显示这个结果,直到用户点击停止按钮。有什么建议吗?谢谢 import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextArea; import javax.swing.SwingUtiliti

我试图随机生成一个字符串并不断更新JTextArea。我知道程序在无限循环的runTest()方法中挂起。我试图循环并显示这个结果,直到用户点击停止按钮。有什么建议吗?谢谢

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JTextArea;
    import javax.swing.SwingUtilities;
    import java.awt.BorderLayout;
    import java.awt.Panel;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Random;

public class MyApplication extends JFrame {
    private JTextArea textArea;
    private JButton b;
    private String toChange = "";

    // Called from non-UI thread
    private void runQueries() {
        while (true) {
            runTest();
            updateProgress();
        }
    }

    public void runTest() {

        while (true) {

            if (toChange.length() > 10) {
                toChange = "";
            }
            Random rand = new Random();
            toChange += rand.nextInt(10);
        }
    }

    private void updateProgress() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                textArea.append(toChange);
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MyApplication app = new MyApplication();
                app.setVisible(true);
            }
        });
    }

    private MyApplication() {

        this.setLayout(null);
        this.setResizable(false);
        this.setLocation(100, 100);
        this.setSize(900, 600);

        final Panel controlPanel = new Panel();
        controlPanel.setLayout(new BorderLayout());
        controlPanel.setSize(600, 200);
        controlPanel.setLocation(50, 50);
        setDefaultCloseOperation(this.EXIT_ON_CLOSE);

        textArea = new JTextArea("test");
        textArea.setSize(100, 100);
        textArea.setLocation(200, 200);
        this.add(textArea);

        JButton b = new JButton("Run query");
        b.setSize(100, 75);
        b.setLocation(100, 50);
        this.add(b);

        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Thread queryThread = new Thread() {
                    public void run() {
                        runQueries();

                    }
                };
                queryThread.start();

            }
        });

    }

}
你会想要像我刚才做的那样的东西。否则,您只需冻结线程,因此,
updateProgress()从未被调用

请注意,为什么在
runTest()
方法中甚至需要
while(true)
循环?
runquerys()
中的while-true循环始终在运行和更新它,这意味着
while(true)
循环似乎没有任何意义

澄清: 我是说你应该把runTest()和updateProgress()放在一个延迟的任务中,而不是一个while-true循环——否则,你只是把它们放在同一个线程中而耽误了另一个任务

但是,更改此选项也可以解决此问题:

b.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           int initialDelay = 100; // start after 0.1 seconds
           int period = 100;        // repeat every 0.1 seconds
        {
            Timer timer = new Timer();
            TimerTask task = new TimerTask() {
            public void run() {
                runTest();
            };
        timer.scheduleAtFixedRate(task, initialDelay, period);
        }
        {
            Timer timer = new Timer();
            TimerTask task = new TimerTask() {
            public void run() {
                updateProgress();
            };
        timer.scheduleAtFixedRate(task, initialDelay, period);
        }
    }
    });

}
和runTest()

和updateProgress()

注意,我是在SO编辑器中输入代码,而不是在IDE中。很抱歉出现语法错误

你会想要像我刚才做的那样的东西。否则,您只需冻结线程,因此,
updateProgress()从未被调用

请注意,为什么在
runTest()
方法中甚至需要
while(true)
循环?
runquerys()
中的while-true循环始终在运行和更新它,这意味着
while(true)
循环似乎没有任何意义

澄清: 我是说你应该把runTest()和updateProgress()放在一个延迟的任务中,而不是一个while-true循环——否则,你只是把它们放在同一个线程中而耽误了另一个任务

但是,更改此选项也可以解决此问题:

b.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           int initialDelay = 100; // start after 0.1 seconds
           int period = 100;        // repeat every 0.1 seconds
        {
            Timer timer = new Timer();
            TimerTask task = new TimerTask() {
            public void run() {
                runTest();
            };
        timer.scheduleAtFixedRate(task, initialDelay, period);
        }
        {
            Timer timer = new Timer();
            TimerTask task = new TimerTask() {
            public void run() {
                updateProgress();
            };
        timer.scheduleAtFixedRate(task, initialDelay, period);
        }
    }
    });

}
和runTest()

和updateProgress()

注意,我是在SO编辑器中输入代码,而不是在IDE中。很抱歉出现语法错误。

请尝试此操作

 private void runQueries() {
    while (!stop) {
        runTest();
        updateProgress();
    }
}
当您想要完全停止时,make
stop
为真,例如点击停止按钮。然后

public void runTest() {

    while (true) {

        if (toChange.length() > 10) {
            toChange = "";
            break;  
        }
        Random rand = new Random();
        toChange += rand.nextInt(10);
    }
}
如果不中断循环,您的
updateProgress
将不会调用..

试试这个

 private void runQueries() {
    while (!stop) {
        runTest();
        updateProgress();
    }
}
当您想要完全停止时,make
stop
为真,例如点击停止按钮。然后

public void runTest() {

    while (true) {

        if (toChange.length() > 10) {
            toChange = "";
            break;  
        }
        Random rand = new Random();
        toChange += rand.nextInt(10);
    }
}

如果不中断循环,您的
updateProgress
将不会调用..

最重要的事情之一是,Java中的所有GUI元素都应该在EventDispatchThread上运行,否则可能会导致不可预知的错误行为

请在此阅读:

从您当前的代码可以看出,您正在通过在一个恒定循环中冻结应用程序来对其进行实时锁定

您需要做的是创建一个单独的线程,该线程在创建时会不断更新EDT中的TextArea,但会在主应用程序中引用该线程。 一旦用户按下按钮(这将在EDT上),它应该告诉主线程终止单独的线程,从而停止更新


如果您陷入困境,请随时询问更详细的步骤。

我不能强调的最重要的一点是,Java中的所有GUI元素都应该在EventDispatchThread上运行,否则可能会导致不可预知的错误行为

请在此阅读:

从您当前的代码可以看出,您正在通过在一个恒定循环中冻结应用程序来对其进行实时锁定

您需要做的是创建一个单独的线程,该线程在创建时会不断更新EDT中的TextArea,但会在主应用程序中引用该线程。 一旦用户按下按钮(这将在EDT上),它应该告诉主线程终止单独的线程,从而停止更新


如果您陷入困境,请随时询问更详细的步骤。

我认为您需要在新线程上重复执行任务。请给我一分钟时间获取代码。将
线程queryThread
设为类变量,并在“停止”按钮的
actionPerformed()
方法中执行
queryThread.interrupt()
。有关更多信息,请参阅。Java GUI必须在不同的操作系统、屏幕大小、屏幕分辨率等上工作。因此,它们不利于像素完美布局。请改为使用布局管理器,或与布局填充和边框一起使用。请参见所示示例。希望如果您阅读了整个主题,您会学到很多关于Swing中并发性的知识。也可以启动和停止,也可以作为SwingWorker的替代品。我想你需要一个新线程上的重复任务。请给我一分钟时间获取代码。将
线程queryThread
设为类变量,并在“停止”按钮的
actionPerformed()
方法中执行
queryThread.interrupt()
。有关更多信息,请参阅。Java GUI必须在不同的操作系统、屏幕大小、屏幕分辨率等上工作。因此,它们不利于像素完美布局。请改为使用布局管理器,或与布局填充和边框一起使用。请参见所示示例。希望如果您阅读了整个主题,您会学到很多关于Swing中并发性的知识。也可以启动和停止,可以作为SwingWorker的替代品。我很难理解这一点,你能用我给出的例子详细说明一下吗?应该在哪里创建计时器?Thanks@JavaNoob我添加了一些澄清,加上一个我之前没有意识到的解决方案。啊,解决方案显示一次,然后冻结程序。@JavaNoob Try now。它应该在不同的线程上不断运行updateProgress()和runTest()。。。这些是正确的进口货吗?导入java.util.TimerTask;导入javax.swing.Timer;我很难理解这一点,你能用我给出的例子详细说明一下吗?该去哪里