In my program I am testing a button which when clicked throws up a JOptionPane window in the application.
However when this window pops up it expects the user to click OK which means that the test can't continue unless the window is manually closed down.
I want to be able to close this window programmatically when it appears within my test or prevent these JOptionPane windows from popping up at all for this test.
What I typically do in such case is to make sure the UI does not appear in my test. Just to illustrate this with some code. Let's say the dialog is triggered somewhere in an Action
public class ActionWithUI extends AbstractAction{
#Override
public void actionPerformed( ActionEvent e ){
//... do some stuff
int result = JOptionPane.show... //show the dialog
//do some other stuff based on the result of the JOptionPane
}
}
I would then refactor my code so that the showing of the JOptionPane is in its own separate method.
public class ActionWithUI extends AbstractAction{
#Override
public void actionPerformed( ActionEvent e ){
//... do some stuff
int result = askUserForInput();
//do some other stuff based on the result of the JOptionPane
}
int askUserForInput(){
return JOptionPane.show...
}
}
Now in my test, I can test a custom version of that action where I override the askUserForInput method and just return the "OK" (or "Cancel", ... ) option. That will avoid any clever tricks in my test and keeps my code readable.
Another approach I sometimes use is not calling JOptionPane.show directly, but rather make sure my class accepts in its constructor a delegate class for showing such dialogs. In my test, I can then insert a mock instead of the real class, and intercept the call to the UI.
Of course, both of these approaches do not actually test whether the JOptionPane is correctly shown. But seeing as that is a JDK method, I do not really feel the need to test this. And it is not like I am bypassing some business logic. I just got rid of a JOptionPane.show call.
If none of these are an option, I normally use a listener attached to the DefaultKeyboardFocusManager. When the component which has the focus changes, I see whether it is the JOptionPane (using the Swing hierarchy) and dispose of it. This turns out to work quite well, but still not 100% reliable. Therefore (and certainly for new code), I try to stick to one of the two previously outlined approaches
There are two basic ways to overcome this issue. Both require you to be able to find the button.
This will require to be able to use a second Thread to find the window/dialog and walk it's container to find the button...
Depending on how your tests are set up will depend on how much additional work you might need to go through. The UI should be operating within the Event Dispatching Thread, if your tests are running in the same thread, then you will need to use separate Thread, as the JOptionPane will block the EDT (in a special way), making it impossible for your code to run until the option pane is closed.
If your tests are already running in a separate Thread, then you have a little more capability...
This is a very simple example. It initialises a JOptionPane within the context of the EDT, but has methods that are running in the main thread which find and execute the "OK" button of the message dialog.
import java.awt.Button;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Window;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FindButton {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JOptionPane.showMessageDialog(null, "This is message dialog", "Message", JOptionPane.INFORMATION_MESSAGE);
}
});
JDialog frame = waitForDialog("Message");
System.out.println("Found window " + frame);
if (frame != null) {
final JButton btn = getButton(frame, "OK");
System.out.println("Found button " + btn);
if (btn != null) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
btn.doClick();
}
});
}
}
}
public static JDialog waitForDialog(String title) {
JDialog win = null;
do {
for (Window window : Frame.getWindows()) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
System.out.println(dialog.getTitle());
if (title.equals(dialog.getTitle())) {
win = dialog;
break;
}
}
}
if (win == null) {
try {
Thread.sleep(250);
} catch (InterruptedException ex) {
break;
}
}
} while (win == null);
return win;
}
public static JButton getButton(Container container, String text) {
JButton btn = null;
List<Container> children = new ArrayList<Container>(25);
for (Component child : container.getComponents()) {
System.out.println(child);
if (child instanceof JButton) {
JButton button = (JButton) child;
if (text.equals(button.getText())) {
btn = button;
break;
}
} else if (child instanceof Container) {
children.add((Container) child);
}
}
if (btn == null) {
for (Container cont : children) {
JButton button = getButton(cont, text);
if (button != null) {
btn = button;
break;
}
}
}
return btn;
}
}
This example uses the doClick method of the JButton to simulate a clicking of the button. You could use the locationOnScreen information from the button and java.awt.Robot to physically click the button. but this just seemed simpler.
You could also take a look at Jemmy which is a utiliy library designed to make it easiert to test Swing (and JavaFX) based applications...
First, create a JDialog from a JOptionPane object. Then, create a timer to run for the time you want( exemple 1min) , and dispose the dialog once it has finished. Then, retrieve the chosen value from your JOptionPane object, making sure to account for an uninitialized value if the dialog was disposed by your timer.
final JOptionPane pane = new JOptionPane(......., JOptionPane.OK_CANCEL_OPTION);
final JDialog dialog = pane.createDialog(.....);
Timer timer = new Timer(you_time, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
dialog.dispose();
}
});
timer.start();
dialog.setVisible(true);
dialog.dispose();
Integer choice = (Integer) (pane.getValue() == JOptionPane.UNINITIALIZED_VALUE ? JOptionPane.OK_OPTION : pane.getValue());
Related
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
Okay, so here's the deal. Currently, I am using this:
String[] choices = {"Rock", "Paper", "Scissors"};
String input = (String) JOptionPane.showInputDialog(null, "Please, make your choice", "Rock Paper Scissors!", JOptionPane.QUESTION_MESSAGE, null, choices, choices[0]);
Which is what I need. It creates a drop down menu that allows the user to select Rock, Paper, or Scissors and then outputs it into a String. The problem is, the window that it pops in is REALLY small, and is in the center of the screen. I want to re-size it to be 970 pixels by 300 pixels, and to appear at the location of 950 pixels and 0 pixels.
Now, before you say it, I HAVE tried to use JFrames for this, because I know how to get it the size and at the location I want it. However, I can't get the ActionListener to behave in the way that I want it to.
public static void main(String args[]) throws IOException
{
JFrame hi = new JFrame("Hi");
hi.setSize(970, 300);
hi.setLocation(950, 0);
System.out.println("Hi");
Picture Hi = new Picture("c:/The Game/Cool.png");
Hi.display();
JButton B = new JButton("Hey There!");
hi.add(B);
int c = Output(hi);
}
public int Output(JFrame b)
{
int j = 0;
j = //CODE NEEDED HERE
return j;
}
#Override
public void actionPerformed(ActionEvent arg0) {
}
So, the problem with this is that I need the JFrame to pop up in then "CODE NEEDED HERE" section, and then, upon clicking the button, to return a certain value, and then to close out of the JFrame. However, the JFrame doesn't wait for the Output() function, and it immediately returns j, which is equal to 0. Instead, it just does whatever is in the actionPerformed function.
So, I am asking for a solution to either one of these problems. How to either re-size the JOptionPane.showInputDialog() or to get the JFrame to return an int value upon clicking a button.
Sorry if this is really poorly explained, I'm really new to JOptionPane and JFrames.
JOptionPane is quite configurable, it's also nicely self contained, taking a lot of the repetitive, boil plate code and hiding it away in an easy to use package.
But that doesn't mean you have to use it that way, you can simply create an instance of JOptionPane, which is just an ancestor of JComponent and add it to what ever you want.
The difficulty is plumbing all the functionality back together, so you can respond to the buttons, for example.
Just beware, your example places the dialog under my task bar (yes, mine is at the top of the screen), so I can tell you, as a user, that will annoy me!
So, this example basically wraps up all the boiler plate code into a simple class/method, which makes it easy to repeatedly prompt the user the same question, over and over again...
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
import static javax.swing.JOptionPane.UNINITIALIZED_VALUE;
import static javax.swing.JOptionPane.VALUE_PROPERTY;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
String pick = Picker.pick();
System.out.println("You picked " + pick);
System.exit(0);
}
public static class Picker {
public static String pick() {
String[] choices = {"Rock", "Paper", "Scissors"};
JOptionPane pane = new JOptionPane("Please, make your choice", JOptionPane.QUESTION_MESSAGE,
OK_CANCEL_OPTION, null, null, null);
pane.setWantsInput(true);
pane.setSelectionValues(choices);
pane.setInitialSelectionValue(choices[0]);
JDialog dialog = new JDialog();
dialog.setModal(true);
PropertyChangeListener listener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
// Let the defaultCloseOperation handle the closing
// if the user closed the window without selecting a button
// (newValue = null in that case). Otherwise, close the dialog.
if (dialog.isVisible()
&& (event.getPropertyName().equals(VALUE_PROPERTY))
&& event.getNewValue() != null
&& event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE) {
dialog.setVisible(false);
}
}
};
WindowAdapter adapter = new WindowAdapter() {
private boolean gotFocus = false;
public void windowClosing(WindowEvent we) {
pane.setValue(null);
}
public void windowClosed(WindowEvent e) {
dialog.removePropertyChangeListener(listener);
dialog.getContentPane().removeAll();
}
public void windowGainedFocus(WindowEvent we) {
// Once window gets focus, set initial focus
if (!gotFocus) {
pane.selectInitialValue();
gotFocus = true;
}
}
};
dialog.addWindowListener(adapter);
dialog.addWindowFocusListener(adapter);
dialog.addComponentListener(new ComponentAdapter() {
public void componentShown(ComponentEvent ce) {
// reset value to ensure closing works properly
pane.setValue(JOptionPane.UNINITIALIZED_VALUE);
}
});
pane.addPropertyChangeListener(listener);
dialog.add(pane);
//dialog.pack();
//dialog.setLocationRelativeTo(null);
dialog.setSize(970, 300); // This is bad idea, use an EmptyBorder instead
dialog.setLocation(950, 0);
dialog.setVisible(true);
String pick = null;
Object value = pane.getInputValue();
if (value != UNINITIALIZED_VALUE) {
pick = value.toString();
}
return pick;
}
}
}
The reason you're having problems with JFrame is because it's not designed to block the code execution when displayed, a JDialog can, see How to Make Dialogs for more details
I'm using the SwingX AutoCompleteDecorator for a JComboBox. The autocomplete feature works beautifully...
But I have trouble to identify the moment of the final user selection; to persist my data seldom.
Let me try to explain: The combobox fires an "comboBoxChanged"-ActionEvent for every selection. I have to ignore these events while the user is typing characters and the combobox is auto-matching and selecting items. If the user hits the return-key an "comboBoxEdited"-ActionEvent is generated and I can save the selected value. Great ;-)
If the mouse is used to open the JComboBox-PopUp and to select an item, the only fired event is a "comboBoxChanged"-ActionEvent (like when auto-matching or selecting an item with the cursor-keys). The mouse-clicked-Event is consumed somehow!? That's why I can't identify the final mouse selection.
How can I figure this out? My failed attempts to listen for the mouseClicked-Event are documented in this SSCCE:
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
public class SearchForThePopUpMouseClick extends JPanel
{
private JComboBox<String> comboBox;
public SearchForThePopUpMouseClick()
{
comboBox = new JComboBox<String>(new String[] { "Anna", "Marc", "Maria", "Marten", "Peter" });
add(comboBox);
add(new JTextField("textfield to click"));
AutoCompleteDecorator.decorate(comboBox);
comboBox.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println("Action Event with '" + e.getActionCommand() + " " + e.getID() + "'");
};
});
((Component) comboBox.getUI().getAccessibleChild(comboBox, 0)).addMouseListener(new MouseListener()
{
#Override
public void mouseReleased(MouseEvent e)
{
System.out.println(e);
}
#Override
public void mousePressed(MouseEvent e)
{
System.out.println(e);
}
#Override
public void mouseExited(MouseEvent e)
{
System.out.println(e);
}
#Override
public void mouseEntered(MouseEvent e)
{
System.out.println(e);
}
#Override
public void mouseClicked(MouseEvent e)
{
System.out.println(e);
}
});
}
public static void main(String[] args) throws Exception
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
SearchForThePopUpMouseClick autoCompletePanel = new SearchForThePopUpMouseClick();
JFrame frame = new JFrame("SwingX Autocomplete Example");
frame.add(autoCompletePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
A comboBox has no notion of final selection: all selections have equal semantic weight independent on their trigger (mouse, keyboard navigation, programmatically, selection by first letter in core) and fire an actionEvent. Same behaviour for plain and decorated comboBox.
That's exactly what you need in most contexts: react to a selection always as if it were final (whatever that might mean)
If in your case you really want to regard a selection triggered by a mouseEvent as more final than those triggered by anything else (again: that's typically not recommended for a good user experience, so be very, very careful in your evaluation) you can check the modifiers returned by the actionEvent:
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
// triggered by mouse
}
Edit
Seeing the use cases (thanks for providing them!) in the comments, realized that my beware partly barked at the wrong tree :-)
In this context, the mouse- vs. keyboard gesture have indeed different semantics
keyboard: typing in the editor as well as navigating in the popup denote the process to build the final selection, with a special key (enter) denoting a commit
mouse: clicking in the popup is both selecting and commit
JComboBox doesn't support that use-case optimally, firing too much. That's problem even swing-internally, f.i. when using a comboBox as CellEditor. That's partly fixed by a magic clientProperty:
public DefaultCellEditor(final JComboBox comboBox) {
editorComponent = comboBox;
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
Detecting that property, the BasicComboBoxUI (actually the BasicComboPopup) keyStrokes navigation selects in the list of the popup only, defering the synch of the listSelection to the comboSelection until committed via enter. It's partial because the look-ahead (aka: typing and selecting by first letter) still selects (and thereby committing) immediately in the combo.
Short summary: there already is a swing-internal use-case, which leads to an already available swingx-internal solution for autoComplete editing in tables - a class named ComboBoxCellEditor. Can be used stand-alone also:
AutoCompleteDecorator.decorate( withEditor );
ComboBoxCellEditor editor = new ComboBoxCellEditor(withEditor);
CellEditorListener listener = new CellEditorListener() {
#Override
public void editingStopped(ChangeEvent e) {
// do commit stuff
}
#Override
public void editingCanceled(ChangeEvent e) {
}
};
editor.addCellEditorListener(listener);
contentPane.add(withEditor, BorderLayout.SOUTH);
I know that there is another way to do this, but I prefer to see if anyone has an answer for doing it this way. The original way is to get the integer return value after calling the ShowDialog() function; I want to grab it from within the Event (shown below) itself. I've thrown some code in there to check if a file is selected, but I need to check whether the approval button (the OK button) has been selected before it gets there. Does anyone know how to check which button is pressed in a FileChooser dialog, using a setup like below?
Here's my code:
private void FileChooser_OpenMouseClicked(java.awt.event.MouseEvent evt) {
if(!FileChooser_Open.getSelectedFile().equals(null))
{
}
}
Original method:
//In response to a button click:
int returnVal = fc.showOpenDialog(aComponent);
The difference is that the original method gets a return value when the dialog box is closed, while in this method, I do not know of a way to get that return value (I believe the box has already closed, but there is nothing there to catch the return value). I apologize if I do not appear to be making a lot of sense.
edit: More information
So this is how I am creating the dialogue (a menu item, "Open" raises an event, which calls the showOpenDialog() method. As you can see, it is not capturing the return value (bear with me). Is it possible then to get the return value or at design a method to figure out whether the OK button is then pressed in the MouseClicked event? I guess I am trying to focus on an event-based programming style, where the code reacts according to the event raised, and grabbing the checking for the OK / approval button click inside the Open Menu event seems a little...disorganized from my perspective. Perhaps I am too used to C# / WinForm's approach to this problem?
private void MenuItem_OpenActionPerformed(java.awt.event.ActionEvent evt) {
FileChooser_Open.showOpenDialog(this);
}
private void FileChooser_OpenMouseClicked(java.awt.event.MouseEvent evt) {
if(!FileChooser_Open.getSelectedFile().equals(null))
{
}
}
If I understand the question, you might be able to use a JFileChooser#approveSelection() method:
OTN Discussion Forums : How to react on events fired by a JFileChooser?
java - JFileChooser with confirmation dialog - Stack Overflow
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class ApproveSelectionDemo {
public JComponent makeUI() {
final JPanel p = new JPanel();
final JFileChooser fileChooser = new JFileChooser() {
#Override public void approveSelection() {
if(!getSelectedFile().exists()) {
int returnVal = JOptionPane.showConfirmDialog(
this, "message", "title", JOptionPane.YES_NO_OPTION);
if(returnVal!=JOptionPane.YES_OPTION) {
return;
}
}
super.approveSelection();
}
};
p.add(new JButton(new AbstractAction("Open") {
#Override public void actionPerformed(ActionEvent e) {
int retvalue = fileChooser.showOpenDialog(p);
if(retvalue==JFileChooser.APPROVE_OPTION) {
System.out.println(fileChooser.getSelectedFile());
}
}
}));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new ApproveSelectionDemo().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
I had posted this in a wrong place (GameDev) and got no response there. So I'm posting it again here.
I'm making an applet game and it is rendering, the game loop is running, the animations are updating, but the keyboard input is not working. Here's an SSCCE.
public class Game extends JApplet implements Runnable {
public void init(){
// Initialize the game when called by browser
setFocusable(true);
requestFocus();
requestFocusInWindow(); // Always returning false
GInput.install(this); // Install the input manager for this class
new Thread(this).start();
}
public void run(){
startGameLoop();
}
}
And Here's the GInput class.
public class GInput implements KeyListener {
public static void install(Component c){
new GInput(c);
}
public GInput(Component c){
c.addKeyListener(this);
}
public void keyPressed(KeyEvent e){
System.out.println("A key has been pressed");
}
......
}
This is my GInput class. When run as an applet, it doesn't work and when I add the Game class to a frame, it works properly.
Thanks
Solved now. See my solution
One possible solution is to use the JApplet's contentPane, to set the focus on it rather than on the JApplet itself. But my preference is to use Key Bindings instead. You may need to use a Swing Timer for this to work:
My SSCCE:
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
#SuppressWarnings("serial")
public class AppletKeyListen extends JApplet {
#Override
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setFocusable(true);
int timerDelay = 100;
Timer myTimer = new Timer(timerDelay , new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
boolean focusObtained = requestFocusInWindow();
System.out.println("focusObtained for JApplet: " + focusObtained);
Container contentPane = getContentPane();
contentPane.setFocusable(true);
focusObtained = contentPane.requestFocusInWindow();
System.out.println("focusObtained for contentPane: " + focusObtained);
}
});
myTimer.setRepeats(false);
myTimer.start();
// boolean focusObtained = requestFocusInWindow();
// System.out.println("focusObtained: " + focusObtained);
//
// Container contentPane = getContentPane();
// contentPane.setFocusable(true);
//
// focusObtained = contentPane.requestFocusInWindow();
// System.out.println("focusObtained: " + focusObtained);
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
}
If you're running in a browser, you probably need to click on the applet to give it focus. For security reasons most browsers won't let an applet just grab the keyboard focus without the user clicking it.
So, I would add a mouse listener instead of doing the focus grabbing directly in init():
addMouseListener(new MouseAdapter() {
public void onMousePress(MouseEvent e) {
requestFocus();
}
});
Now that I have two options,
Use JWS
Don't make an applet mode
Now I had tried to make a new class called GApplet. It loads a game into a new JFrame which worked from the applet. Now I can access the fullscreen mode from web too. Here's a link to the class.
The GApplet class
And now it's working like the webstart and is actually an applet.