Eugene
Eugene

Reputation: 11055

Why does my frame show nothing?

I want to show a progress bar window when I close the main frame. However, the progress bar window will show nothing and I have no idea about it. Here is the code.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class MainFrame {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                MainFrame mainFrame = new MainFrame();
                mainFrame.createUI();
            }
        });
    }
    public void createUI(){
        JFrame frame = new JFrame();
        JPanel mainPanel = new JPanel(new BorderLayout());
        JButton button = new JButton("Close");
        button.setBorder(new EmptyBorder(20, 20, 20, 20));
        button.addActionListener(new ButtonListener());
        mainPanel.add(button,BorderLayout.CENTER);
        frame.add(mainPanel,BorderLayout.CENTER);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
    }

    class ButtonListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent arg0) {
            // TODO Auto-generated method stub
            FeedbackBox feedbackBox = new FeedbackBox();
            feedbackBox.createUI();
            feedbackBox.increment(0, 100);
            try {
                feedbackBox.getThread().join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            feedbackBox.closeBox();
        }

    }
}

And the progress bar window is:

import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

public class FeedbackBox {
    private JFrame frame;
    private JProgressBar progressBar;

    Thread thread;

    public void createUI(){
        frame = new JFrame("Reminder");
        MainPanel mainPanel = new MainPanel();
        frame.add(mainPanel,BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
    }

    public JProgressBar getProgressBar(){
        return progressBar;
    }

    public void closeBox(){
        frame.dispose();
    }

    public void increment(final int minimum,final int maximum){
        thread = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                for (int i = minimum; i <= maximum; i++) {
                    getProgressBar().setValue(i);
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });

        thread.start();
    }

    public Thread getThread(){
        return thread;
    }

    @SuppressWarnings("serial")
    class MainPanel extends JPanel{
        public MainPanel(){
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

            progressBar = new JProgressBar();
            progressBar.setStringPainted(true);
            progressBar.setIndeterminate(true);
            progressBar.setBackground(Color.white);
            progressBar.setForeground(Color.blue);
            JPanel topPanel = new JPanel();
            topPanel.add(progressBar);

            JLabel label = new JLabel("It is closing. ");
            label.setForeground(Color.blue);
            label.setBackground(Color.WHITE); 
            JPanel bottomPanel = new JPanel();
            bottomPanel.add(label);

            add(topPanel);
            add(Box.createVerticalStrut(10));
            add(bottomPanel);
        }
    }
}

If I remove the

try {
        feedbackBox.getThread().join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
}
feedbackBox.closeBox();

Then everything will be OK. WHY? Thanks for your help in advance.

Based on @Hovercraft Full Of Eels 's help. I've modified my code. However, wired things are still here. The void propertyChange won't be called unless I close the progress bar window manually.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class MainFrame {
    private JFrame frame;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                MainFrame mainFrame = new MainFrame();
                mainFrame.createUI();
            }
        });
    }
    public void createUI(){
        frame = new JFrame();
        JPanel mainPanel = new JPanel(new BorderLayout());
        JButton button = new JButton("Close");
        button.addActionListener(new ButtonListener());
        button.setBorder(new EmptyBorder(20, 20, 20, 20));
        mainPanel.add(button,BorderLayout.CENTER);
        frame.add(mainPanel,BorderLayout.CENTER);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
    }

    class ButtonListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent arg0) {
            // TODO Auto-generated method stub
            FeedbackBox feedbackBox = new FeedbackBox(frame,0,100,"It is closing");
            feedbackBox.displayDialog();
        }

    }
}


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;


public class FeedbackBox {
    private JDialog dialog;
    private MyWorker myWorker;
    private JProgressBar progressBar = new JProgressBar();

    public FeedbackBox(Window win,int minimum,int maximum,String title){
        myWorker = new MyWorker(minimum, maximum);
        MainPanel mainPanel = new MainPanel(minimum,maximum);
        myWorker.addPropertyChangeListener(new MyWorkerListener());
        dialog = new JDialog(win,title,ModalityType.APPLICATION_MODAL);
        dialog.add(mainPanel,BorderLayout.CENTER);
        dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        dialog.setResizable(false);
        dialog.setLocationRelativeTo(win);
        dialog.pack();
    }

    public void displayDialog(){
        dialog.setVisible(true);
        myWorker.execute();
    }

    public void closeBox(){
        dialog.dispose();
    }

    @SuppressWarnings("serial")
    class MainPanel extends JPanel{
        public MainPanel(int minimum,int maximum){
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

            progressBar.setMinimum(minimum);
            progressBar.setMaximum(maximum);
            progressBar.setStringPainted(true);
            progressBar.setIndeterminate(true);
            progressBar.setBackground(Color.white);
            progressBar.setForeground(Color.blue);
            JPanel topPanel = new JPanel();
            topPanel.add(progressBar);

            JLabel label = new JLabel("It is closing.");
            label.setForeground(Color.blue);
            label.setBackground(Color.WHITE); 
            JPanel bottomPanel = new JPanel();
            bottomPanel.add(label);

            add(topPanel);
            add(Box.createVerticalStrut(10));
            add(bottomPanel);
        }
    }

    class MyWorkerListener implements PropertyChangeListener{

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            // TODO Auto-generated method stub
            if (evt.getPropertyName().equals(MyWorker.VALUE)) {
                System.out.println("myWorker.getValue()" + myWorker.getValue());
                progressBar.setValue(myWorker.getValue());
            }
            if (evt.getNewValue() == SwingWorker.StateValue.DONE && dialog != null) {
                closeBox();
            }
        }
    }
}

    class MyWorker extends SwingWorker<Void, Void>{
        public static final String VALUE = "value";
        private int value;
        private int minimum;
        private int maximum;

        public MyWorker(int minimum,int maximum){
            this.minimum = minimum;
            this.maximum = maximum;
            value = minimum;
        }

        @Override
        protected Void doInBackground() throws Exception {
            // TODO Auto-generated method stub
            for (int i = minimum; i <= maximum; i++) {
                setValue(i);
                Thread.sleep(30);
            }
            return null;
        }

        public void setValue(int i){
            int oldValue = this.value;
            int newValue = i;
            this.value = i;
            firePropertyChange(VALUE, oldValue, newValue);
        }

        public int getValue(){
            return value;
        }
    }

Upvotes: 1

Views: 87

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285415

By joining your thread with the Swing event thread, you make the thread a non-background thread, thereby tying up the Swing event thread, preventing it from doing its job -- drawing your GUI and interacting with the user, and this will freeze your dialog window (which should be a JDialog and not a separate JFrame by the way). Solution: don't join the threads. Also your background thread should not be changing the states of Swing components as its currently doing. Better to use a SwingWorker to allow you to keep Swing things on the event thread and background things on a background thread.

For the gory details, please read, Lesson: Concurrency in Swing - Oracle Documentation

For example:

import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;

import javax.swing.*;

@SuppressWarnings("serial")
public class ClosingDialogPanel {
   private JPanel mainPanel = new JPanel();
   private JProgressBar progressBar = new JProgressBar();
   private JDialog dialog;
   private MyWorker myWorker;

   public ClosingDialogPanel(Window win, int minimum, int maximum, String title) {
      myWorker = new MyWorker(minimum, maximum);
      progressBar.setMinimum(minimum);
      progressBar.setMaximum(maximum);
      myWorker.addPropertyChangeListener(new WorkerListener());
      progressBar.setStringPainted(true);
      mainPanel.add(progressBar);
      dialog = new JDialog(win, title, ModalityType.APPLICATION_MODAL);
      dialog.add(mainPanel);
      dialog.pack();
      dialog.setLocationRelativeTo(win);
   }

   public void displayDialog() {
      myWorker.execute();
      dialog.setVisible(true);
   }

   private class WorkerListener implements PropertyChangeListener {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
         if (MyWorker.VALUE.equals(evt.getPropertyName())) {
            progressBar.setValue(myWorker.getValue());
         }
         if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
            if (dialog != null && dialog.isVisible()) {
               dialog.dispose();
            }
            try {
               myWorker.get();
            } catch (InterruptedException e) {
               e.printStackTrace();
            } catch (ExecutionException e) {
               e.printStackTrace();
            }
         }
      }
   }

   private static void createAndShowGui() {
      final JFrame frame = new JFrame("Closing Frame");

      JButton closeBtn = new JButton(new AbstractAction("Close") {

         @Override
         public void actionPerformed(ActionEvent e) {
            final ClosingDialogPanel closingDlg = new ClosingDialogPanel(frame, 0,
                  200, "Closing");
            closingDlg.displayDialog();
         }
      });

      JPanel panel = new JPanel();
      panel.add(closeBtn);

      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(panel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

}

class MyWorker extends SwingWorker<Void, Void> {
   public static final String VALUE = "value";
   private int value;
   private int minimum;
   private int maximum;

   public MyWorker(int minimum, int maximum) {
      this.minimum = minimum;
      this.maximum = maximum;
      value = minimum;
   }

   @Override
   protected Void doInBackground() throws Exception {
      for (int i = minimum; i <= maximum; i++) {
         setValue(i);
         Thread.sleep(30);
      }
      return null;
   }

   private void setValue(int i) {
      int oldValue = this.value;
      int newValue = i;
      this.value = i;
      firePropertyChange(VALUE, oldValue, newValue);
   }

   public int getValue() {
      return value;
   }
}

Upvotes: 4

Related Questions