Animate splitpane divider - javafx

I have a horizontal split pane, and i would like to on button click, change divider position, so that i create sort of "slide" animation.
divider would start at 0 (complete left) and on my click it would open till 0.2, when i click again, it would go back to 0;
now i achived this, i just use
spane.setdividerPositions(0.2);
and divider position changes, but i cant manage to do this slowly i would really like that slide feeling when changing divider position.
Could anyone help me ? all examples i found on google, show some DoubleTransition, but that does not exist anymore in java 8, at least i dont have import for that.

You can call getDividers().get(0) to get the first divider. It has a positionProperty() that you can animate using a timeline:
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class AnimatedSplitPane extends Application {
#Override
public void start(Stage primaryStage) {
SplitPane splitPane = new SplitPane(new Pane(), new Pane());
splitPane.setDividerPositions(0);
BooleanProperty collapsed = new SimpleBooleanProperty();
collapsed.bind(splitPane.getDividers().get(0).positionProperty().isEqualTo(0, 0.01));
Button button = new Button();
button.textProperty().bind(Bindings.when(collapsed).then("Expand").otherwise("Collapse"));
button.setOnAction(e -> {
double target = collapsed.get() ? 0.2 : 0.0 ;
KeyValue keyValue = new KeyValue(splitPane.getDividers().get(0).positionProperty(), target);
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(500), keyValue));
timeline.play();
});
HBox controls = new HBox(button);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(splitPane);
root.setBottom(controls);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

Duplicate the view of a component in javafx

I am looking for a way to duplicate just the view of a component in javafx. This duplicate will not have any of the mouse or key events, and will basically be like a canvas.
As long as this duplicate doesn't change, I can use the snapshot(...) method that nodes have. My problem is that I want this to be dynamic. For example, I have one pane which displays some sort of animation (which can depend on user input), and I want a second pane which show the exact same image (but cannot have in itself user input like mouse presses).
The reflection effect is very specific case of what I need. Is there any way to do it in general?
One way to do it (which I used so far) is to just create a second duplicate component and connect all its input to the first. The problem is that this is a lot of work for every component that I want to copy, and it cannot be done generically.
A second way is just to take a snapshot every time the original component changes and copy it to the duplicate. This should be the solution, but I think that there is supposed to be a more low level solution instead of listening to changes, create an Image duplicate and then update an ImageView.
You could use some kind of binding. This is a basic example
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.control.Separator;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author blj0011
*/
public class JavaFXTestingGround extends Application
{
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
Circle circle = new Circle(0, 200, 25, Color.BLUE);
Circle duplicateCircle = new Circle(25, Color.BLUE);
#Override
public void start(Stage primaryStage)
{
duplicateCircle.centerXProperty().bind(circle.centerXProperty());
duplicateCircle.centerYProperty().bind(circle.centerYProperty());
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1.0 / 40.0), (ActionEvent t) -> {
circle.setCenterX(circle.getCenterX() + 1);
}));
timeline.setCycleCount(Timeline.INDEFINITE);
circle.setOnMouseClicked((t) -> {
switch (timeline.getStatus()) {
case STOPPED:
timeline.play();
break;
case RUNNING:
timeline.stop();
break;
}
});
Pane root = new Pane(circle);
primaryStage.setTitle("Test");
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
Pane duplicateRoot = new Pane(duplicateCircle);
Stage duplicatStage = new Stage();
duplicatStage.setScene(new Scene(duplicateRoot, 400, 400));
duplicatStage.setX(primaryStage.getX() + primaryStage.getWidth() + 10);
duplicatStage.setY(primaryStage.getY());
duplicatStage.show();
}
}

JavaFX Slider : How to drag the thumb only by increments

I am trying to implement the Slider such that user can drag only by given increments. I tried in different ways by using the Slider API, but didnt get the desired results. Below is a quick demo of what I had tried. I am expecting to drag the thumb only in increments of 10 not with intermediate values. snapToTicks is doing what I required, but only after finishing the drag. I am trying to not move the thumb till the next desired block increment is reached.
Can anyone let me know how can i achieve this. Below is the screenshot while dragging.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class SliderDemo extends Application {
public static void main(String... args){
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Label label = new Label();
label.setStyle("-fx-font-size:30px");
Slider slider = new Slider(5,240,5);
slider.setBlockIncrement(10);
slider.setMajorTickUnit(10);
slider.setMinorTickCount(0);
slider.setShowTickLabels(true);
slider.setShowTickMarks(true);
slider.setSnapToTicks(true);
slider.valueProperty().addListener((obs,old,val)->label.setText((int)Math.round(val.doubleValue())+""));
VBox root = new VBox(slider,label);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(20));
root.setSpacing(20);
Scene scene = new Scene(root,600,200);
stage.setScene(scene);
stage.show();
}
}
The solution is to set the value of the slider directly inside of the listener. The listener will not be called again
final ChangeListener<Number> numberChangeListener = (obs, old, val) -> {
final double roundedValue = Math.floor(val.doubleValue() / 10.0) * 10.0;
slider.valueProperty().set(roundedValue);
label.setText(Double.toString(roundedValue));
};
slider.valueProperty().addListener(numberChangeListener);
If you use Math.floor() instead of round you get a more intuatuive behavior of the thumb.

Javafx custom cursor reverts to system when hovering over background

I have added a default cursor:
someScene.setCursor(getSomeCursor());
This is working. I have this cursor-code working everywhere in my application, and it looks fine. But whenever I hover over a background GUI component, even if that background component, (be that a VBox, a Canvas or whatever), uses the correct cursor itself, the cursor reverts to the system cursor, instead of my custom cursor.
Any help appreciated.
Here is a complete worked example, which exactly produces the problem: the http link to that "blue cursor" was live at the time of posting. But please check if you get a problem reproducing.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.ImageCursor;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class CursorTest extends Application {
#Override
public void start(Stage stage) {
SomeDialog someDialog = new SomeDialog(stage);
GridPane root = new GridPane();
HBox buttonHolder= new HBox();
buttonHolder.setPrefSize(300,300);
Scene theScene = new Scene(root);
Canvas canvas = new Canvas();
canvas.setWidth(300);
canvas.setHeight(300);
canvas.getGraphicsContext2D().setFill(Color.RED);
canvas.getGraphicsContext2D().fillRoundRect(100, 100, 100, 100, 10, 10);
Image cursorImg = new Image("http://www.pngmart.com/files/3/Cursor-Arrow-PNG-Transparent-Image.png");
ImageCursor imageCursor = new ImageCursor(cursorImg);
theScene.setCursor(imageCursor);
stage.setTitle("Ribbon dialog");
stage.setScene(theScene);
VBox vBox = new VBox();
vBox.getChildren().add(canvas);
vBox.setSpacing(50);
Button button = new Button("Show modal");
button.setPadding(new Insets(30,30,30,30));
button.setOnMouseClicked(event -> {
someDialog.showMeAndWait();
});
buttonHolder.getChildren().add(button);
root.getChildren().addAll(vBox, buttonHolder);
stage.show();
}
class SomeDialog {
Stage newStage;
public SomeDialog(Stage primaryStage) {
newStage = new Stage();
GridPane gridPane = new GridPane();
Scene theScene = new Scene(gridPane);
Image cursorImg = new Image("http://www.pngmart.com/files/3/Cursor-Arrow-PNG-Transparent-Image.png");
ImageCursor imageCursor2 = new ImageCursor(cursorImg);
theScene.setCursor(imageCursor2);
theScene.setCursor(imageCursor2);
theScene.setFill(Color.TRANSPARENT);
newStage.initOwner(primaryStage);
newStage.initModality(Modality.APPLICATION_MODAL);
newStage.setTitle("Player inventory");
newStage.setScene(theScene);
newStage.initStyle(StageStyle.TRANSPARENT);
VBox vBox = new VBox();
Button someBtn = new Button("Close");
someBtn.setPadding(new Insets(100,100,100,100));
someBtn.setOnMouseClicked(event -> newStage.close());
vBox.getChildren().add(someBtn);
gridPane.getChildren().add(vBox);
}
public void showMeAndWait() {
newStage.showAndWait();
}
}
}

Add text under buttons in Dialog

I was wondering if there is a way to display some text (like a info) under the buttons of a Dialog ? I've looked in many places, but even to align the buttons seems messy (from this post).
This is what I got for now. I just want the "Set my choice ..." text under the 2 buttons.
I looked for a function in the documentation that could help me display the way I want (like "getButtonBar()" or something like that) with no chance. Also creating a new ButtonBar seems a bit complicated for what I want to achieve.
I also tried to create a stage that could look like a dialog, but I needed the result incoming from clicking "Yes / No" in the same way the Dialogs do.
Is there any way to achieve want I want ? Or do I have to build it completely myself ? Thanks !
Just override the createButtonBar() method of DialogPane:
DialogPane pane = new DialogPane() {
#Override
public Node createButtonBar() {
VBox vbox = new VBox(5);
vbox.setAlignment(Pos.BOTTOM_RIGHT);
vbox.setPadding(new Insets(5));
vbox.getChildren().add(super.createButtonBar());
vbox.getChildren().add(new Label("Additional text"));
return vbox ;
}
};
Here's a SSCCE:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CustomDialogPaneTest extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Show Dialog");
button.setOnAction(e -> {
DialogPane pane = new DialogPane() {
#Override
public Node createButtonBar() {
VBox vbox = new VBox(5);
vbox.setAlignment(Pos.BOTTOM_RIGHT);
vbox.setPadding(new Insets(5));
vbox.getChildren().add(super.createButtonBar());
vbox.getChildren().add(new Label("Additional text"));
return vbox ;
}
};
CheckBox checkBox = new CheckBox("A check box");
pane.setContent(checkBox);
pane.setHeaderText("The header");
pane.getButtonTypes().addAll(ButtonType.YES, ButtonType.NO);
Dialog<ButtonType> dialog = new Dialog<>();
dialog.setDialogPane(pane);
dialog.showAndWait().ifPresent(System.out::println);
});
StackPane root = new StackPane(button);
root.setPadding(new Insets(20));
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Why my Stage.close is not Working

Stage.close() is not working for me.
I've checked on:
JavaFX 2.0: Closing a stage (window)
Here is my codes:
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.stage.Modality;
public class MsgBox {
public Stage MessageBox(String Title, String Message){
VBox Pnl = new VBox();
Pnl.setPadding(new Insets(10,10,10,10));
Pnl.setSpacing(10);
Pnl.setAlignment(Pos.CENTER);
Label LblMsg = new Label(Message);
Button CmdOK = new Button("OK");
Pnl.getChildren().addAll(LblMsg, CmdOK);
Scene SCN = new Scene(Pnl);
Stage Window = new Stage();
Window.initModality(Modality.APPLICATION_MODAL);
Window.setTitle(Title);
Window.setScene(SCN);
Window.showAndWait();
CmdOK.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent ev){
Window.close();
}
});
return Window;
}
}
Here is the code that calls the Message Box Class:
CmdUpdate.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent ev){
new MsgBox().MessageBox("Hello", "Hello World");
}
});
Calling Stage#showAndWait waits until the stage closes before returning, so in fact the next line never gets a chance to run.
Move the line
Window.showAndWait();
to be the last in the method (crucially - after you set the handler to allow closing the stage), or else just use Stage#show, and your problem should be solved.

Resources