What is the best practice way to start a java swing application? Maybe there is another way to do it.
I want to know if i have to use the SwingUtilities class to start the application (secound possibility) or not (first possibility).
public class MyFrame extends JFrame {
public void createAndShowGUI() {
this.setSize(300, 300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
// add components and stuff
this.setVisible(true);
}
public static void main(String[] args) {
// First possibility
MyFrame mf = new MyFrame();
mf.createAndShowGUI();
// Secound possibility
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame mf = new MyFrame();
mf.createAndShowGUI();
}
});
}
}
Only the second way is correct. Swing components must be created and accessed only in the event dispatch thread. See concurrency in swing. The relevant quote:
Why does not the initial thread simply create the GUI itself? Because almost all code that creates or interacts with Swing components must run on the event dispatch thread. This restriction is discussed further in the next section.
So yes, you need to use invokeLater().
Related
I understand that EventQueue.invokeLater() is a function called to make the Java Swing components Thread-Safe.
Also, I know that the argument to this function is an object with implements Runnable.
However, I am unable to understand the syntax for this function call, i.e. this call -
EventQueue.invokeLater(()-> {
new Screen();
});
Here, Screen() is a class that extends JFrame.
public class Screen extends JFrame
{
Screen()
{
setSize(1000, 1000);
JPanel j1 = new Board();
j1.setBounds(0,0,500, 500);
JPanel j2 = new DiceModel();
j2.setBounds(500, 0, 500, 500);
add(j1);
add(j2);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(()-> {
new Screen();
});
}
}
This code runs as expected.
Board and DiceModel are two classes I have defined that which extend JPanel.
The invocation
EventQueue.invokeLater( new Screen() );
gives the expected error that Screen is not an object of type Runnable.
So,my question is, what is the meaning of the syntax for the function call for invokeLater() ?
Is it a kind of anonymous function call in Java ?
The complete Swing processing is done in a thread called EDT (Event Dispatching Thread). Therefore you would block the GUI if you would compute some long lasting calculations within this thread.
The way to go here is to process your calculation within a different thread, so your GUI stays responsive. At the end you want to update your GUI, which have to be done within the EDT. Now EventQueue.invokeLater comes into play. It posts an event (your Runnable) at the end of Swings event list and is processed after all previous GUI events are processed.
Also the usage of EventQueue.invokeAndWait is possible here. The difference is, that your calculation thread blocks until your GUI is updated. So it is obvious that this must not be used from the EDT.
Still there is Java code out there that starts a JFrame simple from the main thread. This could cause issues, but is not prevented from Swing. Most modern IDEs now create something like this to start the GUI
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
This question already has answers here:
Extends JFrame vs. creating it inside the program
(6 answers)
Closed 7 years ago.
so I've found multiple ways of implementing a swing GUI in java but don't know what each does and my teacher isn't able to help me. One method of creating a JFrame is:
import javax.swing.*;
import java.awt.*;
public class UI extends JFrame{
public UI() {
initaliseGUI();
}
private void initaliseGUI(){
setTitle("My Title");
setBackground(Color.red);
setSize(800,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args){
EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
UI M = new UI();
M.setVisible(true);
}
});
}
But another way of implementing it is:
import javax.swing.*;
import java.awt.*;
public class Main{
public static void main(String[] args){
JFrame window = new JFrame();
window.setSize(500,500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = window.getContentPane();
c.setBackground(Color.red);
window.setBackground(Color.red);
window.setTitle("main");
JLabel message = new JLabel("JLabel");
window.add(message);
window.setVisible(true);
}
}
what is the difference between how each one works and when should I use one over the other and how does the runnable work in this context?
thankyou!
Your first example calls the EventQueue invokeLater method, but extends a JFrame.
Your second example puts everything in the static method main, and doesn't run the invokeLater method.
Here's one way I start a Swing application.
public class TryingProject2 implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TryingProject2());
}
#Override
public void run() {
JFrame frame = new JFrame("Color Gradient Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel();
// Add your Swing components here
return panel;
}
}
I don't extends Swing components. I use Swing components. The only time you extend a Swing component, or any Java class, is when you want to override one of the class methods.
The SwingUtilities invokeLater method is the same as the EventQueue invokeLater method. This method puts the creation and updates of all Swing components on the Event Dispatch thread.
I implement Runnable because it makes the invokeLater method parameter an instance of the class.
I create the main panel in a method to keep the JFrame code separate from the JPanel(s) code.
testing a game, i sometimes get exceptions thrown when a component is not displayable. i added a wait loop on isDisplayable().
seems like my game can take a few hundred ms. to become displayable.
is this a sane way to handle this problem?
i am testing game clients that talk over sockets to a server.
thanks
edit 1: thanks for the comments. i discovered that i am adding the mediator for the gui (an observer) to the model (an observable) before the gui completes its construction and initialization. it gets worse, as i am initializing a panel with calls to createImage which returns null and throws.
import java.awt.*;
import javax.swing.*;
public class WaitForFrameToBeVisible {
JFrame frame=new JFrame("FrameDemo");
private void createAndShowGUI() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel=new JLabel("");
emptyLabel.setPreferredSize(new Dimension(175,100));
frame.getContentPane().add(emptyLabel,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
void run() throws Exception {
System.out.println("waiting for frame to be displayable");
long t0=System.nanoTime();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
while (!frame.isDisplayable())
Thread.sleep(1);
long dt=System.nanoTime()-t0;
System.out.println("waited "+dt/1_000_000.+" ms. for frame to be displayable");
}
public static void main(String[] args) throws Exception {
new WaitForFrameToBeVisible().run();
}
}
You don't need to use isDisplayable(). You could use invokeAndWait(...) for what you are trying to do :
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createAndShowGUI();
}
});
// control will reach here when the GUI will be created
Notice that this way you are not actually checking if the frame is visible but you are checking if createAndShowGUI() has done its work
Another thing is you should not call isDisplayable() or any function like this in loop. It will consume unnecessary processing speed. Instead use wait-notify.
But as far as your case is concerned to use WindowListener is very good idea as suggested by MadProgrammer in comment.
I have one simple question why do I need write code like this with
SwingUtilities.invokeLater(new Runnable(){
If programm create same frame without it?
code with SwingUtilities
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class App {
public static void main (String args[]){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
JFrame frame = new JFrame("Hello world swing");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 400);
}
});
}
}
code without swing utilities.
import javax.swing.JFrame;
public class App {
public static void main (String args[]){
JFrame frame = new JFrame("Hello world swing");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 400);
}
}
Swing is not thread-safe, and is single-threaded. It relies on the Event Dispatch Thread (EDT) for creating, updating and rendering its components.
See http://en.wikipedia.org/wiki/Event_dispatching_thread
SwingUtilities.invokeLater and SwingUtilities.invokeAndWait are utility methods
to basically put your Swing related task into the EDT.
If you don't do it, it may fail eventually. You will see weird results, as your application becomes bigger.
Always do GUI (SWING) related operations on EDT.
Also most GUIs are single-threaded. So is Swing. Therefore, trying to
access Swing from more than one thread will increase the risk of application failing.
Read this
http://codeidol.com/java/java-concurrency/GUI-Applications/Why-are-GUIs-Single-threaded/
In your code, a Swing Operation (creation of JFrame) is being done on main thread, which is not recommended. Use SwingUtilities.invokeLater().
When I initiate my Swing dialog layout does it make a difference whether I do it in the class's run method:
public void run()
{
frame = new JFrame();
...
frame.setVisible( true );
}
or the class constructor?
public MyClass
{
frame = new JFrame();
...
frame.setVisible( true );
}
public void run()
{
}
Thanks
Yes it does matter, and the reason is that you should call most Swing code, including creation of your JFrame, on the Swing event thread (the Event Dispatch Thread or EDT). To do this, you usually create your Swing GUI in a Runnable, and queue the Runnable on the event thread by calling something like:
SwingUtilities.invokeLater(new Runnable(){
public void run() {
// create your Swing GUI here
frame = new JFrame();
...
frame.setVisible( true );
}
});
The exceptions are Swing method calls that are documented in the API to be thread-safe such as the repaint() method of Components.
This is contextual. As #hovercraftfullofeels points out, you need to make sure ALL your UI code is executed in the EDT, including initalisation.
If you're already running in the EDT, then there shouldn't be any need to use InvokeLater (unless you really want to), otherwise you MUST resync the call back to the EDT.
Best to check with EventQueue.isDispatchingThread