I want to create a basic JDialog with a progress bar, and to update the bar when some operations are done. My code is:
public class Main {
public static void main(String[] args) {
WikiReaderUI ui = new WikiReaderUI();
SwingUtilities.invokeLater(ui);
}}
and:
public class WikiReaderUI implements Runnable {
private JFrame frame;
protected Document doc;
protected JProgressBar progressBar;
protected int progress;
#Override
public void run() {
frame = new JFrame("Wiki READER");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
addComponentsToPane(frame.getContentPane());
// Display the window.
frame.setSize(600, 320);
frame.setResizable(false);
frame.setVisible(true);
}
private void addComponentsToPane(Container pane) {
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
addLanguagePanel(pane);
//other panels...irelevant for my problem
addCreationPanel(pane);
}
private void addCreationPanel(Container pane) {
JPanel infoPanel = new JPanel();
infoPanel.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.ipady = 5;
JButton createDoc = new JButton("Create PDF");
createDoc.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
JDialog dlg = new JDialog(frame, "Progress Dialog", true);
progressBar = new JProgressBar(0, 500);
progressBar.setOpaque(true);
dlg.add(BorderLayout.CENTER, progressBar);
dlg.add(BorderLayout.NORTH, new JLabel("Progress..."));
dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dlg.setSize(300, 75);
dlg.setLocationRelativeTo(frame);
dlg.setVisible(true);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while (progress < 500) {
progressBar.setValue(progress);
progress++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t.start();
}
});
infoPanel.add(createDoc, c);
pane.add(infoPanel);
}
When I run the program and click the createDoc button, the progress bar is not updated in the dialog, but if I close the dialog and click the button again, the progress bar is updating. I know it's something related with event dispatch thread, but I don't know how to change my code in order to always update the bar.
I've also tried with a SwingWorker, without success.
Make JDialog visible after starting the thread.
t.start();
dlg.setVisible(true);
Use Swing Timer instead of Java Timer that is more suitable with Swing application.
Read more How to Use Swing Timers
Related
Is it possible to create a button that won't be seen until the user clicks another button?
My goal is for the button to be invisible by default rather than when its clicked on. Then become visible when another action is performed. The code below is my original attempt at creating this.
public void but_roll1ActionPerformed(java.awt.event.ActionEvent evt)
{
if (!bal_but.isEnabled() && !gamble_but.isEnabled()) {
but_roll1.setVisible(true);
but_roll1.setEnabled(true);
d1 = diceRoll();
die1_display.setText(String.valueOf(d1));
but_roll1.setEnabled(false);
} else {
but_roll1.setVisible(false);
}
}
Two better strategies:
Put the button in a CardLayout with a second blank panel till needed.
Make the button disabled until the first button is clicked.
I prefer the 2nd as the 'path of least surprise' for the user. YMMV.
Initial view
View after 'effect' button actioned
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class ButtonNotUsableTillAction {
private JComponent ui = null;
ButtonNotUsableTillAction() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridLayout(1, 0, 4, 4));
ui.setBorder(new EmptyBorder(4,4,4,4));
// first demo, using card layout
JPanel cardDemoPanel = new JPanel(new GridLayout(1, 0, 2, 2));
cardDemoPanel.setBorder(new TitledBorder("Card Layout"));
ui.add(cardDemoPanel);
JButton actionCardButton = new JButton("Action");
cardDemoPanel.add(actionCardButton);
CardLayout cardLayout = new CardLayout();
JPanel cardLayoutPanel = new JPanel(cardLayout);
cardDemoPanel.add(cardLayoutPanel);
cardLayoutPanel.add(new JPanel(), "panel");
cardLayoutPanel.add(new JButton("Effect"), "button");
cardLayout.show(cardLayoutPanel, "panel");
ActionListener flipCardListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(cardLayoutPanel, "button");
}
};
actionCardButton.addActionListener(flipCardListener);
// first demo, using disabled / enabled
JPanel enabledDemoPanel = new JPanel(new GridLayout(1, 0, 2, 2));
enabledDemoPanel.setBorder(new TitledBorder("Enabled"));
ui.add(enabledDemoPanel);
JButton actionEnabledButton = new JButton("Action");
enabledDemoPanel.add(actionEnabledButton);
JButton effectButton = new JButton("Effect");
enabledDemoPanel.add(effectButton);
effectButton.setEnabled(false);
ActionListener enableComponentListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
effectButton.setEnabled(true);
}
};
actionEnabledButton.addActionListener(enableComponentListener);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
ButtonNotUsableTillAction o = new ButtonNotUsableTillAction();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
As #markspace mentioned, you need to revalidate the button's container after setting the button visible:
but_roll1.getParent().revalidate();
I'm writing a GUI that is able to perform some JUnit Tests and to handle this I have used a SwingWorker.
When I start the program the GUI comes up and I click through some selections and the SwingWorker initiates and does it's part and finally outputs either a console output or file output. Then I would click through the GUI again and start another test. At this point when the program finishes it would generate the final output twice, e.g. the console output would be followed directly by an identical console output.
I am assuming this is due to the SwingWorker not terminating and "dying".
Also I am creating the SwingWorker when I click a "start" button in the GUI. Is this a bad idea and what would the proper way to do it be instead?
EDIT Added code sample
public class TestMainFrame {
private static JFrame frame;
private static JTextArea textArea;
public TestMainFrame(){
createAndShowGUI();
}
private void createAndShowGUI() {
frame = new JFrame("Test");
frame.setLayout(new BorderLayout());
JButton btn = new JButton("Test Me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(btn.getText().equals("Test Me")){
testMe();
}
}
});
textArea = new JTextArea("This is a test pane! \n");
textArea.setEditable(false);
JScrollPane scroller = new JScrollPane(textArea);
frame.add(scroller, BorderLayout.CENTER);
frame.add(btn, BorderLayout.PAGE_END);
frame.setSize(new Dimension(300, 400));
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static void testMe(){
writeToTextArea("Button Pressed");
writeToTextArea("Starting tests");
SwingWorker<Result, Void> worker = new SwingWorker<Result, Void>() {
#Override
public Result doInBackground() {
writeToTextArea("Inside the doInBackground method of SwingWorker");
return null;
}
#Override
public void done() {
writeToTextArea("The SwingWorker has finished");
}
};
worker.execute();
}
private static void writeToTextArea(String text){
textArea.append(text + "\n");
}
(Not an answer)
This is how I ran your code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestMainFrame {
private static JFrame frame;
private static JTextArea textArea;
public TestMainFrame() {
createAndShowGUI();
}
private void createAndShowGUI() {
frame = new JFrame("Test");
frame.setLayout(new BorderLayout());
final JButton btn = new JButton("Test Me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (btn.getText().equals("Test Me")) {
testMe();
}
}
});
textArea = new JTextArea("This is a test pane! \n");
textArea.setEditable(false);
JScrollPane scroller = new JScrollPane(textArea);
frame.add(scroller, BorderLayout.CENTER);
frame.add(btn, BorderLayout.PAGE_END);
frame.setSize(new Dimension(300, 400));
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static void testMe() {
writeToTextArea("Button Pressed");
writeToTextArea("Starting tests");
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
writeToTextArea("Inside the doInBackground method of SwingWorker");
return null;
}
#Override
public void done() {
writeToTextArea("The SwingWorker has finished");
}
};
worker.execute();
}
// *** note change ***
private static void writeToTextArea(final String text) {
if (SwingUtilities.isEventDispatchThread()) {
textArea.append(text + "\n");
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(text + "\n");
}
});
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TestMainFrame testMainFrame = new TestMainFrame();
testMainFrame.createAndShowGUI();
}
});
}
}
I have the following problem:
I have a main application window (JFrame) that fills the whole screen.
When a button is clicked, a smaller window appears, to let the user input some Data. While the User does this, the main window should neither jump in front of it, nor allow interaction.
Solution to that: open a modal JDialog. Lets call that Dialog 1.
But when a button within this Dialog is clicked, a NEW window (yes/no-dialog) is supposed to pop up.. and, again, needs to act modal on the already modal JDialog Dialog 1. Trying to do that, the second Dialog keeps disappearing behind the first one.
I tried making Dialog 1 a JFrame but then, of course, I loose the "modal" bit. Forcing Dialog 1 to stay in from still keeps the main window's Button clickable.
What am I missing? How can I put a modal swing window OVER another modal swing window?
Edit:
minimal example of one not-really working version:
Main class for opening:
public class MainWin extends JFrame {
public MainWin(){
this.setSize(800,800);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Dia1(MainWin.this);
}
});
this.setVisible(true);
}
}
Main window:
public class MainWin extends JFrame {
public MainWin(){
this.setSize(800,800);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Dia1(MainWin.this);
}
});
this.setVisible(true);
}
}
First Dialog:
public class Dia1 extends JDialog {
public Dia1(final JFrame parent){
super(parent, true);
this.setSize(400, 400);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
this.setVisible(true);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Dia2(parent);
}
});
}
}
Second Dialog:
public class Dia2 extends JDialog {
public Dia2(JFrame parent){
super(parent, true);
this.setSize(200, 200);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
this.setVisible(true);
}
}
PS: I just realised: Dialog 2 is not hidden, as I suspected.. it is simply not there. Most likely because the parent window is blocked from the Modal Dialog?
Here is an MCVE of modality working as advertised.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class ModalOverModal {
private JComponent ui = null;
ModalOverModal() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridLayout());
ui.setBorder(new EmptyBorder(40,40,40,40));
final JButton b1 = new JButton("Open Modal Dialog");
b1.setMargin(new Insets(40, 200, 40, 200));
ui.add(b1);
final JButton b2 = new JButton("Open 2nd Modal Dialog");
ActionListener al1 = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b1, b2);
}
};
b1.addActionListener(al1);
ActionListener al2 = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b2, "Close Me!");
}
};
b2.addActionListener(al2);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ModalOverModal o = new ModalOverModal();
JFrame f = new JFrame("Modal over Modal");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
I know the title isn't very explanatory, I was unsure of how to phrase the question. What I have is a GUI that I want to trigger an event when the window in closed (including when you force quit the window/application). Thank you in advance for any help!!! Here's my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.IOException;
import java.io.Serializable;
public class NotAVirus extends JFrame {
private JTextField statusField = new JTextField(20);
private JButton yesButton = new JButton("Open");
private JButton noButton = new JButton("Close");
private static NotAVirus app = new ImLost();
public static void main() {
app.setVisible(true);
app.setLocationRelativeTo(null);
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
public ImLost() {
super("ImLost");
statusField.setText("There's No Escape");
statusField.setHorizontalAlignment(JLabel.CENTER);
statusField.setEditable(false);
add(statusField, BorderLayout.CENTER);
JPanel p = new JPanel();
p.setLayout(new GridLayout(1, 2));
p.add(yesButton);
p.add(noButton);
add(p, BorderLayout.SOUTH);
yesButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e) {
app.setVisible(false);
for(int i = 0; i <= 10000; i ++)
{
JFrame frame = new JFrame("ImLost");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(160, 1));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
//Display the window.
frame.setLocation((int)(Math.random() * ((1280) + 1)),(int)(Math.random() * ((800) + 1)));
frame.pack();
frame.setVisible(true);
}
}
});
noButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e) {
app.setVisible(false);
for(int i = 0; i <= 10000; i ++)
{
JFrame frame = new JFrame("ImLost");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(160, 1));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
//Display the window.
frame.setLocation((int)(Math.random() * ((1280) + 1)),(int)(Math.random() * ((800) + 1)));
frame.pack();
frame.setVisible(true);
}
}
});
p.setPreferredSize(new Dimension(200, 35));
pack();
}
You can add a WindowListener to the JFrame:
frame.addWindowListener(new WindowListener() {
#Override
public void windowOpened(WindowEvent e) {
}
#Override
public void windowClosing(WindowEvent e) {
//window is being closed
}
#Override
public void windowClosed(WindowEvent e) {
//window is closed
}
#Override
public void windowIconified(WindowEvent e) {
}
#Override
public void windowDeiconified(WindowEvent e) {
}
#Override
public void windowActivated(WindowEvent e) {
}
#Override
public void windowDeactivated(WindowEvent e) {
}
});
I want to trigger an event when the window in closed (including when you force quit the window/application)
If you mean "when someone kills the process" i think it wouldn't be possible, as the process gets killed and so stops its execution immediately. If you mean "when the application freezes and the user forces it to close" I think it wouldn't be possible too, usually if you force the quit of an application, it means that it's frozen and it's not responding anymore, so executing other code of it wouldn't be possible.
I have a button in a java frame that when pressed it reads a value from a text field and uses that string as a port name attempting to connect to a serial device.
If this connection is successful the method returns true if not it returns false. If it returns true I want the frame to disappear. A series of other frames specifed in other classes will then appear with options to control the serial device.
My problem is: the button is connected to an action listener, when pressed this method is invoked. If I try to use the frame.setVisible(true); method java throws a abstract button error because I'm effectively telling it to disappear the frame containing the button before the button press method has exited. Removing the frame.setVisible(true); allow the program to run correctly however I am left with a lingering connection frame that is no longer any use.
How to I get the frame to disappear upon pressing a the button?
package newimplementation1;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
*
* #author Zac
*/
public class ConnectionFrame extends JPanel implements ActionListener {
private JTextField textField;
private JFrame frame;
private JButton connectButton;
private final static String newline = "\n";
public ConnectionFrame(){
super(new GridBagLayout());
textField = new JTextField(14);
textField.addActionListener(this);
textField.setText("/dev/ttyUSB0");
connectButton = new JButton("Connect");
//Add Components to this panel.
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(connectButton, c);
connectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
boolean success = Main.mySerialTest.initialize(textField.getText());
if (success == false) {System.out.println("Could not connect"); return;}
frame.setVisible(false); // THIS DOES NOT WORK!!
JTextInputArea myInputArea = new JTextInputArea();
myInputArea.createAndShowGUI();
System.out.println("Connected");
}
});
}
public void actionPerformed(ActionEvent evt) {
// Unimplemented required for JPanel
}
public void createAndShowGUI() {
//Create and set up the window.
frame = new JFrame("Serial Port Query");
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
//Add contents to the window.
frame.add(new ConnectionFrame());
frame.setLocation(300, 0);
//Display the window.
frame.pack();
frame.setVisible(true);
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("Exiting Gracefully");
Main.mySerialTest.close();
((JFrame)(e.getComponent())).dispose();
System.exit(0);
}
});
}
}
Running your snippet (after removing/tweaking around the custom classes), throws an NPE. Reason is that the frame you'r accessing is null. And that's because it's never set. Better not rely on any field, let the button find its toplevel ancestor and hide that, like in
public void actionPerformed(final ActionEvent e) {
boolean success = true;
if (success == false) {
System.out.println("Could not connect");
return;
}
Window frame = SwingUtilities.windowForComponent((Component) e
.getSource());
frame.setVisible(false); //no problem :-)
}
Your problem is with this line:
frame.add(new ConnectionFrame());
You're creating a new ConnectionFrame object, and so the frame that your button tries to close on is not the same as the one being displayed, and this is the source of your problem.
If you change it to,
//!! frame.add(new ConnectionFrame());
frame.add(this);
so that the two JFrames are one and the same, things may work more smoothly.
But having said that, your whole design smells bad and I'd rethink it in a more OOP and less static fashion. Also, use dialogs where dialogs are needed, not frames, and rather than dialogs consider swapping views (JPanels) via CardLayout as a better option still.
Myself, I'd create a "dumb" GUI for this, one that creates a JPanel (here in my example it extends a JPanel for simplicity, but I'd avoid extending if not necessary), and I'd let whoever is calling this code decide what to do with the information via some control. For e.g.,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ConnectionPanel extends JPanel {
private JTextField textField;
private JButton connectButton;
private ConnectionPanelControl control;
public ConnectionPanel(final ConnectionPanelControl control) {
super(new GridBagLayout());
this.control = control;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (control != null) {
control.connectButtonAction();
}
}
};
textField = new JTextField(14);
textField.addActionListener(listener);
textField.setText("/dev/ttyUSB0");
connectButton = new JButton("Connect");
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(connectButton, c);
connectButton.addActionListener(listener);
}
public String getFieldText() {
return textField.getText();
}
}
Again, something outside of the simple GUI would make decisions on what to do with the text that the textfield contains and what to do with the GUI that is displaying this JPanel:
public interface ConnectionPanelControl {
void connectButtonAction();
}
Also, you will likely do any connecting in a background thread so as to not freeze your GUI, probably a SwingWorker. Perhaps something like this:
import java.awt.event.ActionEvent;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyMain extends JPanel {
public MyMain() {
add(new JButton(new ConnectionAction("Connect", this)));
}
private static void createAndShowGui() {
JFrame frame = new JFrame("My Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyMain());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class ConnectionAction extends AbstractAction {
private MyMain myMain;
private ConnectionPanel cPanel = null;
private JDialog dialog = null;
public ConnectionAction(String title, MyMain myMain) {
super(title);
this.myMain = myMain;
}
#Override
public void actionPerformed(ActionEvent e) {
if (dialog == null) {
dialog = new JDialog(SwingUtilities.getWindowAncestor(myMain));
dialog.setTitle("Connect");
dialog.setModal(true);
cPanel = new ConnectionPanel(new ConnectionPanelControl() {
#Override
public void connectButtonAction() {
final String connectStr = cPanel.getFieldText();
new MySwingWorker(connectStr).execute();
}
});
dialog.getContentPane().add(cPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
dialog.setVisible(true);
}
private class MySwingWorker extends SwingWorker<Boolean, Void> {
private String connectStr = "";
public MySwingWorker(String connectStr) {
this.connectStr = connectStr;
}
#Override
protected Boolean doInBackground() throws Exception {
// TODO: make connection and then return a result
// right now making true if any text in the field
if (!connectStr.isEmpty()) {
return true;
}
return false;
}
#Override
protected void done() {
try {
boolean result = get();
if (result) {
System.out.println("connection successful");
dialog.dispose();
} else {
System.out.println("connection not successful");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
Your code would be much more readable if you named JFrame instances xxxFrame, and JPanel instances xxxPanel. Naming JPanel instances xxxFrame makes things very confusing.
It would also help if you pasted the stack trace of the exception.
I suspect the problem comes from the fact that frame is null. This is due to the fact that the frame field is only initialized in the createAndShowGUI method, but this method doesn't display the current connection panel, but a new one, which thus have a null frame field:
ConnectionFrame firstPanel = new ConnectionFrame();
// The firstPanel's frame field is null
firstPanel.createAndShowGUI();
// the firstPanel's frame field is now not null, but
// the above call opens a JFrame containing another, new ConnectionFrame,
// which has a null frame field
The code of createAndShowGUI should contain
frame.add(this);
rather than
frame.add(new ConnectionFrame());
for Swing GUI is better create only once JFrame and another Top-Level Containers would be JDialog or JWindow(un-decorated by default),
simple example here
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SuperConstructor extends JFrame {
private static final long serialVersionUID = 1L;
public SuperConstructor() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300, 300));
setTitle("Super constructor");
Container cp = getContentPane();
JButton b = new JButton("Show dialog");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
FirstDialog firstDialog = new FirstDialog(SuperConstructor.this);
}
});
cp.add(b, BorderLayout.SOUTH);
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.exit(0);
}
});
add(bClose, BorderLayout.NORTH);
pack();
setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SuperConstructor superConstructor = new SuperConstructor();
}
});
}
private class FirstDialog extends JDialog {
private static final long serialVersionUID = 1L;
FirstDialog(final Frame parent) {
super(parent, "FirstDialog");
setPreferredSize(new Dimension(200, 200));
setLocationRelativeTo(parent);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
JButton bNext = new JButton("Show next dialog");
bNext.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
SecondDialog secondDialog = new SecondDialog(parent, false);
}
});
add(bNext, BorderLayout.NORTH);
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
add(bClose, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}
private int i;
private class SecondDialog extends JDialog {
private static final long serialVersionUID = 1L;
SecondDialog(final Frame parent, boolean modal) {
//super(parent); // Makes this dialog unfocusable as long as FirstDialog is visible
setPreferredSize(new Dimension(200, 200));
setLocation(300, 50);
setModal(modal);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setTitle("SecondDialog " + (i++));
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
add(bClose, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}
}
better would be re-use Top-Level Containers, as create lots of Top-Level Containers on Runtime (possible memory lack)