Search code examples
javajframejbuttonactionlistener

Build JFrame from another JFrame with long process


I'm quite new on JAVA, and i have a question (i hope my english is not too bad).

Here is my process :

  • Open a first JFrame in the Main, with a JButton (to open the second JFrame).
  • On click, with ActionLister, i call the process to open my second window, with a black background (this works very well).

BUT, if i add a long process (in my code, just a sleep(5000)) just after setVisible() my second JFrame, this one will appear in white, and waits for the sleep(5000) to end before being black.

Questions :

  • Can someone tell me why the second JFrames appears white until the end of process ? Maybe i make something wrong when i build my JFrame ?
  • Can someone tell me how to show my second JFrame black BEFORE the process ends ?

I searched for a long time, and saw that if my second window is built direct in the main thread it's ok even with the sleep before end of process.

But when i am in another thread (like when i click on the button), that doesn't work good !

SECOND PART :

On click on the button from the first window : The second window shows up (empty with black background). then, the result's calcul is launched. Calculate the result cant take 20sec, and will find 1 element each 5 seconds. Each times an element is found, i want it to be shown in the second window.

For that, i added an observer on this result from the JFrame, which will add an element each time one element is found. I hope you understand. Here picture of what i want to make :

Process

Here my project .JAR : http://dl.free.fr/b5IUSStBJ

Here my result's calcul :

public void launchCalculateResult(){
    String[] tabelements = {"test1","test2", "test3", "test4", "test5"};
    for (int i=0; i < 5; i++){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        _elementslist.add(tabelements[i]);
        notifyObservers();
    }
}

you can see that it adds an element in a list each 2 seconds, and then notify the observers (my second window), then the observer adds an element :

public void refresh(Observable o) {
    _otherwindow.addResultElement(_result.getLastElement());
}
  • The behaviour I got :

The Result calculates good, and in the end the second window looks good, with its 5 elements. But during the result's search, my second windows remains empty and white . . .

  • I repeat the aim : Each time an element is added in the Result, i want to show it in my second window.

Solution

  • You're calling the long process on the Swing event thread, and this will tie up the thread preventing it from doing its important jobs, including painting your new JFrame.

    The canonical solution is to use a background thread for your long processes, and for Swing GUI's, you'd want to use a SwingWorker -- if the background process needs to communicate with the GUI (which is usually the case).

    For the details on this problem and solution, please check out: Concurrency in Swing

    Side issue: you'll usually not want to show multiple JFrames in your application. For why this is important and for how you can improve this design, please check out Multiple JFrames

    For example

    import java.awt.Color;
    import java.awt.Dialog.ModalityType;
    import java.awt.Dimension;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    
    import javax.swing.*;
    
    public class SwingExample extends JPanel {
        private JButton openDialogBtn = new JButton(new OpenDialogAction("Open Dialog"));
        private JDialog dialog;
        private DialogPanel dialogPanel = new DialogPanel();
    
        public SwingExample() {
            setPreferredSize(new Dimension(400, 400));
            add(openDialogBtn);
        }
    
        private class OpenDialogAction extends AbstractAction {
            public OpenDialogAction(String name) {
                super(name);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                dialogPanel.setText("");
                if (dialog == null) {
                    Window win = SwingUtilities.getWindowAncestor(SwingExample.this);
                    dialog = new JDialog(win, "Dialog", ModalityType.MODELESS);
                    dialog.add(dialogPanel);
                    dialog.pack();
                    dialog.setLocationRelativeTo(win);
                }
                new SwingWorker<Void, Integer> () {
                    private final int maxI = 5;
    
                    @Override
                    protected Void doInBackground() throws Exception {
                        for (int i = 0; i < maxI; i++) {
                            publish(i);
                            Thread.sleep(1000);
                        }
                        return null;
                    }
    
                    protected void process(java.util.List<Integer> chunks) {
                        for (Integer chunk : chunks) {
                            dialogPanel.setText("Time: " + chunk);
                        }
                    };
    
                    protected void done() {
                        dialogPanel.setText("Done!");
                    };
                }.execute();
                dialog.setVisible(true);
            }
        }
    
        private class DialogPanel extends JPanel {
            private JTextField textField = new JTextField(10);
    
            public DialogPanel() {
                setBackground(Color.BLACK);
                setPreferredSize(new Dimension(200, 200));
                add(textField);
            }
    
            public void setText(String text) {
                textField.setText(text);
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    
        private static void createAndShowGui() {
            SwingExample mainPanel = new SwingExample();
            JFrame frame = new JFrame("SwingExample");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    }
    

    Example 2: handles Strings being passed into a JList<String> using a SwingWorker<Void, String>

    import java.awt.Color;
    import java.awt.Dialog.ModalityType;
    import java.awt.Dimension;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class SwingExample extends JPanel {
        private JButton openDialogBtn = new JButton(new OpenDialogAction("Open Dialog"));
        private JDialog dialog;
        private DialogPanel dialogPanel = new DialogPanel();
    
        public SwingExample() {
            setPreferredSize(new Dimension(400, 400));
            add(openDialogBtn);
        }
    
        private class OpenDialogAction extends AbstractAction {
            public OpenDialogAction(String name) {
                super(name);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                dialogPanel.clearList();
                if (dialog == null) {
                    Window win = SwingUtilities.getWindowAncestor(SwingExample.this);
                    dialog = new JDialog(win, "Dialog", ModalityType.MODELESS);
                    dialog.add(dialogPanel);
                    dialog.pack();
                    dialog.setLocationRelativeTo(win);
                }
                new SwingWorker<Void, String>() {
                    @Override
                    protected Void doInBackground() throws Exception {
                        String[] tabelements = { "test1", "test2", "test3", "test4", "test5" };
                        for (int i = 0; i < 5; i++) {
                            try {
                                Thread.sleep(2000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            publish(tabelements[i]);
                        }
                        return null;
                    }
    
                    protected void process(java.util.List<String> chunks) {
                        for (String chunk : chunks) {
                            dialogPanel.addText(chunk);
                        }
                    };
    
                    protected void done() {
                        dialogPanel.addText("Done!");
                    };
                }.execute();
                dialog.setVisible(true);
            }
        }
    
        private class DialogPanel extends JPanel {
            private DefaultListModel<String> listModel = new DefaultListModel<>();
            private JList<String> jList = new JList<>(listModel);
    
            public DialogPanel() {
                jList.setPrototypeCellValue("ABCDEFG HIJKLMNOP");
                jList.setVisibleRowCount(6);
                JScrollPane scrollPane = new JScrollPane(jList);
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    
                setBackground(Color.BLACK);
                setPreferredSize(new Dimension(200, 200));
                add(scrollPane);
            }
    
            public void clearList() {
                listModel.clear();
            }
    
            public void addText(String text) {
                listModel.addElement(text);
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    
        private static void createAndShowGui() {
            SwingExample mainPanel = new SwingExample();
            JFrame frame = new JFrame("SwingExample");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    }