How can I implement the 'restart application' feature in Java [duplicate] - java

This question already has answers here:
How can I restart a Java application?
(13 answers)
Closed 9 years ago.
In many software, after we make any changes, the software has to be restarted for the changes to take effect, and sometimes, there is an option to restart the software automatically. How can I implement this in Java?
This is what I have tried:
int o = JOptionPane.showConfirmDialog(
frame,
"<html>The previously selected preferences have been changed.<br>Watch must restart for the changes to take effect.<br> Restart now?</html>",
"Restart now?", JOptionPane.YES_NO_OPTION);
if(o == JOptionPane.YES_OPTION) {
try {
Process p = new ProcessBuilder("java", "Watch").start();
} catch(IOException e) {
e.printStackTrace();
}
frame.dispose();
However, this doesn't seem to work. The application just terminates. What am I missing here? Thanks in advance!

This looks interesting: Make your application restart on its own
Basically, you create a script to run your app. In your app, if the user choses to restart, a restart file is created, then the app exits. Upon exiting, the startup script checks for the existence of a restart file. If exists, call the app again.

I think this is hard using just the facilities of the JVM alone.
I've never done this, but if you really want to terminate the whole JVM in which your current application is running and start a completely new instance of it, I would probably try something along these lines:
From your main application thread, start a shell script / batch file (e.g. using Runtime.getRuntime().exec("...")` that does the following steps:
Forks or uses some other system facility of starting the next step(s) in the background.
Maybe wait some time so you can be sure the old instance is dead. Or wait until some kind of PID file or similar thing is removed telling you that the old instance is gone.
Start a new JVM with your applications main class, probably giving it some command line argument or setting some system property to notify this new instance that it is in fact, an automatically restarted instance (so it can react to this e.g. by continuing where your originally left off).
In parallel to step 1 in your first main app instance, maybe wait a small amount of time (to make sure the background stuff is actually executed) and call System.exit(0); or some other method of shutting down.
Maybe there is a simpler way, it's just the first way that I could think of.

What about the next:
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
buildAndShowGui(args);
}
});
}
public static void buildAndShowGui(final String[] args) {
final JFrame frame = new JFrame("Window");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setSize(100, 400);
frame.setLayout(new FlowLayout());
JButton button = new JButton("Click!");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int option = JOptionPane.showConfirmDialog(frame, "Restart?");
if (option == JOptionPane.YES_OPTION) {
frame.dispose();
restart(args);
}
}
});
frame.add(button);
frame.setVisible(true);
frame.toFront();
}
public static void restart(String[] args) {
main(args);
}

Related

On closing the main Swing window, the other thread on the EventQueue gets not created

I write Java SE 8 desktop application. It's got a Swing UI.
Platform:
Eclipse IDE
Windows 10 OS
Now when I close the main window, by pressing on the "X" on the top-right-corner, I have a listener to listen for such event.
The listener right here:
private void listenerForClosingResources(){
this.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
if(e.getID() == WindowEvent.WINDOW_CLOSING){
CountDownLatch continueOn = new CountDownLatch(1);
saveUnsavedTmpProject(continueOn);
try {
continueOn.await();
}
catch(InterruptedException ee) {
ee.printStackTrace();
}
}
}
});
}
So, I use the listener to identify the window closing event, and when that happens I ask the user whether or not to save the project (it's data on DB).
This method (saveUnsavedTmpProject(continueOn);) leads to the other window which supposed to take the name under which to save the project.
Now the CountDownLatch forces the main window to stay up, up till when the user confirms/rejects saving the project on the other panel.
The other class method which creates the window, leading to saving the project, is right here:
public static void getInstance(CountDownLatch continueOn, String openProjectName) {
if(frame == null) {
synchronized(SaveAsPane.class) {
if(frame == null) {
carryOn = continueOn;
if(!openProjectName.isEmpty()){
openProject = openProjectName;
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new SaveAsPane();
frame.setVisible(true);
frame.setLocationRelativeTo(MainGUI.getMainGUI());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
}
Now, when I run the app, I don't get inside the run() method (and no window pops-up). But that only happens when I access this method only from the mentioned above listener. Which has the CountDownLatch, and it appears that it stops the execution of the new thread.
The latch gets counted-down when the user confirms/denies saving the project, so that the execution flow continues on.
Yet, I create the additional thread on the EventQueue.
How come that the thread gets stopped?
The Java group on facebook.com pointed me to the right direction.
The solution is this:
redefine what the close button (X) does on the main GUI.
And here it comes:
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
And now when I click the main GUI window's close button, the close does not lead to closing the window. Meaning that I don't need any longer the CountDownLatch class, which was stopping the main window from closing up (and waiting till the user counts-down on the other class).
In the end, I made the app to work in the way I like.

Prevent breaking of JTextField / JDialog with repeated transferFocus()

I have a very strange scenario which unfortunately I cannot prevent from occurring in my Swing application. When it occurs however, it has major consequences for me. Perhaps somebody could help!
The basic setup is as follows:
Linux environment.
Multiple JTextFields in a JFrame.
JTextFields push through transferFocus() when the Enter key is pressed.
A JDialog pops up on leaving one of the fields which requires the Enter key to be pressed to remove it.
The situation that causes the issue is as follows:
The Enter key is held down for a few seconds.
When the enter key is held down, the focus obviously flies through the different text fields. When the dialog box is shown, the enter key closes it causing the focus to then continue to fly through the text fields. Eventually, within a couple of seconds, Java breaks. The textboxes immediately stop responding to key strokes - you cannot type anything in them at all. Other than that, everything seems normal - you can click around and focus on different textboxes, close the application etc.
I have created a simple test case you can use to recreate the situation.
The JFrame:
public class TestSwing extends JFrame {
JTextField jtfText1, jtfText2, jtfText3;
TextHandler handler = null;
public TestSwing() {
super("TextField Test Demo");
Container container = getContentPane();
container.setLayout(new FlowLayout());
jtfText1 = new MyJTextField(10);
jtfText2 = new MyJTextField(10);
jtfText3 = new MyJTextField(10);
container.add(jtfText1);
container.add(jtfText2);
container.add(jtfText3);
handler = new TextHandler();
jtfText3.addActionListener(handler);
setSize(325, 100);
setVisible(true);
}
private class TextHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
JOptionPane.showConfirmDialog(null, "wait!");
}
}
public static void main(String args[]) {
TestSwing test = new TestSwing();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
The custom JTextField:
public class MyJTextField extends JTextField {
public MyJTextField(int len) {
super(len);
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_ENTER)
transferFocus();
}
});
}
}
To answer any potential questions up front:
The Enter key must be used to transfer the focus.
The spamming of the Enter key comes from the user leaving something on the keyboard (this is in the retail environment so this happens often).
Simply closing and restarting the application is not really an option as there is no mouse plugged into the computer. The application is booted up automatically on start-up making this scenario devastating as the only way to fix the problem is to restart the machine.
The machines aren't very powerful (processing & memory) which somehow causes the issue to happen a lot quicker than when it's recreated on a development machine.
Is this a bug in Java? Can anyone think of a way to prevent this from happening?
The closest I can get to preventing this from happening is to put a sleep(500) call in the JDialog (mine is extended) before it closes but that's not really a great fix...
I have tested this in JDK 1.6, 1.7 and 1.8. While it takes a bit longer in the later versions for the textboxes to become unresponsive, it still happens eventually.
Thanks in advance!
Xandel
Don't use KeyEvents. KeyEvents are generally used in AWT. Swing has newer and better API's to use (in most cases). In this case a JTextField was designed to respond to an ActionEvent when the Enter key is pressed.
You could try to keep track of the last time Enter was pressed and ignore events that seem to be invoked within the repeat rate of the OS. My repeat rate appears to be around 35ms:
import java.awt.event.*;
import javax.swing.*;
public class MyJTextField extends JTextField
{
private static long lastTime = System.currentTimeMillis();
public MyJTextField(int len)
{
super(len);
addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
long diff = evt.getWhen() - lastTime;
System.out.println(diff);
if (diff > 50)
{
transferFocus();
}
lastTime = evt.getWhen();
}
});
}
}

JDialog created before Thread.sleep() shows after sleep is finished

I just encountered a problem when trying to add an imprint to a swing application which is shown for five seconds when the application is closed.
I had planned to open a JDialog just containing a simple image when the main frame is closed.
I got a function showing the JDialog (I removed everything which is not necessary).
public static void show() {
JDialog d = new JDialog();
JLabel l = new JLabel(new ImageIcon(MainController.class.getClass().getResource("/path/to/endlogo.png")));
d.add(l);
d.setVisible(true);
}
The function is called by the following snippet (in the window listener of my main window)
#Override
public void windowClosing(WindowEvent e) {
show();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The problem is that the dialog is shown AFTER the five seconds (which is when the windows is already closed and the application exited, I tested it and it showed up perfectly after five seconds when run on application start).
Do you guys know a way to achieve it the other way round?
You're blocking the UI thread. Don't do that, basically... use a swing timer or something similar if you want to do something on the UI thread at a later time.
Golden rules:
Don't do anything time consuming on the UI thread
Only access the UI on the UI thread

Program displays filenames in a JTextArea as it walks the directory tree but I don't know how to stop it via a keypress

There are two windows: a GUI for user input and Output window for list of filenames found. Execution must be user-stoppable via a keypress and must leave both windows open because the program processes subdirectories, so it can run a long time, possibly stepping thru 100_000 files, either producing tons of output or none at all, depending on how user's filename pattern matches files encountered in the selected starting node.
Here's my question:
How do I look for a keypress (e.g., ESC or CTRL-C) to allow user to terminate? (Clicking red X isn't an option since that closes windows; user needs to see what's been found before termination. Doing so does not close either window anyway since all buttons are disabled once tree walk begins.)
I've tried putting keyListeners in several places, but once the "Start" button is clicked, all the swing components are disabled.
This seems like such a common situation that I'm surprised I can't find any textbook, thread, or Google info that directly answers the question. So I'm afraid it's not gonna be at all easy. That would be no surprise. I may have found a clue here but I can't get it to compile and the link contained there doesn't lead to that code snippet.
The search begins when the Search button is clicked:
private void jbSearchActionPerformed(ActionEvent evt) {
SearchyGUI.doIt();
}
The doIt() method walks the directory tree by an extension of SimplefileVisitor:
public class OverriddenFileVisitor extends SimpleFileVisitor<Path> {
...
}
public static void doIt(){
try {
visitor = new OverriddenFileVisitor();
info.setVisible(true);
Files.walkFileTree(SearchyGUI.p , visitor);
}
catch (Exception e) { }
}
}
Output is written to jTextArea1 via the report() method:
public static void report(String s){
Output.jTextArea1.append(s + "\n");
}
This is done primarily in the visitFile() method of SimpleFileVisitor:
public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException {
report(foundkt + "--" + f.getFileName().toString());
return FileVisitResult.CONTINUE;
}
Here's the main class:
public class SearchyGUI {
static Output info;
static Path p ;
static FileVisitor visitor ;
static GUI gui
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
gui = new GUI();
gui.setVisible(true);
}
});
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
info = new Output();
}
});
}
The problem is you are hogging the GUI thread, so the GUI thread can't process any events originating from the user.
You need to create a new Thread and do the work in there. Then, to display output from that thread, you can use SwingUtilities.invokeLater or something like that.
The Key Bindings API is probably the best choice for monitoring key strokes.
I would also add a [Cancel] button to the UI, which shared the same action...
public class CancelAction extends AbstractAction {
public CancelAction() {
putValue(NAME, "Cancel");
}
public void actionPerformed(ActionEvent evt) {
// Perform the cancel operation...
}
}
Then some where else in your code...
CancelAction cancelAction = new CancelAction();
JButton cancelButton = new JButton(cancelAction);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel");
am.put("Cancel", am);
Now the other problem you're going to have is the fact that you look like you are running a long running task within the context of the Event Dispatching Thread. This is going to prevent your program from being able to update the UI or allow the user to interact with the UI.
If you need to make changes to the UI (ie, show the output of the file processing), you should try a SwingWorker.
The main reason being is that it allows you to execute the long running task in another thread, but provides the mechanism for re-syncing updates back to the EDT, where it is safe to make changes to the UI.
Take a look at Concurrency in Swing for more details.
Regardless of which direction you take, you're going to need to supply a reference to the object that is carrying out the task and provide some kind of "cancel" flag, which the "task" object will need to monitor
The way I had left this program last night was unsatisfactory since Exit resulted in user not being able to see the output so far displayed (it could be useful). So I established window listeners and used the close event to set a boolean aborted to true to prevent further output to the window, but the thread kept running, which led to intermittent problems if another search was started before the thread ended.
Here's how I fixed it.
The FileVisitor interface has 4 methods to implement to walk the tree--two for each file visited, two for each directory. Each returns a FileVisitResult which is normally FileVisitResult.CONTINUE. By changing the return value to FileVisitResult.TERMINATE in the file visitor thread, it terminates appropriately! That is, I set a flag that the thread could check and take appropriate action, which is exactly what #MadProgrammer suggested.
public static FileVisitResult disposition = FileVisitResult.CONTINUE;
...
private static void report(String s){
if (! aborted)
try{
Output.jTextArea1.append(s + "\n");
}
catch (Exception e){
aborted = true ;
disposition = FileVisitResult.TERMINATE;
}
}
...
#Override
public FileVisitResult visitFile(Path f, BasicFileAttributes a) throws IOException {
f1 = new File(f.getParent().toString() + "\\" + f.getFileName().toString());
long filesize = f1.length();
report(f.getFileName().toString() + "\t found in " + f.getParent().toString());
return disposition;
}
I am one happy camper! Thank you BOTH for your ideas and input.
Well, I made it stop. I guess if you wander the woods long enough you'll find a gnome. I read Robin's hint last week and sort of gave up. Then I read some more and more. And then more. But Robin assured me that gnomes DO exist in these here woods!
The code I used was a modification of some I found for a MatLab/Java app. (Why'd I even look at it?? Best apparent Google hint.)
I made the "file visitor" (directory tree walker component) startable as a thread as Robin advised:
public class OverriddenFileVisitor extends SimpleFileVisitor<Path> implements Runnable{
// ................................................................^^^^^^^^^^^^^^^^^^^
In doIt() I made a couple of changes, moving the lines that process the directory to the now-runnable class and started the file visitor as its own thread in doIt():
public static void doIt(){
try {
new OverriddenFileVisitor().startTh();
//^^^^^^^^^^
//(moved) Files.walkFileTree(SearchyGUI.p , visitor);
...
I added the new method in the previous line to OverriddenFileVisitor class: (This is the main part of the MatLab/Java code that made sense to me so I used and modified it.)
public void startTh() {
Thread t = new Thread(this);
t.start();
}
And I inserted the overridden run() method for the class:
public void run() {
try {
Files.walkFileTree(SearchyGUI.p , this); // Used to be in doIt().
}
catch (IOException ex) { }
}
It ran and gave correct results and stopped when I hit Exit button, which "became" enabled after revising the file visitor to run in its own thread, which is what #Robin Green was saying. I almost feel like I know what I've done.
P.S. Note that I already was able to get my output via invokeLater()--last several lines of original question.
It's not finished but it's much more satisfactory.

Setting text on jLabel using setText is delayed

I was building a small test tool with Java Swing using Netbeans IDE.
I am trying to update a label, which is somehow not getting 'repainted'/'refreshed'. I looked into a couple of similar questions on SO but was not able to resolve my problem.
private void excelFileChooserActionPerformed(java.awt.event.ActionEvent evt)
{
if(!JFileChooser.CANCEL_SELECTION.equals(evt.getActionCommand()))
{
String selectedFile = excelFileChooser.getSelectedFile().getAbsolutePath();
loaderLabel.setText("Please Wait..");
try {
//This is sort of a blocking call, i.e. DB calls will be made (in the same thread. It takes about 2-3 seconds)
processFile(selectedFile);
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
catch(Exception e) {
System.out.println(e.getMessage());
loaderLabel.setText("Failed..");
}
}
}
loaderLabel is a JLabel and the layout used is AbsoluteLayout.
So, my problem is "Please Wait..." is never shown. Although call to the method processFile takes about 2-3 seconds, "Please Wait..." is never shown. However, "Done..."/"Failed..." are shown.
If I add a popup (JOptionPane) before the call to processFile, "Please Wait.." is shown. I am not able to clearly understand why this is happening.
Is there a "good practice" that I should follow before a heavy method call? Do I need to call an explicit repaint/refresh/revalidate?
You need to call
processFile(selectedFile);
in another thread (not in the AWT thread). To do so you can do something like this :
Thread t = new Thread(){
public void run(){
processFile(selectedFile);
// now you need to refresh the UI... it must be done in the UI thread
// to do so use "SwingUtilities.invokeLater"
SwingUtilities.invokeLater(new Runnable(){
public void run(){
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
}
)
}
};
t.start();
Please not that I didn't work with swing for a long time, so there may be some syntax issues with this code.
Have you tried dispatching the call to the EDT with SwingUtilities.invokeLater() ?
http://www.javamex.com/tutorials/threads/invokelater.shtml

Categories