Keeping a java application open when a user selects "Cancel"? - java

I have a very basic question.
I have the following WIndowClosing() event in java. I want to keep the application open if the user clicks "Cancel". How do I do this?
The application keeps closing when "Cancel" is selected.
This is what I have:
public void windowClosing(WindowEvent evt)
{
SAVE_MODE event = m_model.saveChanges();
if(event == SAVE_MODE.YES)
{
saveChanges();
System.exit(0);
}
else if(event == Common.SAVE_MODE.NO)
{
System.exit(0);
}
else
{
//Keep the application open -- how do I say that in code?
}
}
Note the following:
The application still closes when the ELSE clause is empty. I don't think that should be happening.
This should have taken me two minutes to solve. Any help would be appreciated. Thanks.

(if you want to credit me with the correct answer)
make sure you're calling [yourJFrame].setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

I think probably a different approach is all that's needed. Set your default close operation for the main frame (during your initial setup) to:
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
Then add your windowClosing code to exit on OK, and do nothing on Cancel.
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent evt) {
SAVE_MODE event = m_model.saveChanges();
switch (event)
{
case YES:
saveChanges();
System.exit(0);
break;
case NO:
System.exit(0);
break;
default:
break;
}
}
});

Related

Handling exit button which is create automatically?

I am building a text editor and I don't know how to handle a listener on Swing exit button, which is create automatically.
I want to use dialogs when user doesn't save file, for example press exit button.
final JFrame f = new JFrame("Good Location & Size");
// make sure the exit operation is correct.
f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
f.addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent we) {
// pop the dialog here, and if the user agrees..
System.exit(0);
}
});
As seen in this answer to Best practice for setting JFrame locations, which serializes the frame location & size before exiting.
Assuming you have a handle on your window, assuming it's a Window object (e.g. a JFrame or other kind of window), you can listen to WindowEvent events. Here is an example with windowClosed, you can replace it with windowClosing if you need to intercept it before.
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
// do something here
}
});
Go stepwise:
Declare a boolean variable saved and set its default value to false.
When user saves the file, change it to true
When exit button is pressed, check the variable.
If true, exit, else, prompt user for saving file.
So, finally this code snippet looks like:
public boolean saved = false;
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saved = true;
//Code to save file
}
});
exitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(saved)
System.exit(0);
else {
//Code to prompt user to save file
}
}
});

JToggleButton addItemListener seems to repeat the ItemListener forever

I'm programming a JToggleButton to load to/discard from memory the configuration of an element (a telescope config), so I've added a JComboBox in a JFrame and near it the button to load the selected item. When the JToggleButton is selected, an hard disk icon is displayed, another icon if otherwise. I'm using the IntelliJ IDEA GUI editor for that. Of course, I've added an ItemListener (as suggested from the web) to that button:
loadTelescopeButton.setSelected(true);
System.out.println(loadTelescopeButton.isSelected());
loadTelescopeButton.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
System.out.println("LAODACTION " + loadTelescopeButton.isSelected());
try {
if (e.getStateChange() == ItemEvent.SELECTED) {
String selected = telescopesList.getSelectedItem().toString();
if ((selected != null) && (!selected.equals("")) && (ObjUtils.isAlphaNumeric(selected))) {
//...
} else {
showErrorMessage("Invalid id selected!");
}
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
if ((configurationActivity != null) && (configurationActivity.getManager() != null) &&
(configurationActivity.getTelescope() != null) && (configurationActivity.getTelescope().isConnected())) {
//...
} else {
//...
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
Output:
true
-> When the window is displayed
LAOD_ACTION false
-> When I click the button
I've made some tests with some new toggle buttons and they gave me same error: the code inside itemStateChanged(ItemEvent e) {...} is repeated forever, without stopping! In that piece of code there are no for and while loops! The result is a great number of message dialogs (only one dialog should be displayed), and if I focus another window in my desktop the screen behind the dialogs becomes black (the area of the parent window). I changed the listener to ActionListener and now everything is executed one time/click.
Why this error? I've copied that code from https://stackoverflow.com/a/7524627/6267019, as you can see.
Full code on GitHub Here, I've highlighted the code for that toggle button. The same error happens with other JToggleButtons in my MainActivity.java file, and also when debugging IntelliJ lets me see that the code in the listener is repeated forever. After some thousand of dialogs Windows shows me a message and closes Java Platform Binary with an error.
EDIT:
The same problem in a new class:
import javax.swing.*;
import java.awt.*;
public class ErrorGUI extends JFrame {
public ErrorGUI() throws HeadlessException {
super("ciao");
JPanel panel1 = new JPanel();
setContentPane(panel1);
JToggleButton ciaoToggleButton = new JToggleButton("cajs");
ciaoToggleButton.setSelected(true);
ciaoToggleButton.addItemListener(e -> {
System.out.println("caiooasfsdvn");
try {
JOptionPane.showMessageDialog(panel1, "skjngksfnb");
} catch (Exception e2) {
e2.printStackTrace();
}
});
panel1.add(ciaoToggleButton);
pack();
setVisible(true);
}
public static void main(String[] args) {
new ErrorGUI();
}
}
Whenever you open a modal dialog, the opening method call will return only after the dialog has been closed. This is crucial for the dialogs that return an entered value or choice.
This implies that while the dialog is open, a new event handling loop has to be started to react on the input in the dialog.
So when you open a modal dialog from a listener, you are stopping the handling of the current event and start processing of subsequent events, which can disturb the handling of the current event significantly. Most notably, the button will suddenly loose the focus when the new dialog is opened.
The nested event handling can be easily demonstrated by changing the listener to
ciaoToggleButton.addItemListener(e -> {
System.out.println("entering");
JOptionPane.showMessageDialog(panel1,
e.getStateChange()==ItemEvent.SELECTED? "selected": "deselected");
System.out.println("leaving");
});
which will print sequences of
entering
entering
leaving
leaving
showing how the contradicting event is generated while the processing of the old one hasn’t completed.
As said by others, you can fix this by opening the dialog after the completion of the even handling, like
ciaoToggleButton.addItemListener(e -> {
System.out.println("entering");
EventQueue.invokeLater(() -> JOptionPane.showMessageDialog(panel1,
e.getStateChange()==ItemEvent.SELECTED? "selected": "deselected"));
System.out.println("leaving");
});
or you enforce a non-modal dialog:
ciaoToggleButton.addItemListener(e -> {
System.out.println("entering");
JDialog d = new JOptionPane(
e.getStateChange()==ItemEvent.SELECTED? "selected": "deselected",
JOptionPane.INFORMATION_MESSAGE)
.createDialog(panel1, UIManager.getString("OptionPane.messageDialogTitle"));
d.setModal(false);
d.setVisible(true);
System.out.println("leaving");
});
(in a real application you would either keep the dialog for later reuse or call dispose after use)
Unfortunately, the danger of opening modal dialogs (or doing anything else that creates a secondary event loop) hasn’t been emphasized enough in the documentation. You can read everywhere that accessing Swing components from other threads can create inconsistencies, but starting new event handling loop while there are incompletely processed events can have a similar impact.
I can't say that I understand why your code is misbehaving, but I agree that what you're seeing doesn't quite make sense, and is likely due to the JOptionPane call somehow affecting the JToggleButton's state change. One way to get around this is by wrapping the JOptionPane call in a Runnable and queuing it on the Swing event queue via SwingUtilities.invokeLater(...). For example:
import javax.swing.*;
import java.awt.*;
#SuppressWarnings("serial")
public class ErrorGUI extends JFrame {
public ErrorGUI() throws HeadlessException {
super("ciao");
JPanel panel1 = new JPanel();
setContentPane(panel1);
JToggleButton ciaoToggleButton = new JToggleButton("cajs");
ciaoToggleButton.setSelected(true);
ciaoToggleButton.addItemListener(e -> {
System.out.println("caiooasfsdvn");
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(panel1, "skjngksfnb");
});
// JOptionPane.showMessageDialog(panel1, "skjngksfnb");
});
panel1.add(ciaoToggleButton);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new ErrorGUI();
});
}
}
An interesting variation:
ciaoToggleButton.setSelected(true);
System.out.println("0:" + ciaoToggleButton.isSelected());
ciaoToggleButton.addItemListener(e -> {
System.out.println("1: " + ciaoToggleButton.isSelected());
if (e.getStateChange() == ItemEvent.SELECTED) {
JOptionPane.showMessageDialog(panel1, "skjngksfnb");
}
System.out.println("2: " + ciaoToggleButton.isSelected());
});
prints out:
0:true
1: false
2: false
1: true
1: false
2: false
2: false
1: true
1: false
2: false
2: false

WindowAdapter to dispatch a window event (closing window)

I have created a class that extends from WindowAdapter so that every time I want to close a window, it asks you if you really want to close the window. The problem comes when I click "No". How can I handle it so that the window event doesn't "remain" there and the frame keeps trying to dispatch it?
I only do a return, and I can't come up with anything. Here's the code:
public class ExitController extends WindowAdapter{
#Override
public void windowClosing(WindowEvent windowEvent) {
if(JOptionPane.showConfirmDialog(null,"Are you sure to close this window?",
"Really Closing?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)
== JOptionPane.YES_OPTION){
System.exit(0);
} else {
return;
}
}
}
Check out Closing an Application.
It gives some basic code for this. The basic code would set the default close operation of the frame to DO_NOTHING_ON_CLOSE.
Then in the WindowListener when the user confirms the close it will reset the default close operation to EXIT_ON_CLOSE instead of using System.exit(0);
You can also use the CloseListener class which is a more complex version (because it provides more functionality) of youe ExitController class.
The problem is in JFrame.processWindowEvent:
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e); // --> this will call your listener
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
switch(defaultCloseOperation) {
case HIDE_ON_CLOSE:
setVisible(false);
break;
case DISPOSE_ON_CLOSE:
dispose();
break;
case DO_NOTHING_ON_CLOSE:
default:
break;
case EXIT_ON_CLOSE:
// This needs to match the checkExit call in
// setDefaultCloseOperation
System.exit(0);
break;
}
}
}
Independently of what your listener does, the JFrame evaluates its defaultCloseOperation and closes or hides itself.
Therefore you need also to initialize the right default close operation of the frame on which you install your listener to prevent the default operation:
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new ExitController ());
You could provide a method in ExitListenerto facilitate this:
public class ExitController extends WindowAdapter {
public void installOn(JFrame frame) {
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(this);
}

Java Swing | Key listener not responding at all

Im trying to get my KeyEvent working. Sadly the keyTyped(KeyEvent e) isnt responding at all. :)
I implemented the KeyEvnet to my class.
I assigned the listener like following:
JTextfield searchBar = new JTextField();
searchBar.addKeyListener( this );
My key event looks like this:
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
System.out.println("pressed");
try {
int browser = getSelectBrowser().getSelectedIndex();
logic.search( searchBar.getText(), searchInfo, browser, isURL );
} catch (InterruptedException ie) {
System.out.println( "Pressed fail" );
}
this.repaint();
}
}
I also tried the Listener in a second test Gui and were it also does not work.
:-)
use "keyPressed" instead of "keyTyped". keyTyped listens only on alphanumeric chars
You wont see this listener called when you press enter, so your println will never be called. Pressing enter on a JTextField will call the attached ActionListener, if there is one.
To get this working, add an ActionListener to the text field and put the code you want to run when enter is pressed in there.
You can read more about it here. Thanks to tak3shi for linking that in the comments.

Need help making a proper action listener in java

Ok so each text field the action listener. I've done many tests and found that adding the action listener is not the problem. The problem is somewhere in the below code because for the top four textfields, the hello window shows up but not the ok. But on the bottom one, the ok window and the hello window pop up. What did I do wrong?
public class handler implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == text)
{
JOptionPane.showMessageDialog(null, "ok");
}
else if (event.getSource() == text1)
{
JOptionPane.showMessageDialog(null, "ok");
}
else if (event.getSource() == text2)
{
JOptionPane.showMessageDialog(null, "ok");
}
else if (event.getSource() == text3)
{
JOptionPane.showMessageDialog(null, "ok");
}
else if (event.getSource() == text4)
{
JOptionPane.showMessageDialog(null, "ok");
}
JOptionPane.showMessageDialog(null, "hello");
}
}
The problem you're hitting is that you are doing a shallow comparison:
event.getSource() == textX
Thus, you never meet any of the conditions in your if-else and never see your "ok" dialog for text1 ... text4.
It looks like you are attempting to use a single ActionListener for multiple text fields and then differentiate behavior based on the Event source (the text field on which the Event occurred).
Rather than doing that, you may want to consider creating an ActionListener implementation for each text field.
I typically create my ActionListeners as anonymous classes so I can customize what I want to happen for a particular field when an Event occurs, but I do not have to proliferate classes in my application.

Categories