简体   繁体   English

JTextField不会使用Thread.sleep()更新

[英]JTextField Doesn't Update With Thread.sleep()

I'm trying to figure out why the text field isn't updating. 我试图弄清楚为什么文本字段没有更新。 I'm aware that using SwingWorker will probably fix this problem, but I can't understand why it doesn't work in the first place. 我知道使用SwingWorker可能会解决此问题,但是我不明白为什么它首先不起作用。

public class waitExample {

private JFrame frame;
private JTextField txtLeadingText;
private String one = "update string 1";
private String two = "update string 2";
private String three = "update string 3";

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                waitExample window = new waitExample();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public waitExample() {
    initialize();
}

private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    txtLeadingText = new JTextField();
    txtLeadingText.setHorizontalAlignment(SwingConstants.CENTER);
    txtLeadingText.setText("leading text");
    frame.getContentPane().add(txtLeadingText, BorderLayout.SOUTH);
    txtLeadingText.setColumns(10);

    JButton btnClickMeTo = new JButton("CLICK ME TO UPDATE TEXT");
    btnClickMeTo.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent arg0) {

            try {

                updateOne();
                Thread.sleep(1000);
                updateTwo();
                Thread.sleep(1000);
                updateThree();
                Thread.sleep(1000);
                updateLast();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    frame.getContentPane().add(btnClickMeTo, BorderLayout.CENTER);
}

private void updateOne() {

    txtLeadingText.setText(one);
}

private void updateTwo() {

    txtLeadingText.setText(two);
}

private void updateThree() {

    txtLeadingText.setText(three);
}

private void updateLast() {

    txtLeadingText.setText("default text");
    }
}

From what I understand, the default Thread will prevent any GUI updates. 据我了解,默认线程将阻止任何GUI更新。 That shouldn't matter because I am setting the textField BEFORE the Thread.sleep. 没关系,因为我是在Thread.sleep之前设置textField的。 Why doesn't the text field update? 为什么文本字段不更新? Shouldn't the text be set, then the Thread wait? 不应该设置文本,然后线程等待吗?

EDIT: As per the answers, the above code has been updated. 编辑:根据答案,上述代码已更新。

You are invoking Thread.sleep(1000); 您正在调用Thread.sleep(1000); on EDT. 在EDT上。 This means that when your method will end - only then the repaint() will fire (at some point in time later). 这意味着当您的方法结束时-仅在随后的某个时间点,repaint()才会触发。

Until then your GUI is freezed. 在此之前,您的GUI被冻结。

Consider that this is going on one thread (so processing is straightforward): 考虑到这是在一个线程上进行的(因此处理很简单):

txtLeadingText.setText(one);
Thread.sleep(1000);
txtLeadingText.setText(two);
Thread.sleep(1000);
txtLeadingText.setText(three);
Thread.sleep(1000);
...
<returning from updateText()>
<processing other events on button click>
...
// some time later
<Swing finds out that GUI needs repaint: calls rapaint()>

This is what you should do (I didn't compile or test it): 这是您应该做的(我没有编译或测试过):

    public class MyRunnable implements Runnable {
        private List<String> strsToSet;
        public MyRunnable(List<String> strsToSet) {
            this.strsToSet = strsToSet;
        }
        @Override
        public void run() {
            try {
                if(strsToSet.size() > 0) {
                    final String str = strsToSet.get(0);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            txtLeadingText.setText(str);
                        }
                    });

                    Thread.sleep(1000);
                    List<String> newList = new LinkedList<String>(strsToSet);
                    newList.remove(0);
                    new Thread(new MyRunnable(newList)).start();
                }
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    new Thread(new MyRunnable(Arrays.asList(one, two, three))).start();

It is hard to do in Swing but in contrast in dynamically languages (like Groovy) it would go as simple as that (you'll get a better grasp of what is going on): 在Swing中很难做到这一点,但是相比之下,在动态语言(如Groovy)中,它就这么简单(您将更好地了解正在发生的事情):

    edt { 
        textField.setText(one)
        doOutside { 
            Thread.sleep(1000); 
            edt {
                textField.setText(two)
                doOutside { 
                    Thread.sleep(1000); 
                    edt {
                        textField.setText(three)
                    } 
                }
            } 
        }
    }

The GUI event loop updates the screen, but it can't update the screen until you return. GUI事件循环会更新屏幕,但是直到您返回,它才能更新屏幕。

I suggest you avoid doing any blocking operations in the GUI event thread. 我建议您避免在GUI事件线程中执行任何阻止操作。

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

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