Swing Parent JFrame/JPanel unusable/clickable whil

2019-08-01 05:34发布

问题:

I am loading a JFrame AdminFrame (with add user and addLocation button on it) when the user click's addUser button the new JFrame addUser loads and takes user information. When the information is submitted to server it takes some time(because server is web-based) during that time both of my panels got stuck...what i want is to make AdminFrame clickable and use-able so that user can add new user or can add location... Here is my AdminPanels add button's template code...not writing original code because original code to is too messy..

public class AdminPanel extends JFrame{
       public AdminPanel(){
           Initalize();//Do Initalize Stuff
       }
       public void addBtnActionPerformed(){
           //load Child Form
       }
}//End of class

Now here is my AddUser Panel's adduser button Templete code Orignal code to too messay..

public class AddUser extends JFrame{
       public AddUser(){
           Initalize();//Do Initalize Stuff
       }
       public void addUserBtnActionPerformed(){
           /*
              take user's form input values make a http request send to server
              get response...now what i have to do here to make parent form clickable?
           */
       }
}//End of class

回答1:

You need to use a SwingWorker to dispatch your heavy/lengthy operations into another Thread, allowing the UI-Thread(EDT) to respond to events.

Here is a very simple code showing how SwingWorker can be used (connection to a server is here emulated by a bunch of Thread.sleep()):

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestJFrame implements ActionListener {
    private JProgressBar progress;
    private JButton startButton;
    private JButton testButton;
    private SwingWorker<Void, Integer> worker;

    public void initUI() {
        JFrame frame = new JFrame(TestJFrame.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        progress = new JProgressBar(0, 100);
        startButton = new JButton("Start work");
        testButton = new JButton("Test me while work is in progress");
        startButton.addActionListener(this);
        testButton.addActionListener(this);
        JPanel buttonPanel = new JPanel(new FlowLayout());
        buttonPanel.add(startButton);
        buttonPanel.add(testButton);
        frame.add(buttonPanel, BorderLayout.NORTH);
        frame.add(progress, BorderLayout.SOUTH);
        frame.setSize(600, 400);
        frame.setVisible(true);
    }

    private void showTestDialog() {
        if (worker != null) {
            JOptionPane.showMessageDialog(testButton, "You made a test. See how I still respond while heavy job is in progress?");
        } else {
            JOptionPane.showMessageDialog(testButton,
                    "You made a test, but no job is progress. Hit the \"Start work\" button and hit me again after.");
        }
    }

    private void startWork() {
        if (worker != null) {
            return;
        }
        startButton.setEnabled(false);
        worker = new SwingWorker<Void, Integer>() {

            @Override
            protected Void doInBackground() throws Exception {
                // Outside EDT, we cannot modify the UI, but we can perform lengthy operations
                // without blocking the UI
                for (int i = 0; i < 10; i++) {
                    publish(i * 10);
                    Thread.sleep(1000);
                }
                return null;
            }

            @Override
            protected void process(List<Integer> chunks) {
                // Inside EDT, here we can modify the UI
                super.process(chunks);
                // We only care about the last one
                progress.setValue(chunks.get(chunks.size() - 1));
            }

            @Override
            protected void done() {
                // Inside EDT, he we can modify the UI
                super.done();
                progress.setValue(100);
                startButton.setEnabled(true);
                worker = null;
            }

        };
        worker.execute();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == startButton) {
            startWork();
        } else if (e.getSource() == testButton) {
            showTestDialog();
        }
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestJFrame().initUI();
            }

        });
    }
}


回答2:

Your problem as far as I can tell is you do not create your GUI on Event Dispatch Thread, and than in turn you create another JFrame with a possibly long running task on your initial thread again - as the first JFrame was also created on initial thread.

1) Do not extend JFrame class unnecessarily, as you might want to extend another class which is very necessary but cant due to the lack of multiple inheritance in java. Rather create and instance of JFrame and call methods on the instance something like:

JFrame frame=new JFrame();
frame.setDefaultCloseOperation(..);
frame.add(..);

2) Create Swing components on Event Dispatch Thread like so:

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
           //create Swing and UI components here
        }
    });

3) See The Use of Multiple JFrames, Good/Bad Practice?. Rather use either JDialog which I think is what you will be going for or CardLayout (which allows flipping between various components on single JFrame/Container.

4) Use Swing Worker for long running tasks on EDT (or else GUI, inluding other open windows of your app, will become unresponsive)