Java Swing - Close JDialog from external Thread - java

I am working with Swing right now and I do not get this to work properly.
What I need is the following:
I've got a class "Client" that is able to connect to a TCP server.
If the connection fails (wrong IP for example), then it will show an error dialog that can be closed by clicking on the "OK" Button.
However if the client connected successfully, a window should popup that runs until my client receives a specific message from the server.
My code looks like this:
if(ip != null) {
Client c = new Client();
try{
c.connect(ip, 56556);
JOptionPane msg = new JOptionPane("Connecting...", JOptionPane.INFORMATION_MESSAGE);
JDialog dlg = msg.createDialog("Connecting...");
dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dlg.setVisible(true);
c.addIncomingMessageHandler(new IncomingMessageHandler(){
#Override
public void incomingMessage(Connection<?> cnctn, Object o) {
dlg.setVisible(false);
dlg.dispose();
}
});
}catch(Exception e) {
int n = JOptionPane.showOptionDialog(this, "Oops! Something went wrong!",
"Title", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE,
null, new Object[] {"OK"}, JOptionPane.OK_OPTION);
}
}
So the exception is throws if c.connect() fails.
c.addIncomingMessageHandler() is a listener that listens to any incoming messages to the client. If the server sends something, this method will be called. If that's the case, the JDialog will be closed. But this window can be closed right now by clicking on the OK-Button.
I'd like to rename that button and add a function.
The new text should be "Cancel" and if the button is pressed, the client should be closed (c.disconnect) and the window itself should be closed as well.
How could I do that?

From the Documentation:
Stopping Automatic Dialog Closing
By default, when the user clicks a JOptionPane-created button, the dialog closes. But what if you want to check the user's answer before closing the dialog? In this case, you must implement your own property change listener so that when the user clicks a button, the dialog does not automatically close.
DialogDemo contains two dialogs that implement a property change listener. One of these dialogs is a custom modal dialog, implemented in CustomDialog, that uses JOptionPane both to get the standard icon and to get layout assistance. The other dialog, whose code is below, uses a standard Yes/No JOptionPane. Though this dialog is rather useless as written, its code is simple enough that you can use it as a template for more complex dialogs.
Besides setting the property change listener, the following code also calls the JDialog's setDefaultCloseOperation method and implements a window listener that handles the window close attempt properly. If you do not care to be notified when the user closes the window explicitly, then ignore the bold code.
final JOptionPane optionPane = new JOptionPane(
"The only way to close this dialog is by\n"
+ "pressing one of the following buttons.\n"
+ "Do you understand?",
JOptionPane.QUESTION_MESSAGE,
JOptionPane.YES_NO_OPTION);
final JDialog dialog = new JDialog(frame,
"Click a button",
true);
dialog.setContentPane(optionPane);
dialog.setDefaultCloseOperation(
JDialog.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
setLabel("Thwarted user attempt to close window.");
}
});
optionPane.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (dialog.isVisible()
&& (e.getSource() == optionPane)
&& (prop.equals(JOptionPane.VALUE_PROPERTY))) {
//If you were going to check something
//before closing the window, you'd do
//it here.
dialog.setVisible(false);
}
}
});
dialog.pack();
dialog.setVisible(true);
int value = ((Integer)optionPane.getValue()).intValue();
if (value == JOptionPane.YES_OPTION) {
setLabel("Good.");
} else if (value == JOptionPane.NO_OPTION) {
setLabel("Try using the window decorations "
+ "to close the non-auto-closing dialog. "
+ "You can't!");
}
Click here!
Related question.

Related

How to prevent JOptionPane.showConfirmDialog box from closing

I'm showing a ConfirmDialog with some input fields. When save fails (validation fails) I want to show a MessageDialog box but I don't want the ConfirmDialog box to disappear. How do I do this?
Below is my actionPerformed method to open the ConfirmDialog (when I click a button with this method as it's event handler)
#Override
public void actionPerformed(ActionEvent e) {
int result = JOptionPane.showConfirmDialog(null, panel, "New transaction",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
// save transaction
Transaction transaction = new Transaction();
// ...
if (transaction.save()) {
// close the ConfirmDialog is OK, save was successful
} else {
// don't close the ConfirmDialog, save failed
JOptionPane.showMessageDialog(panel, "Please fix the errors");
}
}
}
You can't use the static methods of the JOptionPane class to create the dialog.
You need to create your own dialog and then use the JOptionPane as the contentPane of your dialog.
Read the section from the Swing tutorial on Stopping Automatic Dialog Closing for example code on how this can be done.

Application not responding to Touch-Events after showing custom dialog

like the title implies i've got a problem with my application. The application is supposed to run in fullscreen mode (no intention for switching back to window mode), so i designed a footer-bar holding some images (with a Label, in a VBox) so the user could navigate or exit the program.
So after starting the application all Buttons work just fine with touch. Even the Exit-button in my footer-bar responded correctly by opening my custom Dialog. But here starts my Problem. The Dialog is shown by showAndWait()-Method call, but does not respond to Touch-Events. In contrary mouse-events are still processed (i still can use a mouse to click the Buttons in my Dialog and the Dialog is responding correctly).
I hope someone got an idea what i'm doing wrong.
MyDialog.java:
public static boolean showExitDialog(Window owner, ResourceBundle resources) {
LOGGER.info("Showing exit dialog...");
final Dialog<ButtonType> dialog = new Dialog<ButtonType>();
dialog.getDialogPane().getStylesheets().add(MyDialog.getInstace().getCssPath());
dialog.setContentText(resources.getString("label.exitdialog.text"));
dialog.setHeaderText(resources.getString("label.exitdialog.header"));
dialog.initOwner(owner);
dialog.initStyle(StageStyle.TRANSPARENT);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.getDialogPane().getButtonTypes().add(new ButtonType(resources.getString("btn.Exitdialog.exit"), ButtonData.OK_DONE););
dialog.getDialogPane().getButtonTypes().add(new ButtonType(resources.getString("btn.Exitdialog.cancel"), ButtonData.FINISH));
Optional<ButtonType> result = dialog.showAndWait();
LOGGER.debug("Result: {}", result.get());
if(result.isPresent() && result.get().getButtonData() == ButtonData.OK_DONE) {
LOGGER.info("Closing exit dialog returning true...");
return true;
} else {
LOGGER.info("Closing exit dialog returning false...");
return false;
}
}
In MainApp.java:
private EventHandler<WindowEvent> confirmCloseEventHandler = event -> {
// close event handling logic.
// consume the event if you wish to cancel the close operation.
if(MyDialog.showExitDialog(primaryStage, rb)) {
event.consume();
System.exit(0);
}
};
...
primaryStage.setOnCloseRequest(confirmCloseEventHandler);
In FooterBar.java:
#FXML
private void exitProgramPressedTouch(TouchEvent event) {
event.consume();
controller.getWindow().fireEvent(new WindowEvent(controller.getWindow(), WindowEvent.WINDOW_CLOSE_REQUEST));
}
*Edit* Oh totally forgot: No Exception or anything else is thrown.
I don't know the reason for the described behavior - maybe a bug. However, you could try to listen for ActionEvent instead of TouchEvent. It handles both touch and mouse events:
#FXML
private void exitProgramPressedTouch(ActionEvent event) {
event.consume();
controller.getWindow().fireEvent(new WindowEvent(controller.getWindow(), WindowEvent.WINDOW_CLOSE_REQUEST));
}
Maybe you need also to change the attribute which binds the event listener (from onTouch to onAction) in your FXML file.
Finally, I think, you could avoid System.exit(0); if you consume the close event only when the cancel button has been clicked:
if(!MyDialog.showExitDialog(primaryStage)) {
event.consume();
}

Close custom dialog when Enter is pressed in input field

I've designed (using the GUI designer within Netbeans) a small dialog with two radio buttons and a number spinner.
If I press Enter while the focus is on one of the radio buttons, the dialog correctly closes, but if the focus is on the spinner, I have to Tab away from it in order to use the Enter key.
How do I instruct the dialog that Enter really means "accept and close"?
Alternatively, how do I instruct (each) input field to relay an Enter to the "accept and close" handler?
Similarly, how do I instruct the dialog that Esc really means "cancel and close" even when the focus is on the spinner (or other field)?
how do I instruct (each) input field to relay an Enter to the "accept and close" handler?
The easiest approach is to define a "default button" on the dialog. Then when Enter is pressed the default button will be activated. Check out Enter Key and Button for different ways to do this.
how do I instruct the dialog that Esc really means "cancel and close"
Use Key Bindings to invoke the Action of your Cancel button.
First you define an Action to be used by the button:
public class CancelAction extends AbstractAction
{
public CancelAction()
{
super("Cancel");
putValue( Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_C) );
}
#Override
public void actionPerformed(ActionEvent e)
{
Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
if (window != null)
{
WindowEvent windowClosing = new WindowEvent(window, WindowEvent.WINDOW_CLOSING);
window.dispatchEvent(windowClosing);
}
}
}
Then you add the Action to the button so the user can use the mouse:
CancelAction cancelAction = new CancelAction();
cancelButton.setAction( cancelAction );
dialog.add(cancelButton);
Now you can use Key Bindings to bind the Escape key to the CancelAction so the user can use the keyboard:
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
getRootPane().getActionMap().put("ESCAPE", cancelAction);
I suspect the reason I had problems is that a spinner is really a compound control, and the text (well, number) field is an component of that. So I needed to hook up the events to that subcomponent, rather than to the spinner itself:
// Make Ok/Cancel work when JSpinner has focus
getSpinnerField(jSpinnerOffset).addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
doOk();
}
});
where "getSpinnerField()" is just a shorthand in a private method:
private JFormattedTextField getSpinnerField(JSpinner spinner) {
return ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
}
Doing this, the Esc key automagically becomes able to dismiss the dialog.

JavaFX Alert Dialog Cancel Button

I made a JavaFX alert dialog box to prompt the user, asking if they want to save the output from the console before closing the application.
I have the yes and no options taken care of. If the user clicks cancel, I want it to just close the dialog box and leave everything open. As of right now, if I hit cancel it will close the GUI.
Here is my code for overriding the close button on the GUI.
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>()
{
#Override
public void handle(WindowEvent event)
{
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Warning");
alert.setHeaderText("Would You Like To Save Your Console Output?");
alert.setContentText("Please choose an option.");
ButtonType yesButton = new ButtonType("Yes");
ButtonType noButton = new ButtonType("No");
ButtonType cancelButton = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(yesButton, noButton, cancelButton);
Optional<ButtonType> result = alert.showAndWait();
if(result.get() == yesButton)
{
Main.setConsoleVisible();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
else if(result.get() == noButton)
{
System.exit(0);
}
else if(result.get() == cancelButton)
{
}
}
});
Both in "yesButton" and "cancelButton" if-blocks consume the CloseRequest WindowEvent:
else if(result.get() == cancelButton)
{
event.consume();
}
Use Platform.exit() instead of System.exit(0).
Use primaryStage.close(); instead of System.exit(0);
From the documentation for onCloseRequest:
Called when there is an external request to close this Window. The installed event handler can prevent window closing by consuming the received event.
Be aware that result.get() will throw an exception if the user closes the alert dialog without pressing any buttons. The Dialog documentation explains this thoroughly.

Java - Message when closing JFrame Window

I have a Java Program containing a class Application inheriting from JFrame.
I want to display a message which asks the user if he wants to exit the program upon clicking the X button at the top right of the window.
This is my code so far:
I got this code from a tutorial I found online. I coded the WindowClosing event handler myself. However, I have trouble registering the window listener (addWindowListener). It is telling me that WindowAdapter is abstract and cannot be instantiated.
How can I solve this problem please?
Basically, you got it almost correct. There are a few things not put together correctly and a typo.
First remove your WindowClosing method (it's window, not Window)
Then replace your addWindowListener(new WindowAdapter()); with the code below
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
int confirmed = JOptionPane.showConfirmDialog(null,
"Are you sure you want to exit the program?", "Exit Program Message Box",
JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) {
dispose();
}
}
});
i got this in two minutes coding....
First is set the j frame default closing event in Exit_on_close. Second create a class called "Window Closing Event Handler" and then call it in the i nit stage.
private void WindowClosingEventHandler(){ addWindowListener(new WindowAdapter() { #Override public void windowClosing(WindowEvent e) { int confirmed = JOptionPane.showConfirmDialog(null, "Are you sure you want to exit this application?", "Exit Program Message Box",JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) {
try{
String login=txtuserid.getText();
Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/repair", "root", "");
Statement st = conn.createStatement();
String update = "UPDATE user set User_Status=0 where UserID='"+ login +"'";
st.executeUpdate(update);
dispose();
Login2 dialog = new Login2(new javax.swing.JFrame(), true);
dialog.setVisible(true);
}catch(SQLException | HeadlessException q){
JOptionPane.showMessageDialog(null, q);
}
System.exit(0);
}
else{
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
}
}
});
}
Ok trying again.
You cannot create a new WindowAdapter because WindowAdapter is abstract. Abstract classes cannot be instantiated. You would need to create a subclass of WindowAdapter and implement its abstract methods as public.
http://docs.oracle.com/javase/7/docs/api/java/awt/event/WindowAdapter.html

Categories

Resources