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 AdminPanel
s 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
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();
}
});
}
}
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)