Is there a way to cut a Polygon if a part of it is getting out of it's AnchorPane?
I could try subtracting the Polygon with a rectangular shape but I wonder if there is a simpler way.
The image shows an example of a polygon getting out of the AnchorPane.
Edit: I tried setting max width and height to the AnchorPane, but it's not working.
You need to use clip.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ClipApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Polygon hexagon = new Polygon();
hexagon.getPoints().addAll(new Double[]{
50., 0.,
150.0, 0.,
200.0, 100.0,
150.0, 200.0,
50.0, 200.0,
0., 100.0,
});
hexagon.setFill(Color.YELLOW);
AnchorPane anchorPane = new AnchorPane(hexagon);
anchorPane.setStyle("-fx-background-color: purple");
anchorPane.setPrefSize(200, 200);
anchorPane.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
anchorPane.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
Rectangle rectangle = new Rectangle();
rectangle.widthProperty().bind(anchorPane.widthProperty());
rectangle.heightProperty().bind(anchorPane.heightProperty());
AnchorPane.setLeftAnchor(hexagon, 50.);
AnchorPane.setTopAnchor(hexagon, 50.);
StackPane stackPane = new StackPane(anchorPane);
stackPane.setStyle("-fx-background-color: blue");
stackPane.setPrefSize(400, 400);
Button button = new Button("Clip");
VBox vBox = new VBox(stackPane, button);
Scene scene = new Scene(vBox);
stage.setScene(scene);
stage.show();
button.setOnAction(event -> {
if (anchorPane.getClip() == null) {
button.setText("Unclip");
anchorPane.setClip(rectangle);
} else {
button.setText("Clip");
anchorPane.setClip(null);
}
});
}
}
Related
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();
}
}
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);
}
}
Is there any way to manage the z-index ordering of multiple stages (independent to each other). Something like, say there are three Stages A, B & C. StageA should stay always at back. StageB should be in middle and StageC should be always on top. Just a special note that these three stages have no relation to each other (like owner)
Below is a quick demo of what I am expecting. I need to access any stage (for dragging or modifying) but z-order need to be maintained. Any ideas or help is highly appreciated.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.HashMap;
import java.util.Map;
public class StagesZOrdering_Demo extends Application {
private Map<String, Stage> stages = new HashMap<>();
#Override
public void start(Stage stage) throws Exception {
Button button1 = new Button("Back");
button1.setOnAction(e -> openStage("Back"));
Button button2 = new Button("Middle");
button2.setOnAction(e -> openStage("Middle"));
Button button3 = new Button("Front");
button3.setOnAction(e -> openStage("Front"));
VBox root = new VBox(button1, button2, button3);
root.setAlignment(Pos.CENTER);
root.setSpacing(10);
Scene sc = new Scene(root, 200, 200);
stage.setScene(sc);
stage.show();
}
private void openStage(String title) {
if (stages.get(title) != null) {
stages.get(title).requestFocus();
} else {
Stage stg = new Stage();
stg.setTitle(title);
stg.setScene(new Scene(new StackPane(), 300, 300, Color.GRAY));
stg.show();
stg.setOnHidden(e -> stages.remove(title));
stages.put(title, stg);
}
}
public static void main(String... a) {
Application.launch(a);
}
}
The following mcve demonstrates re-ordering of back-to-front stages, once a ROOT MOUSE_EXITED_TARGET event is fired from one of them.
It is a simple yet limited solution:
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventType;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class StagesZOrdering_Demo extends Application {
public enum STAGES {BACK, MIDDLE, FRONT;}
private final EnumMap<STAGES, Stage> stages = new EnumMap<>(STAGES.class);
#Override
public void start(Stage stage) throws Exception {
VBox root = new VBox();
for(STAGES s : STAGES.values()){
Button button = new Button(s.name());
button.setOnAction(e -> openStage(s));
root.getChildren().add(button);
}
root.setAlignment(Pos.CENTER);
root.setSpacing(10);
Scene sc = new Scene(root, 200, 200);
stage.setScene(sc);
stage.show();
}
private void openStage(STAGES s) {
if (stages.get(s) == null) {
Stage stg = new Stage();
stg.setTitle(s.name());
stg.addEventHandler(EventType.ROOT, e->reOrder(e));
stg.setScene(new Scene(new StackPane(), 300, 100, Color.GRAY));
stg.show();
stg.setOnHidden(e -> stages.remove(s));
stages.put(s, stg);
}
}
private void reOrder(Event e){
if(! e.getEventType().getName().equals("MOUSE_EXITED_TARGET"))
return;
for(STAGES s : STAGES.values()){
Stage stage = stages.get(s);
if(stage != null) {
stage.requestFocus();
}
}
}
public static void main(String... a) {
Application.launch(a);
}
}
I have seen examples of Rectangle in JavaFx. But Please can anybody Provide me the example where in output window/Scene, if user put desirable width and height, rectangle should be generated automatically.
here is my example
VBox vb = new VBox(20);
HBox h1 = new HBox(7);
HBox h2 = new HBox(7);
Label lebel1 = new Label("X:");
Label lebel2 = new Label("Y:");
TextField txt1 = new TextField();
TextField txt2 = new TextField();
//Converting textfield to integer only
ChangeListener<String> forceNumberListener = (observable, oldValue, newValue) -> {
if (!newValue.matches("\\d*"))
((StringProperty) observable).set(oldValue);
};
txt1.textProperty().addListener(forceNumberListener);
txt2.textProperty().addListener(forceNumberListener);
double width = Double.parseDouble(txt1.getText());
double height = Double.parseDouble(txt2.getText());
Rectangle rect1 = new Rectangle();
rect1.setHeight(height);
rect1.setWidth(width);
h1.getChildren().addAll(lebel1, txt1);
h2.getChildren().addAll(lebel2, txt2);
vb.getChildren().addAll(h1,h2,rect1);
If user put any integer value in "x" as width, "y" as height, Rectangle should be generated below fields. but this code is wrong and i don't know other methods. Please
Thank you so much
You should use the TextField's onkeyreleased event handler. In this app, if both TextFields have a number typed in, a rectangle will be generated. Both TextFields have an event handler that does the same thing if one of their text is changed. This does not catch for any non-double values.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication104 extends Application
{
#Override
public void start(Stage primaryStage)
{
BorderPane root = new BorderPane();
VBox vbox = new VBox();
vbox.setMinWidth(100);
TextField textfield1 = new TextField();
TextField textfield2 = new TextField();
textfield1.setPrefWidth(50);
textfield1.setPromptText("Enter height");
textfield1.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textfield1.getText().length() > 0 && textfield2.getText().length() > 0)
{
Rectangle rectangle = new Rectangle();
rectangle.setHeight(Double.parseDouble(textfield1.getText()));
rectangle.setWidth(Double.parseDouble(textfield2.getText()));
rectangle.setFill(Color.BLUE);
root.setCenter(rectangle);
}
}
});
textfield2.setPrefWidth(100);
textfield2.setPromptText("Enter length");
textfield2.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textfield1.getText().length() > 0 && textfield2.getText().length() > 0)
{
Rectangle rectangle = new Rectangle();
rectangle.setHeight(Double.parseDouble(textfield1.getText()));
rectangle.setWidth(Double.parseDouble(textfield2.getText()));
rectangle.setFill(Color.BLUE);
root.setCenter(rectangle);
}
}
});
vbox.getChildren().addAll(textfield1, textfield2);
root.setLeft(vbox);
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
I'm trying to set an image from a stage snapshot as the stage icon.
The following code demonstrates it:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.io.IOException;
public class IconTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(new StackPane(new ImageView(generateIcon(32))));
primaryStage.setScene(scene);
primaryStage.getIcons().setAll(generateIcon(32));
primaryStage.show();
}
private static Image generateIcon(int dimension) throws IOException {
Pane root = new Pane();
root.setBackground(new Background(new BackgroundFill(Color.RED, null, null)));
Scene scene = new Scene(root, dimension, dimension);
return scene.snapshot(new WritableImage(dimension, dimension));
}
}
Result:
As you can see, the stage icon is not a red square. Why is that? Loading from a file always works, generating the image using AWT works, too.
Workaround:
BufferedImage bimg = new BufferedImage(dimension, dimension, BufferedImage.TYPE_INT_ARGB);
SwingFXUtils.fromFXImage(scene.snapshot(new WritableImage(dimension, dimension)), bimg);
SwingFXUtils.toFXImage(bimg, new WritableImage(dimension, dimension));