How to stop transition when checkbox is unchecked javafx - javafx

So I've made a checkbox that applies a scale transition to a rectangle when checked. But the problem is that the transition keeps going even after I uncheck the checkbox. Any ideas on how to make it stop after un-checking?
checkbox.setOnAction(e -> {
ScaleTransition scaleT = new ScaleTransition(Duration.seconds(5), rectangle);
scaleT.setAutoReverse(true);
scaleT.setCycleCount(Timeline.INDEFINITE);
scaleT.setToX(2);
scaleT.setToY(2);
scaleT.play();
});

To control the animation, you need to define the transistion(with INDEFINITE cycle count) outside the CheckBox listener/action. Then you can just play/pause the animation as you required.
Below is the quick demo:
import javafx.animation.ScaleTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ScaleTransitionDemo extends Application {
#Override
public void start(Stage stage) {
Shape rectangle = new Rectangle(50, 50, Color.BLUE);
ScaleTransition transition = new ScaleTransition(Duration.seconds(1), rectangle);
transition.setDuration(Duration.seconds(1));
transition.setAutoReverse(true);
transition.setCycleCount(Timeline.INDEFINITE);
transition.setToX(3);
transition.setToY(3);
CheckBox checkBox = new CheckBox("Animate");
checkBox.selectedProperty().addListener((obs, old, selected) -> {
if (selected) {
transition.play();
} else {
transition.pause();
}
});
StackPane pane = new StackPane(rectangle);
VBox.setVgrow(pane, Priority.ALWAYS);
VBox root = new VBox(20, checkBox, pane);
root.setPadding(new Insets(10));
Scene scene = new Scene(root, 300, 300);
stage.setScene(scene);
stage.setTitle("Scale transition");
stage.show();
}
public static void main(String[] args) {
launch();
}
}

checking whether checkbox is selected or not with .isSelected() method . In this approach , scaled node will back to xy = 1 scale if checkbox is unchecked , but it will be disabled until transition ends .You can adjust setDuration . I've changed it just for gif recording. This is a single class javafx app you can try .
App.java
public class App extends Application {
#Override
public void start(Stage stage) {
Shape rectangle = new Rectangle(50, 50, Color.BLUE);
ScaleTransition scaleT = new ScaleTransition(Duration.seconds(1), rectangle);
CheckBox checkBox = new CheckBox("scale");
checkBox.setOnAction(e -> {
if (checkBox.isSelected()) {
scaleT.setDuration(Duration.seconds(1));
scaleT.setAutoReverse(true);
scaleT.setCycleCount(Timeline.INDEFINITE);
scaleT.setToX(2);
scaleT.setToY(2);
scaleT.play();
} else {
scaleT.setDuration(scaleT.getCurrentTime());
scaleT.stop();
scaleT.setCycleCount(1);
scaleT.setToX(1);
scaleT.setToY(1);
scaleT.play();
checkBox.setDisable(true);
scaleT.setOnFinished((t) -> {
checkBox.setDisable(false);
});
}
});
var scene = new Scene(new HBox(50, rectangle, checkBox), 640, 480);
stage.setScene(scene);
stage.setTitle("scale transition");
stage.show();
}
public static void main(String[] args) {
launch();
}
}

Related

How to force showing the popup part of a ComboBox in JavaFX

I want to be able to always show the popup part of a combobox regardless of the fact it has been clicked or not, or even without the combo being focused. I tried to use the show() method of the combo, but in my case the popup part never shows.
My code is:
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ComBoBoxTest {
public static final void main(String[] args) {
ComBoBoxTest test = new ComBoBoxTest();
test.setup();
}
private void setup() {
new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
createUI();
}
});
}
private void createUI() {
Stage stage = new Stage();
Pane pane = new Pane();
ComboBox<String> combo = new ComboBox();
ObservableList<String> values = combo.getItems();
values.add("ONE");
values.add("TWO");
values.add("THREE");
combo.setVisibleRowCount(3);
combo.show();
pane.getChildren().add(combo);
Scene scene = new Scene(pane);
stage.setScene(scene);
stage.show(); // the important part
}
}
In that case, I thought that my show() method would force to open the popup, but the result is that the popup is never shown
Per the excellent comment of kleopatra, the solution is to call show() on the Combo after the Stage is shown. This example works:
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ComBoBoxTest {
public static final void main(String[] args) {
ComBoBoxTest test = new ComBoBoxTest();
test.setup();
}
private void setup() {
new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
createUI();
}
});
}
private void createUI() {
Stage stage = new Stage();
Pane pane = new Pane();
ComboBox<String> combo = new ComboBox();
ObservableList<String> values = combo.getItems();
values.add("ONE");
values.add("TWO");
values.add("THREE");
combo.setVisibleRowCount(3);
pane.getChildren().add(combo);
Scene scene = new Scene(pane);
stage.setScene(scene);
stage.show();
combo.show(); // call show() on the Combo after the stage is shown
}
}

How to set popup scene mouse transparent in javafx

How to do that in JavaFX?
The popup shows up when the mouse enters a node. When the mouse enters the showing popup, the popup obscures the mouse from the node. Then the node fire exit event. How to make the popup ignore the mouse events?
code
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 300, 275));
Label labelNode = new Label("Label Node");
labelNode.setPrefHeight(200);
labelNode.styleProperty().set("-fx-background-color: orange");
Popup popup = new Popup();
popup.getScene().getRoot().setMouseTransparent(true);
AnchorPane popContent =new AnchorPane();
popContent.styleProperty().set("-fx-background-color: red");
popContent.setPrefHeight(100);
popContent.getChildren().add(new Label("Popup content"));
popup.getContent().add(popContent);
labelNode.setOnMouseEntered(event->{
Point3D point3D = labelNode.localToScene(event.getX(), event.getY(), 0);
popup.show(primaryStage, point3D.getX()-5, point3D.getY()-5);
});
labelNode.setOnMouseExited(event->{
popup.hide();
});
root.getChildren().add(labelNode);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Please try moving the cursor in to "yellow" several times.
Solution:
Keep two boolean nodeExited and popupExited statuses. Hide popup when both are true.
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
boolean nodeExited = false;
boolean popupExited = false;
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
primaryStage.setScene(new Scene(root, 300, 275));
Label labelNode = new Label("Label Node");
labelNode.setPrefHeight(200);
labelNode.styleProperty().set("-fx-background-color: orange");
Popup popup = new Popup();
popup.getScene().getRoot().setMouseTransparent(true);
AnchorPane popContent = new AnchorPane();
popContent.styleProperty().set("-fx-background-color: red");
popContent.setPrefHeight(100);
popContent.getChildren().add(new Label("Popup content"));
popup.getContent().add(popContent);
popup.getScene().setOnMouseEntered(event -> {
popupExited = false;
});
popup.getScene().setOnMouseExited(event -> {
popupExited = true;
if (nodeExited)
popup.hide();
});
labelNode.setOnMouseEntered(event -> {
nodeExited = false;
Point3D point3D = labelNode.localToScene(event.getX(), event.getY(), 0);
popup.show(primaryStage, point3D.getX() - 5, point3D.getY() - 5);
});
labelNode.setOnMouseExited(event -> {
nodeExited = true;
if (popupExited)
popup.hide();
});
root.getChildren().add(labelNode);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

How to clip and resize javafx borderpane

I am just starting with JavaFX. I want to have a BorderPane with controls on top, left, and right, and an image in the center. I want the center pane to resize as you resize the window, but to always be able to see all left, right, and top controls.
With the code below, I can show a button in the left, top, and right. And I can display an image in the center.
But the image expands beyond center bounds and hides the right button.
Oddly, if I set a clipping rectangle on the imageview in the center pane (uncomment lines 67 & 68), it does in fact only draw the clipped region, but the rest of the layout behaves as if it were drawing the whole picture. That is, the UNDRAWN part of the image still obscures the button on the right.
Any help would be much appreciated.
Thanks in advance and apologies if it's simple.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ImageApp extends Application {
private BorderPane root;
private Rectangle clipRect;
private ImageView iv;
private StackPane leftPane;
private StackPane rightPane;
private Button topButton;
private Button leftButton;
private Button rightButton;
#Override
public void start(Stage primaryStage) {
root = new BorderPane();
Scene primaryScene = new Scene(root, 900, 800);
initializePrimaryStage(primaryStage, primaryScene);
initializeFrameContent(root, topButton, leftButton);
initializeContent(root);
primaryStage.show();
}
private void initializeFrameContent(BorderPane root, Button topButton, Button leftButton) {
topButton = new Button("TOP");
leftButton = new Button("LEFT");
rightButton = new Button("RIGHT");
leftPane = new StackPane(leftButton);
leftPane.setAlignment(Pos.TOP_LEFT);
rightPane = new StackPane(rightButton);
rightPane.setAlignment(Pos.TOP_RIGHT);
root.setLeft(leftPane);
root.setTop(topButton);
root.setRight(rightButton);
}
private void initializePrimaryStage(Stage primaryStage, Scene primaryScene) {
primaryStage.setTitle("Image Clip Test");
primaryStage.setScene(primaryScene);
primaryStage.setWidth(400);
primaryStage.setHeight(300);
primaryStage.minWidthProperty().setValue(400);
primaryStage.minHeightProperty().setValue(300);
}
public static void main(String[] args) {
launch(args);
}
private void initializeContent(BorderPane root) {
Image image = new Image(
"http://www.ciee.org/study-abroad/images/cities/0020/headers/desktop/big-ben-london-traffic-trafalgar-abroad-studies.jpg"
);
iv = new ImageView(image);
root.setCenter(iv);
//clipRect = new Rectangle(400,200);
//root.getCenter().setClip(clipRect);
}
}
You don't specify what you intend to do. Why would you want to clip the content? The way you describe it all you want is some background that's getting clipped. You can do that with various mechanisms, e. g. css.
Or you could use a proper parent, e. g. a ScrollPane in order to limit the region or e. g. an ImageViewPane in order to stretch to fit:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ImageApp extends Application {
private BorderPane root;
private Rectangle clipRect;
private ImageView iv;
private StackPane leftPane;
private StackPane rightPane;
private Button topButton;
private Button leftButton;
private Button rightButton;
#Override
public void start(Stage primaryStage) {
root = new BorderPane();
Scene primaryScene = new Scene(root, 900, 800);
initializePrimaryStage(primaryStage, primaryScene);
initializeFrameContent(root, topButton, leftButton);
initializeContent(root);
primaryStage.show();
}
private void initializeFrameContent(BorderPane root, Button topButton, Button leftButton) {
topButton = new Button("TOP");
leftButton = new Button("LEFT");
rightButton = new Button("RIGHT");
leftPane = new StackPane(leftButton);
leftPane.setAlignment(Pos.TOP_LEFT);
rightPane = new StackPane(rightButton);
rightPane.setAlignment(Pos.TOP_RIGHT);
root.setLeft(leftPane);
root.setTop(topButton);
root.setRight(rightButton);
}
private void initializePrimaryStage(Stage primaryStage, Scene primaryScene) {
primaryStage.setTitle("Image Clip Test");
primaryStage.setScene(primaryScene);
primaryStage.setWidth(400);
primaryStage.setHeight(300);
primaryStage.minWidthProperty().setValue(400);
primaryStage.minHeightProperty().setValue(300);
}
public static void main(String[] args) {
launch(args);
}
private void initializeContent(BorderPane root) {
Image image = new Image(
"http://www.ciee.org/study-abroad/images/cities/0020/headers/desktop/big-ben-london-traffic-trafalgar-abroad-studies.jpg"
);
iv = new ImageView(image);
// ImageViewPane content = new ImageViewPane( iv);
ScrollPane content = new ScrollPane( imageView);
// hide scrollbars
content.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
content.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
content.setPadding(Insets.EMPTY);
root.setCenter(content);
}
// code from here: https://stackoverflow.com/questions/22993550/how-to-resize-an-image-when-resizing-the-window-in-javafx
class ImageViewPane extends Region {
private ObjectProperty<ImageView> imageViewProperty = new SimpleObjectProperty<ImageView>();
public ObjectProperty<ImageView> imageViewProperty() {
return imageViewProperty;
}
public ImageView getImageView() {
return imageViewProperty.get();
}
public void setImageView(ImageView imageView) {
this.imageViewProperty.set(imageView);
}
public ImageViewPane() {
this(new ImageView());
}
#Override
protected void layoutChildren() {
ImageView imageView = imageViewProperty.get();
if (imageView != null) {
imageView.setFitWidth(getWidth());
imageView.setFitHeight(getHeight());
layoutInArea(imageView, 0, 0, getWidth(), getHeight(), 0, HPos.CENTER, VPos.CENTER);
}
super.layoutChildren();
}
public ImageViewPane(ImageView imageView) {
imageViewProperty.addListener(new ChangeListener<ImageView>() {
#Override
public void changed(ObservableValue<? extends ImageView> arg0, ImageView oldIV, ImageView newIV) {
if (oldIV != null) {
getChildren().remove(oldIV);
}
if (newIV != null) {
getChildren().add(newIV);
}
}
});
this.imageViewProperty.set(imageView);
}
}
}

JavaFX How to 'hide' TitledPane back after expanding

I have TitledPane, which i want to hide back (after expanding - un-expand it) after pressing a button. Is there any way to do it? I didn't find any way :( Thanks!
Just do
titledPane.setExpanded(false);
Complete example:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TitledPaneExample extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label("Some content");
Button button = new Button("OK");
VBox content = new VBox(10, label, button);
TitledPane titledPane = new TitledPane("Titled Pane", content);
button.setOnAction(e -> titledPane.setExpanded(false));
VBox root = new VBox(titledPane);
Scene scene = new Scene(root, 250, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Back button that will open main Stage in Javafx 2

I have 2 screens in application. First screen(MainController class) which opens with running application from Eclipse.
And second screen(SecondController class) which opens on button located in first screen.
How can I make some kind of 'Back' button in second screen which will show back first screen?
I'm creating the visual part of the application in JavaFX Scene Builder if it matters.
Here is a small example, containing to screens, to show how you can achieve what you are looking for
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class TwoScreensWithInterchange extends Application {
#Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(loadScreenOne(), 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
public VBox loadScreenOne()
{
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
final Button button = new Button("Switch Screen");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
button.getScene().setRoot(loadScreenTwo());
}
});
Text text = new Text("Screen One");
vBox.getChildren().addAll(text, button);
vBox.setStyle("-fx-background-color: #8fbc8f;");
return vBox;
}
public VBox loadScreenTwo()
{
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
final Button button = new Button("Back");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
button.getScene().setRoot(loadScreenOne());
}
});
Text text = new Text("Screen Two");
vBox.getChildren().addAll(text, button);
return vBox;
}
}

Resources