Since jdk 8u40, I'm using the new javafx.scene.control.Alert API to display a confirmation dialog. In the example below, "Yes" button is focused by default instead of "No" button:
public boolean showConfirmDialog(String title, String header, String content, AlertType alertType) {
final Alert alert = new Alert(alertType);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(content);
alert.getButtonTypes().clear();
alert.getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
final Optional<ButtonType> result = alert.showAndWait();
return result.get() == ButtonType.YES;
}
And I don't know how to change it.
EDIT :
Here a screenshot of the result where "Yes" button is focused by default :
I am not sure if the following is the way to usually do this, but you could change the default button by looking up the buttons and setting the default-behavior yourself:
public boolean showConfirmDialog(String title, String header, String content, AlertType alertType) {
final Alert alert = new Alert(alertType);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(content);
alert.getButtonTypes().clear();
alert.getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
//Deactivate Defaultbehavior for yes-Button:
Button yesButton = (Button) alert.getDialogPane().lookupButton( ButtonType.YES );
yesButton.setDefaultButton( false );
//Activate Defaultbehavior for no-Button:
Button noButton = (Button) alert.getDialogPane().lookupButton( ButtonType.NO );
noButton.setDefaultButton( true );
final Optional<ButtonType> result = alert.showAndWait();
return result.get() == ButtonType.YES;
}
A simple function thanks to crusam:
private static Alert setDefaultButton ( Alert alert, ButtonType defBtn ) {
DialogPane pane = alert.getDialogPane();
for ( ButtonType t : alert.getButtonTypes() )
( (Button) pane.lookupButton(t) ).setDefaultButton( t == defBtn );
return alert;
}
Usage:
final Alert alert = new Alert(
AlertType.CONFIRMATION, "You sure?", ButtonType.YES, ButtonType.NO );
if ( setDefaultButton( alert, ButtonType.NO ).showAndWait()
.orElse( ButtonType.NO ) == ButtonType.YES ) {
// User selected the non-default yes button
}
If you have a look at (private) ButtonBarSkin class, there is a method called doButtonOrderLayout() that performs the layout of the buttons, based in some default OS behavior.
Inside of it, you can read this:
/* now that all buttons have been placed, we need to ensure focus is
set on the correct button. [...] If so, we request focus onto this default
button. */
Since ButtonType.YES is the default button, it will be the one focused.
So #ymene answer is correct: you can change the default behavior and then the one focused will be NO.
Or you can just avoid using that method, by setting BUTTON_ORDER_NONE in the buttonOrderProperty(). Now the first button will have the focus, so you need to place first the NO button.
alert.getButtonTypes().setAll(ButtonType.NO, ButtonType.YES);
ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar");
buttonBar.setButtonOrder(ButtonBar.BUTTON_ORDER_NONE);
Note that YES will still have the default behavior: This means NO can be selected with the space bar (focused button), while YES will be selected if you press enter (default button).
Or you can change also the default behavior following #crusam answer.
Related
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.
How do I display tooltip of a text field when it is in focus, not when mouse is hovering over?
I use TooltipConfig .
TextField email = getEditor().getEmail();
ToolTipConfig toolTipConfig = new ToolTipConfig();
toolTipConfig.setBodyText("TEXT BODY");
toolTipConfig.setAnchor(Style.Side.LEFT);
toolTipConfig.setMouseOffsetY(0);
toolTipConfig.setMouseOffsetX(0);
Are you using extjs? If so, here's my answer:
You need to create custom tooltip to disable the default mouseover event.
Ext.define('nutnull.ToolTip', function() {
return {
extend: 'Ext.tip.ToolTip',
xtype: 'nutnull-tooltip',
// Set this as emptyFn so that it will not create mouse event to show the tooltip
setTarget: Ext.emptyFn
};
});
Then you can override the textfield to show tooltip during focus event.
Ext.define('nutnull.override.Text', {
override: 'Ext.form.field.Text',
tip: null,
onFocus: function() {
// show tooltip if exist
if(this.tip) {
if(!this.tipCmp) {
this.tipCmp = Ext.create('nutnull.ToolTip', {
target: this.id,
html: this.tip
});
}
// Get the position of the textfield instead of mouse position
this.tipCmp.targetXY = this.getPosition();
// Adjust the position.
this.tipCmp.targetXY[0] += this.getWidth();
this.tipCmp.targetXY[1] -= (this.getHeight()/2);
// Manually show the tooltip
this.tipCmp.show();
}
this.callParent(arguments);
}
});
In the textfield item, just add tip: 'Sample Description' config.
{
xtype: 'textfield',
fieldLabel: 'Name',
tip: 'Sample Description'
}
I resolved this problem. I made new Tooltip object and wrapped tooltip config into this object.
TextField email = getEditor().getEmail();
ToolTipConfig toolTipConfig = new ToolTipConfig();
toolTipConfig.setBodyText("TEXT BODY");
toolTipConfig.setAnchor(Style.Side.LEFT);
toolTipConfig.setMouseOffsetY(0);
toolTipConfig.setMouseOffsetX(0);
Tooltip tooltip = new ToolTip(email,toolTipConfig);
tooltip.show();
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.
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.
I have a small problem trying to figure out how to check if a user presses a button in a custom JOptionPane.
My dialog is based on an inputDialog with custom texts for the YES, NO and CANCEL buttons ("Select", "Cancel", "Open Editor").
I tried searching for a solution, but all I found was questions that used the static JOptionPane functions.
Here is my code I am using for now:
public SelectItemDialog(Component parent) {
super("Please select an item:", YES_NO_CANCEL_OPTION, PLAIN_MESSAGE, Editor.getIcon("bookmark"),
new String[] { "Select", "Cancel", "Open Item Editor" }, "Select"
);
setWantsInput(true);
setSelectionValues(null); // Would replace with an Object array
setInitialSelectionValue(null);
setComponentOrientation(getRootFrame().getComponentOrientation());
JDialog dialog = createDialog(parent, "Select Item");
selectInitialValue();
dialog.setVisible(true);
dialog.dispose();
Object obj = getInputValue();
if(obj instanceof Item) {
this.openEditor = false;
this.item = (Item) obj;
} else {
this.openEditor = (obj.equals( CANCEL_OPTION));
this.item = null;
}
}
The check for CANCEL_OPTION is not working at all, same with UNDEFINED_OPTION.
Any ideas?
Actually I just had to use the Object returned by the JOptionPane itself: getValue(), problem solved!