Update March 2023
Changed links to reference modern versions of documents. These are JavaFX 8 for Oracle tutorials as those are the latest they provided and JavaFX 20 for API documents and reference guides.
Some parts of the example may still use or rely on obsolete features of JavaFX which were relevant at the time the answer was originally created, so you might not get the exact outcome shown in the sample images, but, in general, most parts of the answer are still relevant today.
I think for your description, that you actually want a ToggleButton rather than a standard Button.
There is a nice Oracle tutorial on ToggleButtons.
Addressing Items from the Question
dark blue halo appears to show it was clicked
The blue halo is actually a focus ring indicating that a control has focus.
To focus a control, you can invoke the requestFocus method.
During the course of events, my program may want to 'unclick' it to show it is no longer selected.
To remove focus from a control, you can call requestFocus on another control to focus on that control instead.
I expected a button.setSelected(false);
To have a button which can toggle between a selected and unselected state, use a ToggleButton. A ToggleButton
has a setSelected method.
setEffect(new DropShadow()) Using setStyle() is ok, but what values to use
css style values for drop shadow effects are define in the JavaFX CSS Reference Guide.
It is visually equivalent to define the drop shadow effect in code via setEffect
or via css with setStyle
or applying a style class from a stylesheet. Of the three approaches, I would never recommend the setStyle
approach, but only the css from stylesheet or the setEffect
from code approach.
Related
Note there is an additional related property - armed:
Indicates that the button has been "armed" such that a mouse release will cause the button's action to be invoked. This is subtly different from pressed. Pressed indicates that the mouse has been pressed on a Node and has not yet been released. arm however also takes into account whether the mouse is actually over the button and pressed.
A button in an armed state has a slightly different look than one which is not in an armed state. Most programs never need to interact with the armed state of buttons.
Sample for styling the selected state
The standard way to differentiate a selected ToggleButton from one which is not Selected is to darken it to give it a depth style effect and make it appear further away when it has been pushed. Here is the standard toggle button css for JavaFX 20:
.toggle-button:selected {
-fx-background-color:
-fx-shadow-highlight-color,
linear-gradient(to bottom, derive(-fx-outer-border, -20%), -fx-outer-border),
linear-gradient(to bottom,
derive(-fx-color, -22%) 0%,
derive(-fx-color, -13%) 20%,
derive(-fx-color, -11%) 50%);
-fx-background-insets: 0 0 -1 0, 0, 1;
}
.toggle-button:selected:focused {
-fx-background-color:
-fx-focus-color,
linear-gradient(to bottom,
derive(-fx-color, -22%) 0%,
derive(-fx-color, -13%) 20%,
derive(-fx-color, -11%) 50%),
-fx-faint-focus-color,
linear-gradient(to bottom,
derive(-fx-color, -22%) 0%,
derive(-fx-color, -13%) 20%,
derive(-fx-color, -11%) 50%);
-fx-background-insets: -0.2, 1, -1.4, 2.6;
-fx-background-radius: 3, 2, 4, 0;
}
You can override this default behavior by defining your own stylesheet that provides an alternate definition for the selected state. The sample below will ensure that the selected state display is much more subtle than the standard, only darkening the selected state color a small fraction rather than a lot.
Unselected
Selected
Associated css:
/**
* file: colored-toggle.css
* Place in same directory as ColoredToggle.java.
* Have your build system copy this file to your build output directory.
**/
.root {
-fx-background-color: cornsilk;
-fx-padding: 10;
}
.toggle-button {
-fx-color: paleturquoise;
}
.toggle-button:selected {
-fx-background-color:
-fx-shadow-highlight-color,
linear-gradient(to bottom, derive(-fx-color,-22%) 0%, derive(-fx-color,-15%) 100%),
linear-gradient(to bottom, derive(-fx-color,-15%) 0%, derive(-fx-color,-10%) 50%, derive(-fx-color,-8%) 98%, derive(-fx-color,-12%) 100%);
}
.toggle-button:selected:focused {
-fx-background-color:
-fx-focus-color,
linear-gradient(to bottom, derive(-fx-color,-22%) 0%, derive(-fx-color,-15%) 100%),
linear-gradient(to bottom, derive(-fx-color,-15%) 0%, derive(-fx-color,-10%) 50%, derive(-fx-color,-8%) 98%, derive(-fx-color,-12%) 100%);
}
Source file:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ColoredToggle extends Application {
public static void main(String[] args) { Application.launch(ColoredToggle.class, args); }
@Override public void start(Stage stage) {
ToggleButton visibilityControl = new ToggleButton("Winterfell");
VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(visibilityControl);
layout.getStylesheets().add(getClass().getResource("colored-toggle.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}
}