Lag before JFrame event handlers are added? - java

I'm working on a simple Java swing project. This is the code of the main class (name changed):
public class MainProg
{
private static MainProg program;
//mainWin is a JFrame
private MainWindow mainWin;
//Event handler class which extends MouseAdapter
private TrayManager trayMgr;
public static void main(String[] args)
{
program = new MainProg();
}
public MainProg()
{
mainWin = new MainWindow();
trayMgr = new TrayManager();
mainWin.startBtn.addMouseListener(trayMgr);
mainWin.setVisible(true);
}
}
As is clear, when the program starts, in main() it creates a new instance of the MainProg class, which then calls the constructor. In the constructor, it creates a new instance of the JFrame mainWin. It then attaches an event handler to a button on mainWin.
In the event handler class trayMgr, the only method is mouseClicked() which does nothing
except a System.out.println('Clicked');
The issue is, when I run this program in Netbeans, the JFrame is shown right away, but I seem to have to click the button 2-3 times before the message is printed in the console.
Is this just something specific to Netbeans, or do I have to change something to make the event handler be set before the window is made visible?

Your threading issue is not likely one that is causing your current problem, but there's the theoretic potential for problems, and I've seen some real problems associated with some of the more touchy look and feels. Quite simply you should queue your code that starts your GUI onto the Swing event thread. You do this by doing:
public void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(
public void run() {
program = new MainProg();
}
));
}
Someone else recommended using invokeAndWait(...) instead of invokeLater(...) but this can be risky especially if you inadvertently make this call from within the Swing event thread itself. For your situation you're better off using invokeLater(...).
But again, I think the main problem with the code you have shown was inappropriate use of MouseListener where an ActionListener should have been used. Learning to code any GUI library can be quite tricky, and for that reason, you can't assume anything. Check out the tutorials and learn from the experts. Also if you are considering coding Swing for the long haul, consider ditching the NetBean's code-generation utilities and learn first to code Swing by hand. You won't regret doing this.

Since you asked, the code I posted here is a Java SSCCE on a different topic. invokeLater is a way of running computations on the EDT. (There is also invokeAndWait, which would work fine here, but under some other conditions can cause a deadlock.)
In fact this example is perhaps a bit over-conservative. Some references say you can run Swing from the main thread the call to show() or setVisible(). However I have a program that misbehaves under Java 7 when I try that.

Related

What is the difference and efficiency between main() and run()?

So I'm very new to the JSwing world, having not covered much in my AP Computer Science class I finished last year. So, I am familiar with inheritance and all the core parts of the Java language, but I can't see the difference between the two methods main() and run().
My code here works just fine for right now:
Main Class:
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Main {
private JFrame frame;
public Main() {
frame = new JFrame("SoundCombine"); //Create frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Close the frame when |x| button is pressed
//Add components to the frame
JButton button = new JButton();
frame.getContentPane().add(button, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
Run Class:
public class Run {
public static void main(String args[]){
new Main();
}
}
However, I've also seen this method of starting JSwing applications:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
What is the big difference between the two? What sort of problems would I encounter down the road by using either one of the two. Although there are many different ways to write the same program, I want to know the conventional way of going about this.
Thanks!
You're asking what's the difference between an orange and a buffalo -- these are two completely different things.
The main method is the entry point of all Java programs, even those without main methods such as applets where there actually is a main method, but it's hidden from view.
The run method you speak of is a method that needs to be part of any class that implements a Runnable interface. This is not the entry point for programs to start.
Your example above, that is to feed a Runnable into the SwingUtilities.invokeLater(...) method is a way to guarantee that the code within the Runnable's run method is called on the Swing event thread, something that you want to do when starting Swing (not JSwing) applications for thread safety purposes, since if you don't do this, there are risks of errors (actually exceptions) being thrown.
Swing applications still need a main method regardless of whether you queue them on the Swing event thread or not. It's not "either use main or run", since again, they are totally different animals.
Just because some code "works for now" is no guarantee that it will work later. Threading exceptions are notorious for occurring intermittently and when least desired.

Best practice for initialization code in Java Swing

I have some initialization code that needs to be run when my Java Swing application starts, without any events being triggered.
My initialization code is in the myInits() function. myInits() does all sorts of thing: reads config from a file, sets the background and some labels, spawns network threads, initializes variables.
From googling and my own knowledge i have figured out different ways to achieve this(please correct me if any of the assumptions stated below are wrong):
Run myInits() when the Window_Opened event is triggered.
This makes sure the GUI is painted and myInits() can access any component and change it. Unfortunately I can't use this method because my application starts hidden and Window_Opened doesn't get triggered.
Put myInits() inside the JFrame constructor:
public class MyFrame extends javax.swing.JFrame {
private MyFrame(){
initComponents(); // <= Auto generated by NetBeans GUI Builder
myInits();
}
}
I suppose there's nothing wrong with this methoed because initComponents() itself does all kinds of GUI manipulation. I used this method and it worked just fine.
But today I changed MyFrame into a Singleton and i got a java.lang.ExceptionInInitializerError. Because myInits() calls MyFrame.getInstance() and by putting it in the constructor I'm technically calling getInstance() inside another getInstance(). I tried making getInstance() synchronized but it didn't work.
Make myInits() public and call it from main() :
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ChatFrame().myInits();
}
});
}
I personally don't like this method because i don't want myInits() to be public. Also because I like number 4 better.
invokeLater myInits() in the constructor.
private myFrame(){
initComponents();
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
myInits();
}
});
}
This is what i myself came up with. Because the instantiation itself is being done in an invokeLater() method(see number 3), I figured I could be sure that myInits() will run after new myFrame(); has finished and i can safely call MyFrame.getInstance().
To sum it up:
1) Are all of these methods correct?
2) Is any of these (or other possible methods i may have not mentioned) considered the best practice?
3) Which one is the best practice for a Singleton JFrame?
4) Why when i synchronized my getInstance() method i still got the java.lang.ExceptionInInitializerError?
In my opinion, if your initialization logic in not ui specific, it should be in main. Extract a separate class out of myinit, and call it in main.
You may also make it singleton using enum, and use it, so that it gets initialized upon first use/ application load.

Why does my boilerplate Java desktop app JFrame use EventQueue.invokeLater in the main method?

I am using the latest Eclipse, and GWT Designer, to make a swing application in Java.
The main function in my application window (which is a javax.swing.JFrame) in the auto generated by the tools looks like this:
/* launch the application */
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This seems like a lot of noise around what could have been just this:
public static void main(String[] args) {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
I have read that the EventQueue.InvokeLater technique is required in some situations, and another question asks where to use it here.
My question is simpler; Why do this automatically in the code generator here? Why should main return quickly and let the application window get created later by the event queue? Wouldn't blocking be exactly the point? Why is the JFrame auto-generated designer doing this EventQueue stuff? I have tried to see some difference in the start up and showing of forms whether this code is done the simpler way or the harder way, and I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me, and that perhaps in real-world large complex Jframe based classes, there is some benefit to this delaying/queuing strategy?
Depending on your application and how it's being used, it's possible that there could be something that is drawing on the screen (and thus using the EventQueue) before or during the call to your main method. Calls that modify any UI components should be made on the Event Dispatch Thread, and this includes setting the application visible.
So just to be safe, it's a good practice to start your application on the EDT.
Why do this automatically in the code generator here?
It won't hurt, it's easy to generate, and it's considered good practice.
Why should main return quickly and let the application window get created later by the event queue?
It's possible that the main method is being called from some other application that is using the EDT and may have already drawn something on screen. If you draw your application directly in main, it's possible that your application may be altering some component that is in the process of being handled by something on the EDT, and potentially already drawn on the screen.
So just to be safe in case this situation ever happens, you should leave it up to the EDT to draw your application so it can do it when it won't interfere with anything else.
Wouldn't blocking be exactly the point?
Unless something else is calling main other than the JVM process that your user started by double-clicking the desktop icon, it's not going to make a difference when main returns as long as there is something on the screen.
I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me
You're right - most of the time it's probably not gonna make a difference, but I presume they included it because it was easy to generate & implement, it can't hurt, and it would exemplify good practice.
1) why is building Swing GUI inside try-catch-finally, I can't see any reason(s) for that, split create non thread safe GUI and non thread safe code to the separates threads,
2) Swing isn't thread safe, then correct is in all cases that pack() + setVisible(true) would be
last GUI rellated code lines
wrapped into invokeLater
forgot for examples from some code ExamplesDepots, this forum, another forums, sure these code works, but with risk that whatever/everything could happen
correct Swing GUI launch
for example
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
}
});
}
3) is there some Serializable, Custom L&F then (better would be) wrap into invokeAndWait

Java: Calling static method but nothing happens?

I have a class called GUI which basically creates a latout using Swing. In that class i have a method called "log" which is supposed to add a new line to a textarea in the layout.
The problem is that whenever i call the function from outside of the GUI class, nothing happens. If i call the method from within the class it adds a line to the textarea as it's supposed to do.
I have set the method and all the variables it calls to public static, and i don't get any errors. It just doesn't do anything when i call the method from the outside.
Any ideas?
Edit:
Here's the method within the GUI class:
public static void log(String inputString) {
logConsole.append(inputString + "\r\n");
}
At the bottom of the class swing declared the textarea, and i just modified it to be public static instead of private.
public static javax.swing.JTextArea logConsole;
Can't post more code, hope this is at least a little bit helpful? :/
It's most likely a concurrency issue with Swing. Since Swing is single-threaded, Swing components need to be modified in the Event Dispatch Thread (i.e. EDT). For more information, see Concurrency in Swing.
EDIT -
If this is indeed a concurrency issue, then one quick workaround would be to use SwingUtilities. In particular, isEventDispatchThread() and invokeLater(...). For instance,
if(!SwingUtilities.isEventDispatchThread()){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
GUI.log("foo"); // modify textarea in EDT
}
});
}
else{
// your problem lies elsewhere
}

Main Thread vs. UI Thread in Java

In many Swing snippets given here as answers, there is a call to SwingUtilities#invokeLater from the main method:
public class MyOneClassUiApp {
private constructUi() {
// Some Ui related Code
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MyOneClassUiApp().constructUi();
}
});
}
}
But according to the Threads and Swing article, it is safe to construct UI from main thread:
A few methods are thread-safe: In the Swing API documentation,
thread-safe methods are marked with this text:
This method is thread safe, although most Swing methods are not.
An application's GUI can often be constructed and shown in the main
thread: The following typical code is safe, as long as no components
(Swing or otherwise) have been realized:
public class MyApplication {
public static void main(String[] args) {
JFrame f = new JFrame("Labels");
// Add components to
// the frame here...
f.pack();
f.show();
// Don't do any more GUI work here...
}
}
So, is there a real (thread safety) reason to construct the UI in main through SwingUtilities#invokeLater, or this is just a habit, to remember do it in other cases?
"The Swing single-thread rule: Swing components and models should be created, modified, and queried only from the event-dispatching thread."—Java Concurrency in Practice, also discussed here and here. If you don't follow this rule, then you can't reliably construct, modify or query any component or model that may have assumed that you did follow the rule. A program may appear to work correctly, only to fail mysteriously in a different environment. As violations may be obscure, verify correct usage by using one of the approaches mentioned here.
I think that using SwingUtiltities.invokeLater() is just an easier way to execute some code asynchronously. Sometimes it is required for certain application: for example you can create 2 separate windows simultaneously. Nothing more.
It's safe to create your Swing UI in the main method because how would other components be displayed before you set up your UI? As long as you haven't thrown some stuff on the screen already you'll be fine. In other words, this would be bad:
public class MyApplication
{
public static void main(String[] args)
{
JFrame f = new JFrame("Labels");
// Add components to
// the frame here...
f.pack();
f.show();
// now make another frame:
JFrame f2 = new JFrame("Labels2");
// Add components to the 2nd frame here...
f2.pack();
f2.show();
}
}
If you did the above you'd have JFrame f up and running then you'd be adding Swing UI components off the Event Dispatch Thread (EDT). invokeLater runs the code on the EDT - it won't hurt to use it if you want extra peace of mind.

Categories