简体   繁体   English

Java Swing:长事件期间重绘组件

[英]Java Swing: repaint component during long event

I am working with Java Swing to render my GUI for an application. 我正在使用Java Swing渲染应用程序的GUI。 I have an ActionListener set up on a JButton to fire off a series of tests. 我在JButton上设置了一个ActionListener来触发一系列测试。 Ideally, I would like to update a status area (currently a JTextArea ) with real-time testing information and results. 理想情况下,我想使用实时测试信息和结果更新状态区域(当前为JTextArea )。 In other words, the program would set the text area line-by-line as tests are run and completed to something like: 换句话说,程序会在运行和完成测试时逐行设置文本区域,例如:

Running Tests... 
    Test 1:  Check Something...
         Success
    Test 2:  Check Something else...
         Success
    ..    //More testing output

All tests have completed successfully.  Yay.

The problem is that I can't get the status text to update while my actionPerformed event method is still running. 问题是当我的actionPerformed事件方法仍在运行时,我无法更新状态文本。 This is is all fine and dandy when all of the tests complete quickly. 当所有测试都快速完成时,这一切都很好。 However, some of my tests take an indefinite amount of time to complete (think "database connection timeout"). 但是,我的一些测试花费的时间是不确定的(请考虑“数据库连接超时”)。 When this happens, users are stuck with whatever text was already in the status area and my application freezes until the tests complete or fail. 发生这种情况时,用户将被状态区域中已有的任何文本所困扰,并且我的应用程序将冻结,直到测试完成或失败。

I've tried calling repaint on my JTextArea every time I update the status, but it seems that just adds it to the event queue (which won't get fired till after my actionPerformed event completes...doh). 我每次尝试更新状态时都尝试在JTextArea上调用repaint ,但似乎只是将其添加到事件队列中(直到我的actionPerformed事件完成后才会被触发... doh)。 I've also tried calling revalidate and updateUI , and even tried calling wait() on the ActionListener class running my tests, but nothing has worked thus far. 我还尝试调用revalidateupdateUI ,甚至尝试在运行测试的ActionListener类上调用wait() ,但到目前为止没有任何效果。 Here is the structure of my current code: 这是我当前代码的结构:

..

JTextArea statusOutput_textArea;

..

public void actionPerformed(ActionEvent e) {
    setStatusText("Running Tests...");

    //Run Tests
    int currentTest = 1;

    //Check something
    appendStatusText("        Test " + currentTest++ + ":  Checking Something...");
    ..    //Check Something Here
    appendStatusText("            Success");

    //Check something else
    appendStatusText("        Test " + currentTest++ + ":  Checking Something else...");
    ..    //Check Something Else Here
    appendStatusText("            Success");

    //Other tests
    ..    //Run other tests here

    appendStatusText("\nAll tests have completed successfully.  Yay.");
}//End of actionPerformed method

public void setStatusText (String statusText) {
    statusOutput_textArea.setText(statusText);
    statusOutput_textArea.repaint();
}//End of setStatusText method

public void appendStatusText (String statusTextToAppend) {
    statusOutput_textArea.setText(statusOutput_textArea.getText() + "\n" + statusTextToAppend);
    statusOutput_textArea.repaint();
}//End of appendStatusText method 

Any help would be much appreciated :) 任何帮助将非常感激 :)

UPDATE UPDATE

For those interested in the general structure of the solution, here it is: 对于那些对解决方案的总体结构感兴趣的人,这里是:

public class RunTestsButtonActionListener implements ActionListener {
    JTextArea statusOutput_textArea;
    JButton testDatabaseSettings_JButton;

    public RunTestsButtonActionListener(JTextArea statusOutput_textArea){
        this.statusOutput_textArea = statusOutput_textArea;
    }

    public void actionPerformed(ActionEvent e) {
        testDatabaseSettings_JButton = (JButton) e.getSource();

        Thread tests = new Thread(){
            public void run() {
                //Disable button and add tooltip
                testDatabaseSettings_JButton.setEnabled(false);
                testDatabaseSettings_JButton.setToolTipText("Running Tests...");

                //Run Tests
                try {
                    statusOutput_textArea.setText("Running Tests...");
                    int currentTest = 1;

                    //Check something
                    statusOutput_textArea.append("\n        Test " + currentTest++ + ":  Checking Something...");
                    ..    //Check Something Here
                    statusOutput_textArea.append("\n            Success");

                    //Check something else
                    statusOutput_textArea.append("\n        Test " + currentTest++ + ":  Checking Something else...");
                    ..    //Check Something Else Here
                    statusOutput_textArea.append("\n            Success");

                    //Other tests
                    ..    //Run other tests here

                    statusOutput_textArea.append("\n\nAll tests have completed successfully.  Yay.");
                } finally {
                    //Enable button and remove tooltip
                    testDatabaseSettings_JButton.setEnabled(false);
                    testDatabaseSettings_JButton.setToolTipText("");
                }
            }
        };

        tests.start();
    }
}

You are doing the checks on "the Swing thread", you would be better of performing those tasks in a different thread (which notifies the GUI if something happens/changes). 您正在对“ Swing线程”进行检查,最好在另一个线程中执行这些任务(如果发生/更改,通知GUI)。

Run each test in its own thread so they don't block each other. 在自己的线程中运行每个测试,以免彼此阻塞。 Also, JTextArea already has an thread-safe append method, no need to use setText to simulate append . 而且,JTextArea已经具有线程安全的append方法,无需使用setText来模拟append

The problem is you can't have long running tasks happen in an action. 问题是您不能在一个动作中长时间运行任务。 As you've noticed, nothing will get updated when this happens. 如您所知,这种情况不会更新。

You should try taking a look at SwingWorker or some other background thread. 您应该尝试看看SwingWorker或其他一些后台线程。 You would run your tests in the background thread and every time you want to update the UI you would call: 您将在后台线程中运行测试,并且每次要更新UI时都将调用:

SwingUtils.invokeLater(new Runnable() {
     public void run() {
        appendStatusText(....);
    }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM