Long process under Swing GUI : unexpected delay

南笙酒味 提交于 2019-12-10 19:18:56

问题


To explain my question here is an MCVE where clicking clicking a JButton on JDialog A opens JDialog B:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;

public class  DiagA extends JDialog  {

    private DiagB diag;

    public  DiagA() {

        super();
        setTitle("main diag");
        setSize(200, 150);
        setLocation(400,400);

        JButton btn = new JButton("Show DiagB");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {

                showDiag();
            }
        });
        add(btn, BorderLayout.NORTH);

        //make main frame visible
        setVisible(true);
    }

    void showDiag() {

        if(diag == null) {

            diag = new DiagB();

            //this prints out as expected
            System.out.println("set visible done");

            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {}

            //only after the delay diag shows in full
        }
    }

    public static void main(String[] args) {
        new  DiagA();
    }
}

class DiagB extends JDialog  {

    public  DiagB() {

        super();
        setTitle("2nd diag");
        setSize(150, 100);
        setLocation(600,420);
        setLayout(new FlowLayout(FlowLayout.CENTER));
        getContentPane().setBackground(Color.YELLOW);
        setVisible(true);
    }
}

As you can see in the code I added a 3 sec delay after creating DiagB. Clicking the button DiagBshows like this:

Only after the 3 sec delay ends, DiagBshows in full:

My questions are:
a. Why doesn't DiagBshow completely after it is constructed ? (It shows in full only when showDiag() returns).
b. The reason for my question is that DiagB needs to be updated, by long processes in DiagA.
What is the right way to update ? Does it require using a SwingWorker for every updating process ?


回答1:


a. showDiag runs on the GUI thread. The GUI will be completely dead while you make the GUI thread sleep.

b. Yes, use a SwingWorker for long-running tasks and use SwingUtilities.invokeLater() to submit GUI-updating tasks back to the GUI thread. Alternatively, implement SwingWorker#done() which is a convenience method that runs on the GUI thread after the SwingWorker task completes.




回答2:


Based on Marko Topolnik answer and Andrew Thompson comment, I warped the long process with a SwingWorker.
This works fine:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;

public class DiagA extends JDialog  {

    private FrameB frame;
    private JButton btn;

    public  DiagA() {

        super();
        setTitle("main frame");
        setSize(200, 150);
        setLocation(400,400);

        btn = new JButton("Show Frame B");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {

                show2ndFrame();
            }
        });
        add(btn, BorderLayout.NORTH);
        setVisible(true);
    }

    void show2ndFrame() {

        if(frame == null) {

            frame = new FrameB();
            btn.setText("Exit");

        }else {

            System.exit(0);
        }

        doWork();
    }

    private void doWork() {

        SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() {

            @Override
            protected Void doInBackground() throws Exception {

                try {

                    for(int i = 1 ; i<=100 ; i++) {
                        //represents a long process
                        Thread.sleep(100);
                        frame.update(i);
                    }

                } catch (InterruptedException ex) {}
                return null;
            }
        };
        sw.execute();
    }

    public static void main(String[] args) {
        new  DiagA();
    }
}

class FrameB extends JFrame  {

   JLabel label;

    public  FrameB() {

        super();
        setTitle("2nd frame");
        setSize(150, 100);
        setLocation(600,420);
        setLayout(new FlowLayout(FlowLayout.CENTER));
        getContentPane().setBackground(Color.YELLOW);
        label = new JLabel("0");
        add(label);
        setVisible(true);
    }

    void update(int progress) {

        label.setText(String.valueOf(progress));
    }
}


来源:https://stackoverflow.com/questions/39484450/long-process-under-swing-gui-unexpected-delay

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!