Starting and Disposing JFrame inside Runnable object, howto - java

What is the correct way of disposing a frame which is created inside a Runnable object?
The code below returns a null pointer exception when the endDialog is called before the LoadingRunnable has completed its constructor.
How can the endDialog be executed after the constructor has finished?
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LoadingRunnable implements Runnable
{
private JFrame jFrame;
#Override
public void run()
{
jFrame = new JFrame("Window");
JPanel jPanel = new JPanel();
JLabel label = new JLabel("Loading...");
jPanel.add(label);
jFrame.setContentPane(jPanel);
jFrame.pack();
jFrame.setVisible(true);
}
public void endDialog()
{
jFrame.setVisible(false);
jFrame.dispose();
}
public static void main(String args[])
{
LoadingRunnable l = new LoadingRunnable();
SwingUtilities.invokeLater(l);
//work done here
l.endDialog();
}
};

You have a concurrency problem here because SwingUtilities.invokeLater() schedules your runnable class execution in the Event Dispatch Thread asynchronously while your main thread's flow still running, causing a NPE.
The correct way to dispose a frame is through events, just as Swing is designed to be used. For instance by clicking the "X" (close) button or by dispatching a WindowEvent:
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
You may want to take a look to this question too: Optional way to close a dialog window
In addition
If you just want to show something during your application start up, then you can use SplashScreen API instead of JFrame. See How to Create a Splash Screen for further details.
Based on your previous question and this new one, I'd suggest you read the whole Concurrency in Swing tutorial to understand about common concurrency problems in Swing and how to deal with them.

Ok found how:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Loading
{
private JFrame jFrame;
public void startDialog()
{
jFrame = new JFrame("Window");
JPanel jPanel = new JPanel();
JLabel label = new JLabel("Loading...");
jPanel.add(label);
jFrame.setContentPane(jPanel);
jFrame.pack();
jFrame.setVisible(true);
}
public void endDialog()
{
jFrame.setVisible(false);
jFrame.dispose();
}
public static void main(String args[])
{
final Loading l = new Loading();
for (int i = 0; i < 200; i++)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
l.startDialog();
}
});
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
l.endDialog();
}
});
}
}
};

Related

Java - Applet to Executable Jar Wrapping

I have written a Java XML Parser as an Applet. It is looking and functioning well enough in this form.
My Question, Is if I want to run this without a browser, how Would I properly wrap it to run as an executable?
GUI.java
--------------
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GUI extends JPanel implements ActionListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
private Parser xmlEditor;
private String startTimeValue;
private String endTimeValue;
public GUI(){
init();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new GUI();
}
});
}
public void init() {
this.setXmlEditor(new Parser("C:\\Users\\Administrator\\workspace\\XMLParser\\src\\test.xml"));
add(new Label("Start Time"));
startTimeValue = xmlEditor.getStartTimeValue();
endTimeValue = xmlEditor.getEndTimeValue();
startTime = new TextField(startTimeValue);
add(new Label("End Time"));
endTime = new TextField(endTimeValue);
save = new Button("save");
save.addActionListener(this);
add(startTime);
add(endTime);
add(save);
}
public void actionPerformed(ActionEvent e)
{
System.out.println(endTime.getText());
xmlEditor.updateStartTimeValue(startTime.getText());
xmlEditor.updateEndTimeValue(endTime.getText());
System.out.println(e);
System.exit(0);
}
public Parser getXmlEditor() {
return xmlEditor;
}
public void setXmlEditor(Parser xmlEditor) {
this.xmlEditor = xmlEditor;
}
TextField startTime, endTime;
Button save;
}
While trying things with Swing and JFRame etc, I am not getting properly layout, or am opening multiple windows. Can anyone provide assistance? The second Panel Keeps replacing the First. Id like to really try to learn how to place multiple components inside an executable jar is the goal.
SwingPaintDemo.java
import java.awt.Label;
import java.awt.TextField;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
public class SwingPaintDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
Parser myParser = new Parser("C:\\Users\\Administrator\\workspace\\XMLParser\\src\\test.xml");
JPanel top = new JPanel();
top.add(new Label("Start Time"));
TextField startTimeField = new TextField(myParser.getStartTimeValue());
top.add(startTimeField);
f.getContentPane().add(top);
JPanel bottom = new JPanel();
bottom.add(new Label("End Time"));
TextField endTimeField = new TextField(myParser.getEndTimeValue());
bottom.add(endTimeField);
f.getContentPane().add(bottom);
f.pack();
}
}
JFrame uses a BorderLayout by default, where as a JPanel uses a FlowLayout
Instead of rebuilding the UI in the JFrame, simply add an instance of GUI to it, since you've already defined the functionality in a JPanel, this makes it easily reusable.
public class SwingPaintDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new GUI());
f.pack();
f.setVisible(true);
}
}
FYI: You should never reference src in any path element, src won't exist once the program is built and packaged. This is also doubly concerning for applets, as applets run in a tight security model, which prevents them from accessing the file system by default.
Instead, you should be using Class#getResource or Class#getResourceAsStream, depending on your needs.
this.setXmlEditor(new Parser(getClass().getResource("/test.xml")));
for example. You may need to change your Parser to accept either a URL and/or InputStream as well

JWindow not repainting until JFrame returns from while loop

Assume I have a JWindow and a JFrame called TestWindow and TestFrame which should both be shown at the same time, why does the TestWindow only draw a blank grey window without its label while the TestFrame is inside the while(true)???
And why if I remove the while(true) the TestWindow correctly shows?
This is as example of a more complex program where I need to show a splashscreen while the main application is starting which takes 1 or 2 seconds.
During this time the splashscreen should be shown regardless of the state of the main application, instead the splashscreen shows only when the main application is already finished, invokeAndWait doesn't actually wait for the splashscreen to be initialized.
TestFrame.java:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class TestFrame extends JFrame
{
public static void main(String args[])
{
try
{
SwingUtilities.invokeAndWait(new Runnable()
{
#Override
public void run()
{
new TestWindow();
}
});
}
catch (Exception ex)
{
Logger.getLogger(TestFrame.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new TestFrame();
}
});
}
public TestFrame()
{
super("TestFrame");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(new JLabel("sss"), BorderLayout.CENTER);
setSize(500, 120);
setVisible(true);
while(true)
{
//this makes the other not show
}
}
}
TestWindow.java:
import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
public class TestWindow
{
public TestWindow()
{
JWindow jWindow = new JWindow();
JPanel contentPanel = new JPanel();
final JLabel label = new JLabel("Test Window");
contentPanel.add(label, BorderLayout.CENTER);
jWindow.add(contentPanel);
jWindow.setSize(300, 200);
jWindow.setAlwaysOnTop(true);
jWindow.setVisible(true);
}
}
EDIT:
By the way, I realized putting a
catch (Exception ex)
{
Logger.getLogger(TestFrame.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
Thread.sleep(1000);
}
between the two TestWindow and TestFrame creation actually solves the problem, isn't there anything less hacky than this???
Your while (true) loop is being called on the Swing event dispatch thread, or EDT, tying it up and preventing this thread from doing its necessary actions including drawing all your GUI's and interacting with the user. The solution is simple -- 1) get rid of the while loop (as you already figured out), or 2) if the loop is absolutely necessary, do it in a background thread.
For more details on Swing threading, please check out Lesson: Concurrency in Swing.

Updating main GUI Elements in Java Swing

I'm trying to update the main gui in a java swing application, so there is a runnable thread that keeps the main gui visible, but the problem is it is called in main, and main is a static function. I would like to say Element.SetTtext. But all calls that I want to update are not static. How can I update the lables,..etc in the Main GUI then?
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
new AGC().setVisible(true);
// code to update labels here
}
});
}
What I understood from your question is that you think static means non-changeable. This is not true with Java. In Java objects and components that never change are characterized as final.
Keep your main simple and small and make your loops and changes in doThings();
Here is a Timer in order to update the text of the JLabel:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Foo extends JFrame {
public Foo() {
jLabel1 = new JLabel("label 1");
jPanel1 = new JPanel();
jPanel1.add(jLabel1);
add(jPanel1);
pack();
// code to update whatever you like here
doThings();
}
private void doThings() {
// code to update whatever you like here
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
jLabel1.setText("foo " + (j++));
}
};
Timer timer = new Timer(500, actionListener);
timer.start();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Foo().setVisible(true);
}
});
}
private JLabel jLabel1;
private JPanel jPanel1;
private int j = 0;
}
little more clarity is required , when do u want to update the labels ? is it based on an event ?
You can always keep a global variable of the component you want to update and access it from the event handlers.
Can you please update your question with the code , so that it gives a better clarity ?

JProgressBar not visible until told to show

I'm trying to make an application which shows a JProgressBar only while it is performing actions. My problem is, when the program is first opened, I set the JProgressBar visibility to false, then to true when an action is being performed and after it is done, back to false. It seems like it would work, and it does, just not when I make it not visible by default. If the visibility is true by default then it works well, but that's not quite what I want. How could I make it so that it isn't visible until I set it to be visible?
SSCCE just incase my question wasn't clear enough:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
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.JProgressBar;
public class SmileBack {
private JFrame frame;
private JPanel panel, container;
private JButton loadButton;
private JProgressBar progressBar;
public static void main(String[] arguments) {
new SmileBack().constructFrame();
}
public void constructFrame() {
frame = new JFrame("RSTracker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(getContentPane());
frame.pack();
frame.setVisible(true);
}
public JPanel getContentPane() {
panel = new JPanel(new BorderLayout());
progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
//progressBar.setVisible(false); // doesn't work when this is uncommented
loadButton = new JButton("Load memberlist");
loadButton.setEnabled(true);
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
new Thread(new Runnable() {
#Override
public void run() {
progressBar.setVisible(true);
// do my stuff here...
try {
Thread.sleep(2000); // just for the sake of example
} catch (InterruptedException e) {
e.printStackTrace();
}
progressBar.setVisible(false);
}
}).start();
}
});
container = new JPanel(new FlowLayout());
container.add(loadButton);
container.add(progressBar);
panel.add(container);
return panel;
}
}
Ignore the name, I was listening to that song while creating this. :)
This is probably not the way it should be designed, but this code fixes the problem while still using the natural size (pack()) needed to display the button and progress bar. This is achieved by setting the progress bar to invisible after pack is called, but before setting the GUI visible.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
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.JProgressBar;
public class SmileBack {
private JFrame frame;
private JPanel panel, container;
private JButton loadButton;
private JProgressBar progressBar;
public static void main(String[] arguments) {
new SmileBack().constructFrame();
}
public void constructFrame() {
frame = new JFrame("RSTracker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(getContentPane());
// after this, everything is instantiated;
frame.pack();
setProgressBarVisibility(false);
frame.setVisible(true);
}
public void setProgressBarVisibility(boolean visible) {
progressBar.setVisible(visible);
}
public JPanel getContentPane() {
panel = new JPanel(new BorderLayout());
progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
loadButton = new JButton("Load memberlist");
loadButton.setEnabled(true);
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
new Thread(new Runnable() {
#Override
public void run() {
progressBar.setVisible(true);
// do my stuff here...
try {
Thread.sleep(2000); // just for the sake of example
} catch (InterruptedException e) {
e.printStackTrace();
}
progressBar.setVisible(false);
}
}).start();
}
});
container = new JPanel(new FlowLayout());
container.add(loadButton);
container.add(progressBar);
panel.add(container);
return panel;
}
}
any events in your case (from Runnable#Thread) doesn't invoke EventDispashThread you have to wrapp that into invokeLater, otherwise since JProgressBar will be visible but after long running taks ended shouldn't be hidden
1) all changes to the GUI must be done on EDT
2) you can invoke EDV from Swing's Listeners, SwingWorker's methods process and done and invoke changes to the GUI by using invokeLater (in special cases invokeAndWait)
3) Runnable#Thread by default doesn't invoke Swing's Methods nor EDT, there must be output to the GUI wrapped into invokeLater (in special cases invokeAndWait), more in the Concurency in Swing, inc. thread safe methods as are setText(), append() etc.
In your thread call the progressBar.setVisible(true); inside SwingUtilities.invokeAndWait().
The code you have posted works perfectly well. The problem is when you call frame.pack(), the frame resizes to fit all visible component. When you have progressBar visibility set to false, the frame ignores this component and sizes accordingly. So when progressBar.setVisible(true) is called later, the component is shown but the frame is not big enough for you to see the component. If you just drag and increase the size of the frame, you can see the progressBar
I suggest that you provide explicit frame size like frame.setSize(200,400) and dont call frame.pack().

Java GUI programming: Setting the Fore/Background

I'm just getting into GUI programming, slowly learning.
However I'm having a problem right of the bat. I can't get the Fore/Background color to change in my window at all.
However when I add a label via JLabel and then use setFore/Back, they change colors just fine. Just not the whole window.
I thought .setForeground and .setBackground are supposed to change the color of the window?
import javax.swing.*;
import java.awt.*;
public class MyWindow {
public static void main(String args[])
{
Runnable init = new Runnable()
{
public void run()
{
JFrame myWindow = new JFrame("Hola!");
myWindow.setForeground(Color.YELLOW);
myWindow.setBackground(Color.YELLOW);
myWindow.setSize(400, 300);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setLayout(null);
myWindow.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
First of all, do not use a null layout. Let the layout manager do its job. Second of all, you need to set the background of the content pane of the JFrame instance, as such
myWindow.getContentPane().setBackground(Color.YELLOW);
See also:
Using Top-Level Containers
you cannot color a frame. However you can color the ContentPane inside.
import javax.swing.*;
import java.awt.*;
public class MyWindow {
public static void main(String args[])
{
Runnable init = new Runnable()
{
public void run()
{
JFrame myWindow = new JFrame("Hola!");
myWindow.getContentPane().setBackground(Color.YELLOW);
myWindow.setSize(400, 300);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setLayout(null);
myWindow.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
this should fix your problem...
tangina naman ang bobo naman neto, pokegooo
import javax.swing.;
import java.awt.;
public class MyWindow {
public static void main(String args[])
{
Runnable init = new Runnable()
{
public void run()
{
JFrame myWindow = new JFrame("Hola!");
myWindow.getContentPane().setBackground(Color.YELLOW);
myWindow.setSize(400, 300);
myWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myWindow.setLayout(null);
myWindow.setVisible(true);
}
};
SwingUtilities.invokeLater(init);
}
}
// tanga amputa aral ka muna dudong
// pakangkang

Categories

Resources