Currently I have a live active while loop running and it does what I want my only problem is closing the frame (exit the app) while the while loop is still active.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I tried using the if statement to terminate the loop
if (frame.getDefaultCloseOperation() == 3){
running = false;
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
Unfortunately as soon as the app runs automatically gets set to 3 emmidiately and there for this process does not work.
How can I set running = false; by clicking on the frame to be closed.
I want to simply close the app by just clicking on X in the connour, is that possible when having a active loop running?
There are several ways to achieve what you want.
Run the loop in a daemon thread. Such a thread won't stop the application from stopping. Just be careful when you call swing code from such a thread.
This question explains how to show a confirm dialog when the user tries to close the window: Java - Message when closing JFrame Window
Instead of the dialog, just put running = false; in there.
Note: If you run your loop in the Swing thread, then Swing can't respond to the event. Use solution #1 in this case.
just set frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); in your declaration it will close the loop automatically
You are setting the default close operation.
however in your code this
if (frame.getDefaultCloseOperation() == 3){
only checks if the close operation is still set to JFrame.EXIT_ON_CLOSE
what you want is to respond to the close event.
I suspect you need this answer
when you set up your frame, add some code to the initialization block
addWindowListener(this);
and then implement the onclosing window listener int he same class:
public void windowClosing(WindowEvent event) {
running = false;
}
remove frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);, add windows listener and close application manually.
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
running = false;
}
#Override
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
Related
We have an javafx application developed mainly in java 1.7 and tested in 1.8. It was running fine until java 1.8u35. Now we discovered, JavaFx windows are not going to open in 1.8u40 after upgrade. Even worse, the modal windows are blocking the entire tab/ browser of being used. So the user is just able to close the browser using the task manager.
We use javafx.embed.swing.JFXPanel to embed jfx-code into swing legacy code.
I have completely no clue what might be the problem, as there are no errors displayed in client's java console.
UPDATE:
I reviewed the known issues list for java1.8 here. The only thing I would probably link to our issue is this bug:
BUG-RT-32597: The SwingNode class does not support High DPI displays.
So I tried lowering the screen resolution (1280x1024 to 800x600) but without success.
Does anyone faced a similar issue before and knows what might help?
UPDATE:
I tried to better track down the problem but with not much luck.
To make it more visible, this is basically whats going on on window loading:
public static void initWindow(JDialog dialog){
final JFXPanel jfx = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
System.out.println("JFXPanel");
}
});
Runnable r = new Runnable() {
public void run() {
AnchorPane root = new AnchorPane;
//... do some content loading
Scene scene = new Scene(root,width,height);
System.out.println("test");
}
};
dialog.add(jfx);
System.out.println("added jfx panel.");
dialog.pack();
System.out.println("packed jfx panel.");
dialog.setLocationRelativeTo(null);
System.out.println("loaded.");
}
I thought execution is going to stop somewhere, but its running through the entire function as usual. Nevertheless the window is not showing up.
UPDATE:
Not completely correct, my last comment, as I found out:
Around the above function, the following happens:
initWindow(this); //this is extending java.swing.JDialog
System.out.println("this comment is printed to console");
super.setVisible(true); //this is not executed properly. if removed, browser will not be blocked, but window doesnt show up either
System.out.println("this comment is not printed to console";
So, in general, there is the JDialog which gets packed with a JfxPanel. When calling setVisible() method from the JDialog class, the Application gets blocked but the window doesnt show up. Actually, in the thumbnail screen (alt+tab) it is shown as a container inside the application.
When removing the setVisible call, the browser does not get blocked, but also the window does not show up. Unfortunately, I did not find the JDialog class code to look up, what's going on inside setVisible().
Any ideas, what might be wrong with our setup or the setVisible method?
We had a similar problem. While comparing the Java sources of 1.8.0_31 and 1.8.0_45 we found out that there were some changes in the JFXPanel source code introduced with 1.8.0_45 that may cause problems in the following situation:
initialize modal JDialog with JFXPanel (executed on Swing's EDT)
initialize and set FX scene on JFXPanel in FX task (executed on FX Thread)
wait for FX task to be finished (wait on EDT)
pack() and show() JDialog (continued on EDT, blocks program execution)
continue with program execution after user closed JDialog (on EDT)
We use this workflow in order to wait for some user input being shown in a new modal JDialog and continue normal programm execution on EDT afterwards.
In 1.8.0_31, the preferred size of JFXPanel seems to be set in FX thread which allows JDialog.pack() to determine the correct bounds.
In 1.8.0_45, the preferred size of JFXPanel seems to be set not in FX thread anymore but in EDT after all pending AWT events are executed. So, when (4) is executed, JDialog.pack() does not know about the preferred size of the scene. As a consequence, the dialog has no content, or does not show up if undecorated as described in the original question above.
Here is a complete example to reproduce the different behaviour:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// create JDialog on EDT
final JDialog dialog = new JDialog((JDialog)null, "JDialog");
// initialize FX platform and create JFXPanel
final JFXPanel jfxPanel = new JFXPanel();
// add resize listener for JFXPanel
jfxPanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// not called in 1.8.0_45
System.out.println("JFXPanel.getSize(): "+jfxPanel.getSize());
}
});
// set FX Scene on JFXPanel and wait until finished
runAndWait(new Runnable() {
public void run() {
Text text = TextBuilder.create().text("JavaFx content").y(20).build();
Group root = new Group(text);
Scene scene = new Scene(root);
jfxPanel.setScene(scene);
}
});
// show undecorated modal JDialog with FX content
System.out.println("JFXPanel.getPreferredSize(): "+jfxPanel.getPreferredSize());
dialog.setUndecorated(true);
dialog.add(jfxPanel);
dialog.pack();
dialog.setModal(true);
System.out.println("JDialog.setVisible()");
dialog.setVisible(true);
}
});
}
private static void runAndWait(Runnable r) {
try {
FutureTask<Object> task = new FutureTask<Object>(r, null);
Platform.runLater(task);
task.get();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
When running this program, componentResized() is called only in 1.8.0_31 but not in 1.8.0_45.
A possible fix while keeping the synchronous program workflow on EDT is to replace JDialog.pack() with JDialog.setSize(...), e. g. by setting a constant size or by using the size of the FX scene that could be determined using root.getBoundsInLocal().
I encountered the same behaviour described by #Peter using 1.8.0_121.
I was able to get dialog.pack() to work using a window listener.
dialog.addWindowListener( new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
((JDialog)e.getSource()).pack();
}
});
I am trying to find out an elegant way to make JTable stop cell editing (cancel it actually) when user closes the main application window. I know something like this can be done using the WindowAdapter but for this to work properly I need a reference to the window. Problem is I sometimes do not have it.
An abrupt exit may need to be handled at several levels.
Assuming that the user must navigate out of the table to click on an Exit control, you should get the desired result by setting the table's "terminateEditOnFocusLost" property.
table.putClientProperty("terminateEditOnFocusLost", true);
If you have to resort to a WindowListener or similar, you can stop editing explicitly as shown here.
CellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
if (cellEditor.getCellEditorValue() != null) {
cellEditor.stopCellEditing();
} else {
cellEditor.cancelCellEditing();
}
}
Because the host owns the frame decorations, some platforms require special handling to intercept the close control, as discussed here.
Preferences makes a best effort to persist updated values.
So far, this is the solution I am most satisfied with:
All my JTable objects install themselves as HierarchyListener(s) with the following method to handle the HierarchyEvent:
public void hierarchyChanged(HierarchyEvent e) {
Window win = SwingUtilities.getWindowAncestor(this);
if ((win != null) && (!win.equals(topLevelWindow))) {
topLevelWindow = win;
topLevelWindow.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
handleWindowClosing();
}
});
}
}
private void handleWindowClosing() {
if (table.isEditing()) {
table.getCellEditor().cancelCellEditing();
}
}
In the case of the project I work on, cancelling the editing when the application window closes is crucial because it sends the notification that the record is no longer in the editing state...
Using hierarchy listener is also crucial because my JTable objects move from dockable to dockable (we use the excellent Docking Frames here) and can be in different windows at different times.
There is a java swing application that I need to automate one of the functions of. It's quite simple - the user clicks a button in the swing application and starts an action.
I made a small java application that includes the java swing application as a .jar and calls the action behind the button (read).
The problem is - in case of an exception, the swing .jar shows JOptionPane, which halts the automated execution. Is it possible to somehow override this behavior without altering the original jar?
Application structure:
Main.java
import com.swingapp.ui
public static void main(String[] args){
Swingapp.read();
}
Then the read() function in the Swingapp library:
public void read(){
try{
//do a bunch of stuff...
} catch (Exception ex){
JOptionPane.showMessageDialog(null, ex.getMessage()); // In case of an exception, the swing application will show a message dialog. This halts the automated execution of my java task, I'd like to just skip this
}
When exception happens in above application, user is expected to click "OK". But running this as automated task, nobody there to click okay
Since a JOptionPane gains focus as soon as it opens (I think the most right button gets the focus, but it does not matter in your case) you can do the following:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent arg0) {
Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
while(c != null) {
if (c instanceof JOptionPane) {
try {
new Robot().keyPress(KeyEvent.VK_ENTER);
} catch (AWTException e) {
e.printStackTrace();
break;
}
}
c = c.getParent();
}
}
}, AWTEvent.FOCUS_EVENT_MASK);
It will traverse up to see if anything in the current hierarchy is an instance of JOptionPane. If so -> simulate that the user pressed Enter (Return) which will close the dialog even if the focus is in an input field.
I have following solution for you. You need to registrate a listener to monitor all window events. Use Toolkit.getDefaultToolkit().addAWTEventListener(). If you get a window opened event, try to check whether the window is a JDialog and whether the dialog's contentPane contains an instance of JOptionPane. If yes you need traverse the component tree, find the first button and click it.
I want my program to run but once esc is pressed to quit the program. The only way I can think of doing this is by doing a scanner and looking for the next line but that pauses the whole program. Maybe a key listener but how do I make it be constantly checking? And it is a GUI. Any help would be great!
static Scanner sc = new Scanner(System.in);
stop = sc.nextLine();
if (stop.equals(a)){
running = false;
}
else{
do program
}
If u use a frame you can register the keys.
myFrame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "EXIT");
myFrame.getRootPane().getActionMap().put("EXIT", new AbstractAction(){
public void actionPerformed(ActionEvent e)
{
myFrame.dispose();
}
});
If this is a UI, you should not be maintaining any kind of loop that could block the Event Dispatching Thread.
The EDT will dispatch key events to your program and you can respond to them if you have registered for notifications.
I would avoid KeyListener as it requires the component it is registered to be focused and have keyboard focus before it will respond.
Instead, I would use the Key Bindings API.
You can register a Escape key to either the main application window (or sub component) or directly with the JButton you are using to close the application with.
How do you close a java application from the code?
You call System.exit:
System.exit(0);
I believe that by most standards, System.exit() is a not very OOP way of closing applications, I've always been told that the proper way is to return from main. This is somewhat a bit of a pain and requires a good design but I do believe its the "proper" way to exit
If you're terminating a Swing app, I would do an EXIT_ON_CLOSE
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
before System.exit(0). This is better since you can write a Window Listener to make some cleaning operations before actually leaving the app.
That window listener allows you to exit the app from the code:
public void windowClosing(WindowEvent e) {
displayMessage("WindowListener method called: windowClosing.");
//A pause so user can see the message before
//the window actually closes.
ActionListener task = new ActionListener() {
boolean alreadyDisposed = false;
public void actionPerformed(ActionEvent e) {
if (frame.isDisplayable()) {
alreadyDisposed = true;
frame.dispose();
}
}
};
Timer timer = new Timer(500, task); //fire every half second
timer.setInitialDelay(2000); //first delay 2 seconds
timer.setRepeats(false);
timer.start();
}
public void windowClosed(WindowEvent e) {
//This will only be seen on standard output.
displayMessage("WindowListener method called: windowClosed.");
}
If you're running an application, System.exit will work.
System.exit(int);
In an applet, however, you'll have to do something along the lines of applet.getAppletContext().showDocument("landingpage.html"); because of browser permissions. It won't just let you close the browser window.
You use System.exit(int), where a value of 0 means the application closed successfully and any other value typically means something was wrong. Usually you just see a return value of 1 along with a message printed to sysout or syserr if the application did not close successfully.
Everything is fine, application shut down correctly:
System.exit(0)
Something went wrong, application did not shut down correctly:
System.err.println("some meaningful message"); System.exit(1)