JaveFX toggle button doesn't return to default after setting background - javafx

I have the following code in my app
private void showImg(ToggleButton tb) {
Image img = new Image(getAssociatedImage(tb), tb.getWidth(), tb.getHeight(), false, true, true);
BackgroundImage bimg = new BackgroundImage(img, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, new BackgroundSize(tb.getWidth(), tb.getHeight(), true, true, true, false));
Background bkg = new Background(bimg);
Background old = tb.getBackground();
tb.setBackground(bkg);
PauseTransition pause = new PauseTransition(Duration.seconds(3));
pause.setOnFinished(event -> {
tb.setBackground(old);
});
pause.play().
}
It mainly does as I've expected, showing the new background img for 3 seconds, but after "restoring" the old background the ToggleButton looks and feel different; It doesn't look "metalic" as it used to, clicking on it doesn't make it appear "selected", no hovering reaction.
I'm not sure what I've done wrong here I returned the original background of the button and expected it to go back to "default"
EDIT:
minimal working example
public class Test2 extends Application{
#Override
public void start(Stage stage) throws Exception {
ToggleButton root = new ToggleButton();
root.setPrefHeight(300);
root.setPrefWidth(300);
root.setOnAction(event -> {
Image img = new Image(getClass().getResource("1.png").toExternalForm(), root.getWidth(), root.getHeight(), false, true, true);
BackgroundImage bimg = new BackgroundImage(img, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, new BackgroundSize(root.getWidth(), root.getHeight(), false, false, true, false));
Background bkg = new Background(bimg);
Background old = root.getBackground();
root.setBackground(bkg);
PauseTransition pause = new PauseTransition(Duration.seconds(3));
pause.setOnFinished(evt -> {
root.setBackground(old);
});
pause.play();
});
Scene scene = new Scene((Parent)root);
stage.setTitle("Example");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

How do I make my buttons all the same size?

Sorry, I have just begun learning javaFX and cannot figure out how to get all of my icons on buttons the same size. I tried a couple things but could not get it working, all help is appreciated. Thank you!
Wont let me post my question unless I add more details but I cant think of anything else to put so just ignore this whole paragraph as I ramble on so I can post my question and continue coding my game.
public class Main extends Application {
Stage window;
Button button;
Scene scene1, scene2;
public static final int ROCK = 0;
public static final int PAPER = 1;
public static final int SCISSORS = 2;
public static int userChoice;
public static void main(String [] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
window = primaryStage;
//Layout 1
VBox layout = new VBox(20);
Label label = new Label("Rock Paper Scissors");
Button myButton = new Button("Start");
myButton.setOnAction(e -> window.setScene(scene2));
Button exit = new Button("Exit");
exit.setOnAction(e -> System.exit(0));
layout.getChildren().addAll(label, myButton, exit);
layout.setAlignment(Pos.CENTER);
scene1 = new Scene(layout, 300, 300);
//Layout 2
BorderPane border = new BorderPane();
VBox layout1 = new VBox(10);
Label label1 = new Label("Choose One");
layout1.setAlignment(Pos.CENTER);
//Layout 3
HBox layout2 = new HBox(10);
//Rock Image Button
Image rockIm = new Image(getClass().getResourceAsStream("Rock2.png"));
Button rock = new Button();
rock.setGraphic(new ImageView(rockIm));
rock.setOnAction(e -> userChoice = ROCK);
//Paper Image Button
Image paperIm = new
Image(getClass().getResourceAsStream("Paper2.png"));
Button paper = new Button();
paper.setGraphic(new ImageView(paperIm));
paper.setOnAction(e -> userChoice = PAPER);
//Scissor Image Button
Image scissorIm = new
Image(getClass().getResourceAsStream("Scissor2.png"));
Button scissors = new Button();
scissors.setGraphic(new ImageView(scissorIm));
scissors.setOnAction(e -> userChoice = SCISSORS);
Button quit = new Button("Return");
quit.setOnAction(e -> window.setScene(scene1));
layout2.getChildren().addAll(rock, paper, scissors, quit);
layout2.setAlignment(Pos.CENTER);
scene2 = new Scene(layout2, 300, 300);
window.setTitle("Rock Paper Scissors");
window.setScene(scene1);
window.show();
}
}

Stage loses fill (gradient) after simply creating a new control

I have reduced my recreate of this to the following. The line where a ToggleButton is instantiated causes my stage to lose its fill color; it goes white. I am just getting started with JavaFX, so please let me know if I'm doing something I shouldn't, here. This is using jre1.8.0_92 with Eclipse Neon (jfx8_2.3.0 plugin) on Windows 7 sp1.
public class Main extends Application {
public static void main(String[] args) {
if(args.length > 0) {
String s = args[0].toLowerCase();
if(s.equals("full"))
Machine.isFullScreen = true;
}
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Machine.startMachine(primaryStage);
}
}
public class Machine {
static boolean isFullScreen = false;
static Rectangle2D screenRect, backRect;
static Stage backStage;
static Scene backScene;
static Pane backPane;
private Machine() {}
static public void startMachine(Stage primaryStage) {
// backscreen
startScene(primaryStage);
// This line causes the fill to be lost
ToggleButton foo = new ToggleButton("hi");
}
static private void startScene(Stage primaryStage) {
// Stage
backStage = primaryStage;
backStage.initStyle(StageStyle.UNDECORATED);
backStage.setFullScreen(isFullScreen);
screenRect = Screen.getPrimary().getBounds();
if(!isFullScreen) {
int w = 1000, h = 500, t = 20;
backStage.setWidth(w);
backStage.setHeight(h);
backStage.setX((screenRect.getWidth() - w)/2);
backStage.setY(t);
}
backRect = new Rectangle2D(backStage.getX(), backStage.getY(),
backStage.getWidth(), backStage.getHeight());
// Scene
backScene = new Scene(backPane = new Pane());
// backScene.getStylesheets().add(Machine.class.getResource("mainStyle.css").toExternalForm());
// backScene.getRoot().setStyle("-fx-background-color: #CCFF99;");
backScene.setFill(new LinearGradient(0,0,1,1, true, CycleMethod.NO_CYCLE,
new Stop[]{
new Stop(0,Color.web("#4977A3")),
new Stop(0.5, Color.web("#B0C6DA")),
new Stop(1,Color.web("#9CB6CF")), } ));
// Logo
Text logo = new Text("AMT");
logo.setFill(Color.DEEPSKYBLUE);
Font font = Font.font("Times New Roman", FontWeight.BOLD, FontPosture.ITALIC, 96);
logo.setFont(font);
logo.setX(100);
logo.setY(150);
backPane.getChildren().add(logo);
backStage.setScene(backScene);
backStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
backStage.show();
}
}
The setFill() API suggests that this may be a stylesheet effect. The default stylesheet is installed statically when the first Control is instantiated. If that stylesheet is Modena, "the default fill is set to be a light gray color." Instead of backScene.setFill(), try backPane.setBackground(), as suggested here and here.
// Scene
backPane = new Pane();
backScene = new Scene(backPane);
LinearGradient linearGradient = new LinearGradient(
0, 0, 1, 1, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.web("#4977A3")),
new Stop(0.5, Color.web("#B0C6DA")),
new Stop(1, Color.web("#9CB6CF")));
backPane.setBackground(new Background(new BackgroundFill(
linearGradient, CornerRadii.EMPTY, Insets.EMPTY)));
As an aside, note that the varargs constructor parameter of LinearGradient allows you to add instances of Stop directly, without creating a new array.

JavaFX ColorPicker show uncolor option

I want to show un-color option in my ColorPicker.
How i can show it?
Thanks.
The solution is a bit of a hack, but it avoids using private API.
These are the required steps:
Get the Popup control that shows up when you click on the ColorPicker.
You can find it here or here.
Get the square colors on that popup, so we can change one of them. I'll use the last one.
Once we have the popup, we'll get the set of square colors by using lookups: Set<Node> squares = popup.lookupAll(".color-rect");
Let's use the last color to add our customized 'un-color'.
Find out how to draw that red diagonal line.
I've come up with a LinearGradient:
final LinearGradient redLine = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE), new Stop(0.45, Color.WHITE),
new Stop(0.46, Color.RED), new Stop(0.54, Color.RED),
new Stop(0.55, Color.WHITE), new Stop(1, Color.WHITE));
That works fine, but sadly the gradient breaks the ColorPicker control, that is an extension of ComboBoxBase<Color>, and all the fills used for the rectangles will be casted to Color instead of Paint. That means we'll have to use a color (for instance Color.TRANSPARENT) during the transitions.
Solve other issues like the square color that will be seen when the popup closes, or the square color that shows up on hovering.
For this, we need to lookup for both the square color in the color picker and hovered square, and when those match our transparent one, replace the color with the gradient.
This is the code:
public class UnColorPicker extends Application {
private final LinearGradient redLine = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE), new Stop(0.45, Color.WHITE), new Stop(0.46, Color.RED),
new Stop(0.54, Color.RED), new Stop(0.55, Color.WHITE), new Stop(1, Color.WHITE));
#Override
public void start(Stage primaryStage) {
ColorPicker picker = new ColorPicker();
StackPane root = new StackPane(picker);
Scene scene = new Scene(root, 500, 400);
primaryStage.setScene(scene);
primaryStage.show();
Rectangle rect = (Rectangle) root.lookup(".picker-color-rect");
Label label = (Label) root.lookup(".color-picker-label");
picker.showingProperty().addListener((obs, b, b1) -> {
if (b1) {
PopupWindow popupWindow = getPopupWindow();
Node popup = popupWindow.getScene().getRoot().getChildrenUnmodifiable().get(0);
StackPane hover = (StackPane) popup.lookup(".hover-square");
Rectangle rectH = (Rectangle) hover.getChildren().get(0);
Set<Node> squares = popup.lookupAll(".color-rect");
squares.stream()
.skip(squares.size()-2)
.map(Rectangle.class::cast)
.findFirst()
.ifPresent(r -> {
r.getParent().setOnMousePressed(e -> {
// avoid CastException
r.setFill(Color.TRANSPARENT);
e.consume();
});
r.getParent().setOnMouseReleased(e -> {
Platform.runLater(() -> {
rect.setFill(redLine);
label.setText("Un-color");
});
});
r.setFill(redLine);
Tooltip.install(r.getParent(), new Tooltip("Un-color"));
});
hover.visibleProperty().addListener((obs2, ov, nv) -> {
if (nv && rectH.getFill().equals(Color.TRANSPARENT)) {
Platform.runLater(() -> rectH.setFill(redLine));
}
});
}
});
}
private PopupWindow getPopupWindow() {
#SuppressWarnings("deprecation")
final Iterator<Window> windows = Window.impl_getWindows();
while (windows.hasNext()) {
final Window window = windows.next();
if (window instanceof PopupWindow) {
return (PopupWindow)window;
}
}
return null;
}
public static void main(String[] args) {
launch(args);
}
}
The approach posted above didn't work for me anymore so I came up with a slightly different solution, though the idea is the same. It also avoids using deprecated functions.
I subclassed the ColorPicker class to build my own CustomColorPicker which can be used instead.
Here is my code:
#SuppressWarnings("restriction")
public class CustomColorPicker extends ColorPicker {
final static LinearGradient RED_LINE = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE), new Stop(0.45, Color.WHITE),
new Stop(0.46, Color.RED), new Stop(0.54, Color.RED),
new Stop(0.55, Color.WHITE), new Stop(1, Color.WHITE));
#Override
protected Skin<?> createDefaultSkin() {
final CustomColorPickerSkin skin = new CustomColorPickerSkin(this);
final Label lbl = (Label)skin.getDisplayNode();
final StackPane pane = (StackPane)lbl.getGraphic();
final Rectangle rect = (Rectangle)pane.getChildren().get(0);
// set initial color to red line if transparent is shown
if (getValue().equals(Color.TRANSPARENT))
rect.setFill(RED_LINE);
// set color to red line when transparent is selected
rect.fillProperty().addListener((o, oldVal, newVal) -> {
if (newVal != null && newVal.equals(Color.TRANSPARENT))
rect.setFill(RED_LINE);
});
return skin;
}
private class CustomColorPickerSkin extends ColorPickerSkin {
private boolean initialized = false;
public CustomColorPickerSkin(ColorPicker colorPicker) {
super(colorPicker);
}
#Override
protected Node getPopupContent() {
final ColorPalette popupContent = (ColorPalette)super.getPopupContent();
// make sure listeners and geometry are only created once
if (!initialized) {
final VBox paletteBox = (VBox)popupContent.getChildrenUnmodifiable().get(0);
final StackPane hoverSquare = (StackPane)popupContent.getChildrenUnmodifiable().get(1); // ColorSquare
final Rectangle hoverRect = (Rectangle)hoverSquare.getChildren().get(0); // ColorSquare
final GridPane grid = (GridPane)paletteBox.getChildren().get(0); // ColorPalette
final StackPane colorSquare = (StackPane)grid.getChildren().get(grid.getChildren().size()-1); // ColorSquare
final Rectangle colorRect = (Rectangle)colorSquare.getChildren().get(0);
// set fill color of original color rectangle to transparent
// (can't be set to red line gradient because ComboBoxBase<Color> tries to cast it to Color)
colorRect.setFill(Color.TRANSPARENT);
// put another rectangle with red line on top of it
colorSquare.getChildren().add(new Rectangle(colorRect.getWidth(), colorRect.getHeight(), RED_LINE));
// show red line gradient also in hover rectangle when the transparent color is selected
hoverRect.fillProperty().addListener((o, oldVal, newVal) -> {
if (newVal.equals(Color.TRANSPARENT))
hoverRect.setFill(RED_LINE);
});
initialized = true;
}
return popupContent;
}
}
}

JavaFX Transition - Darken button on hover

I'm a beginner in JavaFX. I'm trying to create my own Button subclass that would have its on animations for mouse enter and mouse exit. The animation I'm trying to achieve is a simple "darken" or "dim" transition that would darken the color of the button background when user hovers over the button , and would animate back to normal state when the mouse exits the button.
First I thought I can achieve this with FillTransition, but for that I would need the specific darker color of the button, that depends on the button color.
So now I'm trying to basically fade in and fade out a low-opacity black rectangle on top of the button, but the rectangle doesn't seem to appear at all.
Here's the code of my button:
public class FlatButton extends Button {
private Rectangle dimRectangle;
private Duration dimDuration = Duration.millis(250);
private Color dimColor = new Color(0,0,0,0.11);
public FlatButton(String text) {
super(text);
getStyleClass().addAll("flat-button-style");
createEffect();
}
private void createEffect()
{
dimRectangle = new Rectangle(this.getWidth(), this.getHeight(), dimColor);
dimRectangle.setOpacity(1.0);
dimRectangle.setX(this.get);
FadeTransition enterTransition = new FadeTransition(dimDuration, this);
enterTransition.setInterpolator(Interpolator.EASE_OUT);
enterTransition.setFromValue(0.0);
enterTransition.setToValue(1.0);
FadeTransition exitTransition = new FadeTransition(dimDuration, this);
exitTransition.setInterpolator(Interpolator.EASE_OUT);
exitTransition.setFromValue(1.0);
exitTransition.setToValue(0.0);
this.setOnMouseEntered(new EventHandler<MouseEvent>(){
public void handle(MouseEvent mouseEvent){
enterTransition.play();
}
});
this.setOnMouseExited(new EventHandler<MouseEvent>(){
public void handle(MouseEvent mouseEvent){
exitTransition.play();
}
});
}
}
EDIT: The part in the code "new FadeTransition(dimDuration, this);" should be "new FadeTransition(dimDuration, dimRectangle);". It's just something I was testing.
EDIT2: I figured that "dimRectangle = new Rectangle(this.getWidth(), this.getHeight(), dimColor);" is not really working , but I havent found a way yet how to make the rectangle fill the button dimensions.
You could use a ColorAdjust effect and change it's brightness property using a Timeline.
public class ButtonFadeDemo extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Button button = new Button("Click me!");
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setBrightness(0.0);
button.setEffect(colorAdjust);
button.setOnMouseEntered(e -> {
Timeline fadeInTimeline = new Timeline(
new KeyFrame(Duration.seconds(0),
new KeyValue(colorAdjust.brightnessProperty(), colorAdjust.brightnessProperty().getValue(), Interpolator.LINEAR)),
new KeyFrame(Duration.seconds(1), new KeyValue(colorAdjust.brightnessProperty(), -1, Interpolator.LINEAR)
));
fadeInTimeline.setCycleCount(1);
fadeInTimeline.setAutoReverse(false);
fadeInTimeline.play();
});
button.setOnMouseExited(e -> {
Timeline fadeOutTimeline = new Timeline(
new KeyFrame(Duration.seconds(0),
new KeyValue(colorAdjust.brightnessProperty(), colorAdjust.brightnessProperty().getValue(), Interpolator.LINEAR)),
new KeyFrame(Duration.seconds(1), new KeyValue(colorAdjust.brightnessProperty(), 0, Interpolator.LINEAR)
));
fadeOutTimeline.setCycleCount(1);
fadeOutTimeline.setAutoReverse(false);
fadeOutTimeline.play();
});
root.getChildren().addAll(button);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

Set image on left side of dialog

I created this very simple example for JavaFX alert dialog for JavaFX8u40.
public class MainApp extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception
{
Button create = new Button("Create Alert");
create.setTooltip(new Tooltip("Create an Alert Dialog"));
create.setOnAction(e ->
{
createAlert();
});
primaryStage.setScene(new Scene(create));
primaryStage.show();
stage = primaryStage;
}
protected Alert createAlert()
{
Alert alert = new Alert(AlertType.WARNING);
Image image1 = new Image("http://www.mcaprojecttraining.com/images/java-big-icon.png");
ImageView imageView = new ImageView(image1);
alert.setGraphic(imageView);
alert.initModality(Modality.APPLICATION_MODAL);
alert.initOwner(stage);
alert.getDialogPane().setContentText("Some text");
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
.ifPresent(response -> System.out.println("The alert was approved"));
return alert;
}
}
I'm interested how I can set the image on the left side of the dialog.
Did someone manage to change the side of the image?
If you have a look at how the header is constructed, you'll find a GridPane node to layout a Label on the left and a StackPane for the icon.
If you want to reverse the cells order by code, you can do it, but it will be overriden every time updateHeaderArea() is called.
My suggestion is using this public API:
dialogPane.setHeader(Node header);
dialogPane.setGraphic(Node graphic);
providing a header with an icon on the left and a label, and a null graphic.
Using the same approach as DialogPane, we could add another GridPane as header:
protected Alert createAlert(){
Alert alert = new Alert(AlertType.WARNING);
alert.initModality(Modality.APPLICATION_MODAL);
alert.initOwner(stage);
alert.getDialogPane().setContentText("Some text");
DialogPane dialogPane = alert.getDialogPane();
GridPane grid = new GridPane();
ColumnConstraints graphicColumn = new ColumnConstraints();
graphicColumn.setFillWidth(false);
graphicColumn.setHgrow(Priority.NEVER);
ColumnConstraints textColumn = new ColumnConstraints();
textColumn.setFillWidth(true);
textColumn.setHgrow(Priority.ALWAYS);
grid.getColumnConstraints().setAll(graphicColumn, textColumn);
grid.setPadding(new Insets(5));
Image image1 = new Image("http://www.mcaprojecttraining.com/images/java-big-icon.png");
ImageView imageView = new ImageView(image1);
imageView.setFitWidth(64);
imageView.setFitHeight(64);
StackPane stackPane = new StackPane(imageView);
stackPane.setAlignment(Pos.CENTER);
grid.add(stackPane, 0, 0);
Label headerLabel = new Label("Warning");
headerLabel.setWrapText(true);
headerLabel.setAlignment(Pos.CENTER_RIGHT);
headerLabel.setMaxWidth(Double.MAX_VALUE);
headerLabel.setMaxHeight(Double.MAX_VALUE);
grid.add(headerLabel, 1, 0);
dialogPane.setHeader(grid);
dialogPane.setGraphic(null);
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
.ifPresent(response -> System.out.println("The alert was approved"));
return alert;
}
And this is what you will see:

Resources