I am starting to learn JavaFX
now when I try to rotate the image view using
imgv.setRotate(angle);
it rotates around its central axis
but when I try to rotate it around a custom point inside the image
using
imgv.getTransforms().add(new Rotate(Angle,custom_x,custom_y);
it rotates randomly and I can't figure its axis of the rotation
this was the same as
imgv.getTransforms().add(new Rotate(Angle,custom_x,custom_y,1.0,Rotate.Z_AXIS);
is there any way to rotate the image around a custom point
here is image explaining the position of a point if (0,0) was at the top left or at the center of the image both way I can't rotate the image around that point according to x,y
I know that I can rotate around the origin then do translation but am asking if there is a speedway to do that
thanks in advance
Here is an app that demonstrates how to accomplish what you are asking. The key parts of accomplishing this are .getTransforms().add(..) and Rotate. Comments in the code. I added the Circle so that you can actually see where the point of rotation is located.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication117 extends Application
{
#Override
public void start(Stage primaryStage)
{
Image image = new Image("http://lmsotfy.com/so.png");
ImageView imageView = new ImageView(image);
imageView.setFitHeight(400);
imageView.setFitWidth(400);
Button btn = new Button();
btn.setText("Say 'Hello World'");
//Use this Circle to help see where the rotation occurs
Circle circle = new Circle(5);
circle.setFill(Color.RED);
circle.setCenterX(100);
circle.setCenterY(300);
//Add the Rotate to the ImageView's Transforms
Rotate rotation = new Rotate();
rotation.setPivotX(circle.getCenterX());//Set the Pivot's X to be the same location as the Circle's X. This is only used to help you see the Pivot's point
rotation.setPivotY(circle.getCenterY());//Set the Pivot's Y to be the same location as the Circle's Y. This is only used to help you see the Pivot's point
imageView.getTransforms().add(rotation);//Add the Rotate to the ImageView
//Use the Button's handler to rotate the ImageView
btn.setOnAction((ActionEvent event) -> {
rotation.setAngle(rotation.getAngle() + 15);
});
Pane pane = new Pane();
pane.getChildren().addAll(imageView, circle);
VBox.setVgrow(pane, Priority.ALWAYS);
VBox vBox = new VBox(pane, new StackPane(btn));
StackPane root = new StackPane();
root.getChildren().add(vBox);
Scene scene = new Scene(root, 1080, 720);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Related
Hi I am a JavaFX newbie and I am trying to write my first application. I want to start with an empty window and provide a popup menu that allows users to add 3D elements to the window.
I have created a simple Group containing a few trivial geometric shapes and added this group as the parent to a Scene. I define a mouse event handler for the scene and call setScene to make this the scene for my Stage (passed in to my Application's start method).
Unfortunately, I can't seem to find a way of positioning the menu correctly in response to a mouse pressed event. I get it that I need to get the X and Y coordinates from the Event, but when I pass these unchanged to the context menu show method, the menu appears in the top left-hand corner of my laptop display, rather than inside my application window.
Clearly, I need to offset these values by the origin of some other window, but what? I have tried the Scene, the Group and and the Stage, but with no success :-( This ought to be a trivial problem - where am I going wrong??
Code sample shown below:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Box;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;
public class PopupTest extends Application {
private static final ContextMenu contextMenu = new ContextMenu();
public static void main(String[] args) {
MenuItem cut = new MenuItem("Cut");
MenuItem copy = new MenuItem("Copy");
MenuItem paste = new MenuItem("Paste");
contextMenu.getItems().addAll(cut, copy, paste);
Application.launch(args);
}
#Override
public void start(Stage stage) {
// Create a Box
Box box = new Box(100, 100, 100);
box.setTranslateX(150);
box.setTranslateY(0);
box.setTranslateZ(400);
// Create a Sphere
Sphere sphere = new Sphere(50);
sphere.setTranslateX(300);
sphere.setTranslateY(-5);
sphere.setTranslateZ(400);
// Create a Cylinder
Cylinder cylinder = new Cylinder(40, 120);
cylinder.setTranslateX(500);
cylinder.setTranslateY(-25);
cylinder.setTranslateZ(600);
// Create a Light
PointLight light = new PointLight(Color.YELLOW);
light.setTranslateX(350);
light.setTranslateY(100);
light.setTranslateZ(300);
// Create a Camera to view the 3D Shapes
PerspectiveCamera camera = new PerspectiveCamera(false);
camera.setTranslateX(100);
camera.setTranslateY(-50);
camera.setTranslateZ(300);
// Add the Shapes and the Light to the Group
Group root = new Group(box, sphere, cylinder, light);
// Create a Scene with depth buffer enabled
Scene scene = new Scene(root, 400, 300, true);
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("mouse click detected!");
if (event.isPopupTrigger()) {
// similar results with getX() vs getSceneX() etc.
System.out.println("Display menu at (" + event.getSceneX() + "," + event.getSceneY() + ")");
contextMenu.show(root, event.getSceneX(), event.getSceneY());
}
}
});
// Add the Camera to the Scene
scene.setCamera(camera);
// Add the Scene to the Stage
stage.setScene(scene);
// Set the Title of the Stage
stage.setTitle("Trying to get popup menu working");
// Display the Stage
stage.show();
}
}
In this program, I am trying to make rect turn red when x== 600 in the for-loop. What basically happens is that the for-loop runs faster than the animation on the screen. The rectangle ends up turning red before it actually hits that certain point within the JavaFX screen.
What I would like it to do it that when it hits point x,y:(600,500), make the blue rectangle turn red.
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author Owner
*/
public class TestPoint extends Application {
#Override
public void start(Stage primaryStage) {
Pane root = new Pane();
Scene scene = new Scene(root, 1000, 1000);
Rectangle rect = new Rectangle();
Rectangle rectTwo = new Rectangle();
//Obstacle that other square must hit
rectTwo.setWidth(100);
rectTwo.setHeight(100);
rectTwo.setX(500);
rectTwo.setY(500);
rectTwo.setFill(Color.PINK);
//for loop that causes the animation to properly move
for (int x = 800; x >= 0; x--) {
rect.setWidth(100);
rect.setHeight(100);
rect.setX(800);
rect.setY(500);
rect.setFill(Color.BLUE);
Timeline timeline = new Timeline();
timeline.setCycleCount(1);
timeline.setAutoReverse(true);
final KeyValue kv = new KeyValue(rect.xProperty(), x);
final KeyFrame kf = new KeyFrame(Duration.seconds(8), kv);
timeline.getKeyFrames().add(kf);
timeline.play();
//if it hits the point of rectTwo, change to Color.RED
System.out.println(x);
if (x == 600) {
rect.setFill(Color.RED);
break;//end
}
}
root.getChildren().addAll(rect, rectTwo);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
You misunderstood, how Timeline works. Your code creates 201 Timeline animations running in parallel. The loop is done before the window is shown. Any updates are automatically triggered by JavaFX later.
Specifying the initial state and the target state via KeyFrames is sufficient. KeyFrames allow you to specify a handler to be executed at a specific time; this can be used to change the color. Alternatively the onFinished handler could be used for coloring the Rectangle.
rect.setWidth(100);
rect.setHeight(100);
rect.setY(500);
rect.setFill(Color.BLUE);
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rect.xProperty(), 800)),
new KeyFrame(Duration.seconds(8),
evt -> rect.setFill(Color.RED),
new KeyValue(rect.xProperty(), 600)));
timeline.play();
I want to simulate perspective distortion of boxes and rectangles. My goal is to warp the box and image, as if the camera is being tilted and moved. But I don't really follow how to use the PerspectiveCamera.
When I set the fixedEyeAtCameraZero to false, I can see the box and image on screen. But changing the window size causes weird orthographic perspective changes that aren't realistic.
On the other hand when I set fixedEyeAtCameraZero to true, all I see is a blank window.
False:
True:
Here's the code, with the offending flag at line 51.
package sample;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class Example_Box extends Application {
#Override
public void start(Stage stage) {
//Drawing a Box
Box box2 = new Box();
//Setting the properties of the Box
box2.setWidth(100.0);
box2.setHeight(100.0);
box2.setDepth(100.0);
//Setting the position of the box
box2.setTranslateX(30); //450
box2.setTranslateY(90);//150
box2.setTranslateZ(300);
//Setting the drawing mode of the box
box2.setDrawMode(DrawMode.LINE);
//Drawing an Image
Image image = new Image("Lenna.png");
ImageView imageView = new ImageView(image);
imageView.setTranslateX(200);
imageView.setTranslateY(150);
imageView.setTranslateZ(200);
//imageView.getTransforms().add(new Rotate(30, 50, 30));
//Creating a Group object
Group root = new Group(box2, imageView);
//Creating a scene object
Scene scene = new Scene(root, 600, 300);
//Setting camera
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setTranslateX(30);
camera.setTranslateY(0);
camera.setTranslateZ(-100);
camera.setRotationAxis(new Point3D(1,0,0));
scene.setCamera(camera);
//Setting title to the Stage
stage.setTitle("Drawing a Box");
//Adding scene to the stage
stage.setScene(scene);
//Displaying the contents of the stage
stage.show();
}
public static void main(String args[]){
launch(args);
}
}
Try to change the farClip value. By default farClip value is 100 in FX perspective camera.
camera.setFarClip(2000.0);
With above piece code addition, I could see the Box. If I move the camera further away(in Z direction), I could see Image also,
camera.setTranslateZ(-1000);
Reference: http://www.dummies.com/programming/java/javafx-add-a-perspective-camera/
I have applied a JavaFx Rotation to a rectangle using the constructor that allows you to set the pivot
new Rotate(45, 15, 15)
This rotates the rectangle but it rotates around the top left corner at 15,15 on the AnchorPane in which it is placed. Is it possible to rotate a rectangle around a point that acts like the center of a circle and the rectangle rotates around the circumfrence. Like the rectangle is a piece of tread on a tire that rotates around the central pivot. Thanks heaps.
This works for me, I am not sure what you are doing though.
package helloworld;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import java.time.Duration;
/**
* Created by Matt on 25/08/16.
*/
public class RotatingARectangle extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Group root = new Group();
Rectangle rect = new Rectangle(190, 395, 20, 5);
rect.setFill(Color.BLUE);
Rotate rot = new Rotate(0, 200, 200);
rect.getTransforms().add(rot);
Ellipse path = new Ellipse(200, 200, 200, 200);
path.setStroke(Color.RED);
path.setFill(null);
root.getChildren().add(rect);
root.getChildren().add(path);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
Timeline line = new Timeline(30);
KeyFrame key1 = new KeyFrame(
new javafx.util.Duration(0),
new KeyValue(rot.angleProperty(), 0 )
);
KeyFrame key2 = new KeyFrame(
new javafx.util.Duration(1000),
new KeyValue(rot.angleProperty(), 360 )
);
line.getKeyFrames().addAll(key1, key2);
scene.addEventHandler(MouseEvent.MOUSE_CLICKED, evt->{
line.playFromStart();
});
}
}
I set the pivot to be the center of the elipse, then use a timeline to change the angle from 0 to 360.
Suppose we have a rectangle called r
Rectangle r = new Rectangle(40, 20);
and an image called image
Image image = new Image("...src for image");
How do I fit the image inside the rectangle? Also, how can I make the image move if the rectangle moves too? How do I do the same thing for a circle? Code examples are greatly appreciated.
P.S. Jewelsea, I'm waiting for you, lol!
if you want to fill Rectangle by image, you can follow this:-
in your fxml file add a Circle
<Rectangle fx:id="imgMenuUser" />
And in your Controller
#FXML
private Rectangle rectangle;
Image img = new Image("/image/rifat.jpg");
rectangle.setFill(new ImagePattern(img));
How do I fit the image inside the rectangle?
Put the shape and the image in a StackPane.
Also, how can I make the image move if the rectangle moves too?
Just move the StackPane.
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Point2D;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
StackPane imageContainer = new StackPane();
ImageView image = new ImageView(...);
imageContainer.getChildren().addAll(new Rectangle(64, 48, Color.CORNFLOWERBLUE), image);
enableDragging(imageContainer);
root.getChildren().add(imageContainer);
Scene scene = new Scene(root,800,600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
private void enableDragging(Node node) {
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
node.setOnMousePressed( event -> mouseAnchor.set(new Point2D(event.getSceneX(), event.getSceneY())));
node.setOnMouseDragged( event -> {
double deltaX = event.getSceneX() - mouseAnchor.get().getX();
double deltaY = event.getSceneY() - mouseAnchor.get().getY();
node.relocate(node.getLayoutX()+deltaX, node.getLayoutY()+deltaY);
mouseAnchor.set(new Point2D(event.getSceneX(), event.getSceneY()));;
});
}
public static void main(String[] args) {
launch(args);
}
}