1

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.
NewOne
  • 23
  • 3

2 Answers2

2

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);
    }
}
Community
  • 1
  • 1
  • @NewOne: you're welcome. If you're still having problems, then please tell us and show us more. For one, why are you absolutely required to use only JFrames? Why can't one window be a JDialog? Next, please show code in your question, not a link. Try to create a small runnable program that we can compile and run, and that shows us your problem directly, a [mcve] (please read the link). Good luck! – DontKnowMuchBut Getting Better Nov 25 '16 at 20:56
  • I'm still having problems :) (but I always keep smyling ). I added something, but i was put in Answers, Can you see it ? I put pictures of what I want to build. I'm learning how JDialog works, to see if I can use it ! Thanks again ! – NewOne Nov 25 '16 at 21:03
  • @NewOne: thanks for the reply. You don't want to post in answers unless you're posting an actual answer. For one doing this may dissuade others from answering your question since they're seeing two answers already. Instead, delete that answer and edit your original question with the new information. Also while the pictures help a little, what I really need to see is a small runnable program, not in a link, but posted as code-formatted text in your question. Again, good luck! – DontKnowMuchBut Getting Better Nov 25 '16 at 21:27
  • Ok thanks again and again DontKnowMuchBut Getting Better :) I just deleted my answer, and add the code in my question :) – NewOne Nov 26 '16 at 15:13
  • @NewOne: again, `"...a small runnable program, not in a link, but posted as code-formatted text in your question."`. Links won't work. Post your small runnable code as code-formatted text within your question. This will help all folks helping **immensely**. Good luck! – DontKnowMuchBut Getting Better Nov 26 '16 at 15:19
  • @NewOne: also my answer already addresses your problem -- use a SwingWorker although if you want to send text to the GUI and not an int, it would need to be a `SwingWorker` as well as change the publish/process method pair to handle Strings. Also, if you still need help, again consider creating and posting that [mcve]. – DontKnowMuchBut Getting Better Nov 26 '16 at 15:57
  • @NewOne for example, see my new [mcve] as an example of changing the SwingWorker to pass Strings and as an example of a MCVE. – DontKnowMuchBut Getting Better Nov 26 '16 at 16:13
  • Sorry i re-read you're answer, and SwingWorker is exactly what i need ! Now i finally executed the result in another thread, everything works great ! :) Thank you again ! – NewOne Nov 26 '16 at 19:52
  • Now, how can i "close" this topic ?:) – NewOne Nov 26 '16 at 19:53
0
//Make constructor class for both JFrame then 
 //write this code into your JFrame where your button is accesing another JFrame
 //Note:- jb=button var name,
 //       jf=JFrame vatr name,
 //       addnew()=JFrame Class to be open.

  jb.addActionListener(new ActionListener() { 
    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub
        new addnew();
        jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
       } 
   });

It might work as well.

imjhapali
  • 1
  • 2