How to keep angle of DropShadow when node is rotated - javafx

When you apply a DropShadow on a node which is rotated, then the DropShadow rotates with it. Is there a simple way to keep the DropShadow angle where it is, e. g. bottom right even when the node is rotated?
I know that it would work if I put all the nodes into a group and apply the shadow on the group, but that's unfortunately not an option in my case.
Sample image:
left rectangle with drop shadow
right rectangle with same drop shadow, but rotated by 180 degrees
You see, it looks wrong with the shadows being in opposite directions.
Code
public class HelloEffects extends Application {
Stage stage;
Scene scene;
#Override
public void start(Stage stage) {
Group group = new Group();
DropShadow ds1 = new DropShadow();
ds1.setOffsetY(4.0f);
ds1.setOffsetX(4.0f);
ds1.setColor(Color.BLACK);
Rectangle rect1 = new Rectangle( 100, 200);
rect1.relocate(100, 100);
rect1.setEffect(ds1);
rect1.setFill(Color.RED);
Rectangle rect2 = new Rectangle( 100, 200);
rect2.relocate(300, 100);
rect2.setEffect(ds1);
rect2.setFill(Color.RED);
rect2.setRotate(180);
group.getChildren().addAll(rect1, rect2);
scene = new Scene( group, 840, 680);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}

You should add a container to rect2 and apply the effect on the container, the container can be either Pane or Group:
Group rect2Container = new Group(rect2);
rect2Container.setEffect(ds1);
group.getChildren().addAll(rect1, rect2Container);

Related

How to draw an equilateral triangle in JavaFX?

I'm trying to create a equilateral triangle with JavaFX. It is said that use the Polygon and setLayoutX() and setLayoutY(). So how to do that? This is the code I tried:
#Override public void start(Stage stage) throws Exception {
stage.setTitle("Board");
StackPane root = new StackPane();
Scene scene = new Scene(root, 600, 519);
stage.setScene(scene);
Polygon triangle = new Polygon();
stage.show();
}
Two problems:
You did not add the polygon to the container
You did not define the points of the polygon
Your code should be something like this:
#Override
public void start (Stage stage) throws Exception {
stage.setTitle("Board");
Polygon triangle = new Polygon();
//triangle.setLayoutX(100);
//triangle.setLayoutY(400);
triangle.getPoints()
.addAll(new Double[] {300.0, 50.0, 250.0, 100.0, 350.0, 100.0,});
Group root = new Group(triangle); // You can replace with StackPane for center alignment
Scene scene = new Scene(root, 600, 519);
stage.setScene(scene);
stage.show();
}
Once you do that, you should see something like the image below. You need to figure out the (x,y) coordinates for your triangle.
When I uncommented the setLayoutX() and setLayoutY() lines, the result was like the image below.
If you need a drawing in Java FX tutorial, check out this site.

JavaFX - Child Nodes Overlapping Parent Node (Parent's width smaller than children)

Below there is a quick sample of a JavaFX application where the brown region (parent node) contains two child nodes, a red square and a blue circle. When I am reducing the width of the parent node to a size smaller than those of its children, I was expecting the child nodes to be partially visible. However, this is not the case but instead the child nodes are shown fully over parent's region. Any ideas on how to achieve that on the below example?
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Parent Child Relationship!");
ParentNode parentNode = new ParentNode();
StackPane root = new StackPane();
root.getChildren().add(parentNode);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
class ParentNode extends Region {
private Rectangle square = new Rectangle();
private Circle circle = new Circle();;
public ParentNode() {
square.setWidth(40);
square.setHeight(40);
square.setFill(Color.RED);
circle.radiusProperty().bind(square.heightProperty().divide(3));
circle.centerXProperty().bind(circle.radiusProperty());
circle.centerYProperty().bind(square.heightProperty().divide(2));
circle.setFill(Color.BLUE);
circle.setStroke(Color.LIGHTGRAY);
getChildren().addAll(square, circle);
setBackground(new Background(new BackgroundFill(Color.CHOCOLATE, null, null)));
this.setMaxHeight(100);
this.setMaxWidth(200);
this.setMinHeight(0);
this.setMinWidth(0);
this.setOnMousePressed((e) -> this.setMaxWidth(20));
}
}
The only way i can think of, would be using a rectangle as the clip for the parentNode and binding its height and width to the parentNode's width and height properties, here is a working example:
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Parent Child Relationship!");
ParentNode parentNode = new ParentNode();
parentNode.maxWidthProperty().bind(primaryStage.widthProperty().subtract(200));
Rectangle clip = new Rectangle();
clip.widthProperty().bind(parentNode.widthProperty());
clip.heightProperty().bind(parentNode.heightProperty());
parentNode.setClip(clip);
StackPane root = new StackPane();
root.getChildren().add(parentNode);
primaryStage.setScene(new Scene(root, 400, 250));
primaryStage.show();
}
(i bound the parentNode's width to the windows width just so you see it working while you resize the window)

Box 3D JavaFX Rotate

I have two Boxes (Group), and when I rotate, the image displays like this:
Display Boxes
Rotate Boxes
When rotating, the Box (JANELA_MEIO_BOX) is distorted:
public class Demo1 extends Application {
private PhongMaterial texturedMaterial = new PhongMaterial();
private Image texture = new Image("/T3D/mapfooter.JPG");
private final PhongMaterial redMaterial = new PhongMaterial();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(final Stage stage) {
redMaterial.setSpecularColor(Color.ORANGE);
redMaterial.setDiffuseColor(Color.RED);
texturedMaterial.setDiffuseMap(texture);
javafx.scene.shape.Box JANELA_MEIO_BOX = new javafx.scene.shape.Box();
/* rotate */
JANELA_MEIO_BOX.setWidth(600.0);
JANELA_MEIO_BOX.setHeight(340.0);
JANELA_MEIO_BOX.setDepth(100.0);
JANELA_MEIO_BOX.setMaterial(texturedMaterial);
Group JANELA_001 = new Group();
stage.setTitle("Cube");
final CameraView cameraView = new CameraView();
final Scene scene = new Scene(cameraView, 1000, 800, true);
scene.setFill(new RadialGradient(225, 0.85, 300, 300, 500, false,
CycleMethod.NO_CYCLE, new Stop[]{new Stop(0f, Color.BLUE),
new Stop(1f, Color.LIGHTBLUE)}));
PerspectiveCamera camera = new PerspectiveCamera();
scene.setCamera(camera);
scene.setOnScroll((final ScrollEvent e) -> {
camera.setTranslateZ(camera.getTranslateZ() + e.getDeltaY());
});
javafx.scene.shape.Box JAN_MAIN = new javafx.scene.shape.Box();
JAN_MAIN.setMaterial(redMaterial);
JAN_MAIN.setWidth(1000.0);
JAN_MAIN.setHeight(600.0);
JAN_MAIN.setDepth(100.0);
JAN_MAIN.getTransforms().add(new Translate(1, 1, 1));
JANELA_MEIO_BOX.getTransforms().add(new Translate(1, 1, 1));
JANELA_001.getChildren().addAll(JAN_MAIN, JANELA_MEIO_BOX);
cameraView.add(JANELA_001);
/* mouse events */
cameraView.frameCam(stage, scene);
MouseHandler mouseHandler = new MouseHandler(scene, cameraView);
KeyHandler keyHandler = new KeyHandler(stage, scene, cameraView);
/* scene */
stage.setScene(scene);
stage.show();
}
When rotating, the Box (JANELA_MEIO_BOX) is distorted
You have two boxes: a 1000x600x100 cube, and a 600x340x100 cube.
When you put both of them in a group, they are placed in the center: the bigger one goes from -500 to 500 in X, -300 to 300 in Y, -50 to 50 in Z, and the same goes for the smaller one, also in Z from -50 to 50.
When you render two shapes with their faces in the same exact Z coordinate you will always get these artifacts.
One quick solution, if you want to see both shapes, is just making the smaller one a little bit deeper:
JANELA_MEIO_BOX.setDepth(100.1);
And it is also convenient that you set Scene Antialiasing to Balanced:
final Scene scene = new Scene(cameraView, 1000, 800, true, SceneAntialiasing.BALANCED);

JavaFX Node Snapshot X/Y Params Have To Be Negative

Execute the test below - the cyan rectangle is displayed centered. That's the intended result. However, why minX and minY of the viewport have to be negative values?
public class NodeScreenshotTest extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage stage)
{
stage.setScene(new Scene(createContent()));
stage.getScene().setFill(Color.BEIGE);
stage.setTitle(getClass().getSimpleName());
stage.show();
}
private Parent createContent()
{
BorderPane content = new BorderPane();
Rectangle rectangle = new Rectangle(50, 50);
rectangle.setFill(Color.AQUA);
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.YELLOW);
// Viewport x/y negative???
params.setViewport(new Rectangle2D(-15, -15, 80, 80));
ImageView iv = new ImageView(rectangle.snapshot(params, null));
content.setCenter(iv);
return content;
}
}
The origin (0,0) of the relevant coordinate system here is the upper left corner of the node for which you take the snapshot, i.e. the rectangle in your case. Now you seem to want a border arround your rectangle with a width of 15 raster units. So it's clear that your snapshot has to start at the location -15,-15 and has to have a width and height of 50 + 2*15.

Javafx - How to set drag range for components added in a pane

i have tried a below sample, in which left area of border Pane will have list of components and center of the border pane will act as a canvas area and here i have added a rectangle on run time as children to a Pane which is set to Center portion of BorderPane. But when drag the rectangle it moving outof the area allocated for the center, so how could i make this drag around only inside the Center Pane.
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("BPM");
BorderPane border = new BorderPane();
Pane canvas = new Pane();
canvas.setStyle("-fx-background-color: #F0F0F0;");
border.setLeft(compList());
border.setCenter(canvas);
//
Anchor start = new Anchor(null, "Start", Color.PALEGREEN, new SimpleDoubleProperty(170), new SimpleDoubleProperty(170));
final Rect rect=new Rect(100, 70,new SimpleDoubleProperty(10), new SimpleDoubleProperty(100));
rect.setX(100);
rect.setY(100);
canvas.getChildren().add(rect);
canvas.getChildren().add(start);
Scene scene = new Scene(border, 800, 600);
stage.setScene(scene);
stage.show();
}
Actually, by default, the Pane class does not ensure that all its children are clipping hence there are possibility that the children might go out of the boundary of the Pane. To ensure that all children (in your case, the rectangle) are dragged within specify boundary, you have to manually check the boundary as you dragging the children. Below are example of my implementation:
#Override
public void start(Stage stage){
stage.setTitle("BPM");
BorderPane mainPanel = new BorderPane();
VBox nameList = new VBox();
nameList.getChildren().add(new Label("Data"));
nameList.setPrefWidth(150);
Pane canvas = new Pane();
canvas.setStyle("-fx-background-color: #ffe3c3;");
canvas.setPrefSize(400,300);
Circle anchor = new Circle(10);
double rectWidth = 50, rectHeight = 50;
Rectangle rect = new Rectangle(50,50);
rect.setX(100);
rect.setY(100);
canvas.getChildren().addAll(rect, anchor);
// set the clip boundary
Rectangle bound = new Rectangle(400,300);
canvas.setClip(bound);
rect.setOnMouseDragged(event -> {
Point2D currentPointer = new Point2D(event.getX(), event.getY());
if(bound.getBoundsInLocal().contains(currentPointer)){
if(currentPointer.getX() > 0 &&
(currentPointer.getX() + rectWidth) < bound.getWidth()){
rect.setX(currentPointer.getX());
}
if(currentPointer.getY() > 0 &&
(currentPointer.getY() + rectHeight) < bound.getHeight()){
rect.setY(currentPointer.getY());
}
}
});
mainPanel.setLeft(nameList);
mainPanel.setCenter(canvas);
Scene scene = new Scene(mainPanel, 800, 600);
stage.setScene(scene);
stage.show();
}

Resources