I experiment with my applet using Eclipse and its Applet Viewer. The Applet Viewer appears on the top of Eclipse and during Applet execution I click on Eclipse icon to maximize it from task bar. Then Applet Viewer loses the focus and Applet.stop() gets called.
When I minimize Eclipse, Applet Viewer goes to front again, gains focus and Applet.start() gets called. This ends up in a complete mess.
Is it normal behavior for a browser to call Applet.stop once user changes to another Tab or minimizes the browser Can I disable that, I want stop never been called.
Maybe I am missing something in threads.
My code is something like this:
public class AppletApp extends JApplet {
public void init() {
super.init();
System.out.println("AppletApp.init()");
}
public void start() {
System.out.println("AppletApp.start()");
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
getContentPane().add(new JLabel("Test Label"));
}
});
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {}
Runnable runnable = new Runnable() {
#Override
public void run() {
//For DJ Browser Component
NativeSwing.initialize();
NativeInterface.open();
//connect to server and start message exchange
Client.init(userInterface);
userInterface.authenticate();
NativeInterface.runEventPump();
}
};
Thread t = new Thread(runnable);
t.start();
}
public void stop() {
System.out.println("AppletApp.stop()");
}
public void destroy() {
System.out.println("AppletApp.destroy()");
}
}
Is it normal behavior for a browser to call Applet.stop once user
changes to another Tab or minimizes the browser?
Yes it is normal. From the javadoc:
Called by the browser or applet viewer to inform this applet that it
should stop its execution. It is called when the Web page that
contains this applet has been replaced by another page, and also just
before the applet is to be destroyed.
When you switch tab, I consider that the containing web page has been replaced hence it is logical that stop() is invoked.
Can I disable that, I want stop never been called.
No you can't, you don't have control on that. However, you could rely on the init() and the destroy() methods instead of start() and stop(). start() and stop() are meant for resuming/pausing anything that consumes resources which are not necessary if not visible (for example an animation is pointless if not visible).
Related
Hello StackOverflowers,
I'm currently working on my first Client/Server application and facing a problem that doesn't make sense to me at all. Please note that I'm new to network programming and working with runnables/threads.
I'm using the MVC pattern for my application, so I have a ServerController, ServerView and ServerModel.
Now there's a method in my ServerController which basically has 2 tasks.
Update the Server GUI - It is supposed to write a String "Server is starting..." in a JTextArea so the user knows the application did not crash
Invoke the Server
public ActionListener startServerListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
//Update GUI
view.updateServerNotice(new String("Server is starting..."));
//Start Server in new thread
Thread t1 = new Thread(model);
t1.start();
Thread.sleep(1000);
view.showNotification(model.hostAvailabilityCheck() + "");
} catch (Exception ex)
{
view.showNotification("Server is started already!");
}
}
};
My problem is, that the view.updateServerNotice(new String("Server is starting...")); method gets executed but doesn't show up in the GUI before the Server isn't started. So currently it is like the button is clicked, then there's a little delay (due to the sleep()) and THEN, after the server started, the GUI gets updated with "Server is starting...".
This doesn't make sense to me since the GUI updated is definitely executed before the new thread is created.
I hope someone sees something that I don't and can help me. It's not really a big problem, but I'm really curious why this is happening.
Thanks for your help in advance!
Swing (and AWT, and in fact many UI frameworks in most environments, not just Java) is single-threaded: nothing is going to be drawn as long as your ActionListener is running.
What you can do is running your code in a background thread, however in this case another issue kicks in: single-threaded UI frameworks do not really like random interactions from other threads. While direct access may work sometimes, the 'legal' approach is to send actions packed into some Runnable form, using SwingUtilities.invokeLater or invokeAndWait (I am using this latter one here, so your message will be visible for sure):
public ActionListener startServerListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
new Thread(new Runnable({
public void run(){
try{
// Update GUI #1
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
view.updateServerNotice(new String("Server is starting..."));
}
});
//Start Server in new thread
Thread t1 = new Thread(model);
t1.start();
Thread.sleep(1000);
// Update GUI #2
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
view.showNotification(model.hostAvailabilityCheck() + "");
}
});
}catch(Exception ex){/*...*/}
}
})).start();
}catch(Exception ex){/*...*/}
}
};
Beautiful, isn't it?
I am using InvokeAndBlock whenever any process based function performed. for example.
If I want to save something and it takes while to save the data then i used below code.
First show process dialog.
initProcessDialog();
progressDialog.showModeless(); // show process dialog
//Actual process
Display.getInstance().invokeAndBlock(new Runnable() {
public void run() {
saveAll("SAVE_ALL",jobData);
FileUtil.removeBackupFile(jobDataDetail.getJobTemplateFileName());
progressDialog.dispose();
}
});
also added InvokeAndBlock while any action performed which is time-consuming.
backButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
initLoadingDialog();
loadingDialog.showModeless();
Display.getInstance().invokeAndBlock(new Runnable() {
public void run() {
}
});
}
});
Any correction require in process ?
Since your calls to invokeAndBlock are mostly related to your own code its hard to tell what exactly you are doing.
The call to dialog.dispose() within invokeAndBlock is wrong. You need to call it after the invokeAndBlock which will work exactly the same without the EDT violation.
Codename One has one UI thread: the EDT.
invokeAndBlock opens a separate thread where you aren't allowed to access any UI related API's.
Java is not my mother tongue and I've been fighting with this problem for a little while.
Basically, I am finding a behavioural difference between calling method switchApplets() directly from init(), and calling it from within a new thread spawned by init().
The consequence of calling it from inside the new thread is that the new applet whitescreens -- until/unless the user resizes or minimizes their browser. If called at the end of init(), the new UI renders immediately without any input from the user. But that's not an option because it doesn't wait for the thread to finish its prep work.
Trimmed-down code:
public class PreLoader extends Applet implements AppletStub {
static JProgressBar pBar = null;
static JLabel message;
public void switchApplets() {
try {
Class main_class = Class.forName("MainClass");
Applet main_applet = (Applet)main_class.newInstance();
removeAll();
setSize(0,0);
setLayout(new GridLayout(1,0));
add(main_applet);
main_applet.init();
main_applet.start();
main_applet.setStub(this);
}
catch (Exception e) {
}
}
public void init() {
pBar = new JProgressBar(0, 100);
pBar.setValue(0);
pBar.setStringPainted(true);
message = new JLabel("Beginning work!");
add(message);
add(pBar);
FlowLayout flow = new FlowLayout();
setLayout(flow);
Thread t = new Thread ( new Runnable () {
public void run ()
{
longRunningFunction1();
longRunningFunction2();
message.setText("Work complete! Stand by..");
switchApplets(); //does NOT work as intended from here
return;
}
} );
t.start();
//switchApplets(); //works as intended if called HERE
}
public void longRunningFunction1() {
//perform some tasks, advance progress bar
}
public void longRunningFunction2() {
//perform some tasks, advance progress bar
}
public void start() {
return;
}
public void appletResize(int width, int height) {
return;
}
}
I tried making init() wait for the thread to finish so that I could call switchApplets() from there, but that only blocked the EDT and prevented the UI from updating. Also tried playing with SwingUtilities' invokeLater/invokeAndWait, but even though switchApplets() gets run on the EDT, it seems that it MUST be called directly from init() (or at least the thread init is running on) to have the desired effect.
Why does calling switchApplets() from within a new thread result in a slightly different (and unwanted) UI behaviour?
The consequence of calling it from inside the new thread is that the new applet whitescreens -- until/unless the user resizes or minimizes their browser.
It's likely a deadlock caused by trying to do UI code on the wrong thread.
I tried making init() wait for the thread to finish so that I could call switchApplets() from there, but that only blocked the EDT and prevented the UI from updating.
You're on the right track. You need to call switchApplets() only from the EDT, and only after the work is done on the other thread.
Are you sure you tried using invokeLater() or invokeAndWait() from within the spawned thread after the long running functions were done? It's been a long while since I did applets but I'm not aware of any applet-specific reason why it wouldn't work, and it would work in any other case. I.e.,
public void run()
{
longRunningFunction1();
longRunningFunction2();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
message.setText("Work complete! Stand by..");
switchApplets();
}
});
}
However, the most proper way to do this is with a SwingWorker rather than a manually created thread. SwingWorker (which is not nearly as well-known as it should be) is designed exactly for the goal of performing background tasks on a separate thread while still being able to update the GUI with progress updates and the results. E.g.,
new SwingWorker<Void,Void>() {
#Override
protected Void doInBackground() { // is called on a background thread
longRunningFunction1();
longRunningFunction2();
return null;
}
#Override
protected void done() { // is called on the Swing thread
message.setText("Work complete! Stand by..");
switchApplets();
}
}.execute();
The Void stuff is because SwingWorker is also capable of returning results and sending intermediate progress updates, but this example doesn't use those features.
You indicated that your long running functions are also updating a progress bar. That's another thing that should happen only on the Swing thread. In practice you can often get away without it, but it's dodgy. Your progress updates can use one of the SwingUtilities.invoke methods, or the mechanisms of SwingWorker; either should work. (SwingWorker itself provides two different ways to do it: Call addPropertyChangeListener (Swing thread) and setProgress (background thread), or call publish (background thread) and override process (Swing thread).)
Also, a small suggestion: if it's inconvenient to deal with a checked exception (or impossible to usefully do so), rather than catching and ignoring it, you should at least catch & rethrow it as an unchecked exception:
catch (Exception e) {
throw new RuntimeException(e);
}
That way, the stacktrace and error message of any exception will not be lost.
I'm writing an application which parses XML files (continuously) and show the data in a GUI (Swing). The ParseThread is in the CoreProject, and the GUI is in the GUIProject.
The start of the ParseThread is connected to a JCheckBoxMenuItem with an ItemListener. The value of setSelected() is set directly after adding to the Menu. At this time the GUI does not contain the Component which the ParseThread needs to show the parsed Data.
My Solution is, that the ParseThread should wait until the GUI is build completely.
I thought of something like an EventQueue but I have no Idea how to code one.
My Solution is, that the ParseThread should wait until the GUI is build completely. I thought of something like an EventQueue but I have no Idea how to code one.
you have got issue with Concurency in Swing, your hard and long running task should be moved to the Background task, for Swing there are two possibilities
(easy & simple) use Runnable#Thread, output to Swing GUI must be wrapped into invokeLater(), including thread safe methods as are setText, append e.i.
use SwingWorker
EDIT
please to check my visulaizations for Runnable#Thread this is the same thing as you connect server, parse long file e.i.,
with invokeLater() I cannot be sure that the component exists until the call
create GUI,
show GUI,
some (Swing / Util) Timer or user action to invoke code that is/are redirected out of Swing EventDispatchThread, for this reason there are Runnable#Thread or SwingWorker
I'm suggest two easiest of possible ways
Ok, I got my problem...
The GUI is created like this:
EventQueue.invokeAndWait(new Runnable() {
#Override
public void run() {
try {
Mainframe frame = new Mainframe();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
And at construction of the Object Mainframe this code will be executed:
final JCheckBoxMenuItem chckbxmntmParsing = new JCheckBoxMenuItem("Parsing");
chckbxmntmParsing.setName("mainframe.menu.data.parsing");
localeChangedListener.add(chckbxmntmParsing);
chckbxmntmParsing.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (chckbxmntmParsing.isSelected()) {
parseManager.startParsing();
} else {
parseManager.stopParsing();
}
}
});
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
boolean enabled = false;
String prop = PropertyManager.get().getProperty("parser.continuousparsing.enabled");
if (prop != null) {
if (prop.trim().equals("true") || prop.trim().equals("1")) {
enabled = true;
}
}
chckbxmntmParsing.setSelected(enabled);
}
});
So the ParseThread will start after GUI is build.
Sorry for stealing your time
The issue is when I close my GUI windows I wanna run a last method ( for example printList() ) but I couldn't manage to do it. This is my main method
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
patientTest2 screen = new patientTest2();
screen.setVisible(true);
screen.setResizable(false);
} catch (FileNotFoundException ex) {
Logger.getLogger(patientTest2.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
patientTest2 is my JFrame class. I assume that if I put printList() before } catch (FileNotFoundException ex) { it should work and finally print my list to a file but it doesn't. I will be glad if you can help me and explain why of course_?
You should add a listener that extends WindowAdapter to your frame, and override the method windowClosing(WindowEvent e). In this method, you will be able to call any methods you want to call before the window is closed.
You need to
change the default close operation to JFrame.DO_NOTHING_ON_CLOSE (if the window is a JFrame)
add a WindowListener to your top-level window
listen for window closing events, calling your method
and then finally exit the JVM with the appropriate exit code (usually 0 if no errors).
If you want to have something that runs when you Java VM gets shut down, then you should have a look at
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
//The stuff you want to do at shutdown.
}
}));
Please read the here for further information.
You also should set the DefaultCloseOperation of your Window if you want to close your Programm (and shutdown your Java VM) when the JFrame is closed.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This is I think what you were asking for. Hope this helps.