I have seen the questions asked in this website about rotation in javafx but I don't seem to grasp it. Here is some code:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class TransformationsExample extends Application {
#Override
public void start(Stage stage) {
Rectangle rectangle = new Rectangle(50, 50, 100, 75);
rectangle.setFill(Color.BURLYWOOD);
rectangle.setStroke(Color.BLACK);
Rotate rotate = new Rotate();
rotate.setAngle(90);
rotate.setPivotX(150);
rotate.setPivotY(225);
rectangle.getTransforms().addAll(rotate);
Group root = new Group(rectangle);
Scene scene = new Scene(root, 1400, 780);
stage.setTitle("Transformations");
stage.setScene(scene);
stage.show();
}
public static void main(String args[]){
launch(args);
}
}
Why is it that when I change the angle, the rectangle starts appearing in random places? For example, when I set angle to 180, the rectangle appears in the middle. My understanding is that the rectangle moves in specified angle around X: 150 and Y:225. However, when I set the angle to 180, I am completely wrong. Can you guys help me out?
Edit: While reading and seeing the code answered to this question, I think I found a new question. How do you set a pivoting distance from pivotX and pivotY?
Edit2: This is for user #Slaw. I hope to know how you can find/set X?
If you replace the line
Group root = new Group(rectangle);
with the following two lines
Circle pivot = new Circle(150, 225, 5, Color.BLACK);
Group root = new Group(rectangle, pivot);
and then increment your angle in small steps 0, 10, 45, 90 degrees, the behaviour becomes clearer I think and is exactly what I would expect.
Related
It seems that when I move the circle outside the group of squares, it moves the squares even though there is no code that does that. I'm 99% percent sure it is because the group is trying to auto center itself, but it only does it if I change the scale of the group. Here is the code that demonstrates the problem I'm currently having.(Note that I don't want the square to move at all)
import javafx.application.Application;
import javafx.scene.shape.Circle;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.util.Duration;
import javafx.scene.layout.Pane;
import javafx.scene.Scene;
import javafx.event.EventHandler;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.stage.Stage;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;
public class Test extends Application
{
private static Circle circle = new Circle(0, 0, 10);
private static Group group = new Group(circle);
private static Group mainPane = new Group(group);
private Scene scene = new Scene(mainPane, 600, 600);
public void start(Stage stage){
circle.setViewOrder(-1);
for(int i = 0; i < 100; i++){
Rectangle backGround = new Rectangle(-10, -10, 20, 20);
backGround.setLayoutX((i - (int)(i * .1) * 10) * 20 - 100);
backGround.setLayoutY((int)(i * .1) * 20 - 100);
group.getChildren().add(backGround);
}
/*This line causes the problem*/group.setScaleX(1.5);
/*This line causes the problem*/group.setScaleY(1.5);
group.setLayoutX(200);
group.setLayoutY(200);
circle.setFill(Color.RED);
Timeline time = new Timeline();
time.setCycleCount(Timeline.INDEFINITE);
KeyFrame frame = new KeyFrame(Duration.millis(1), new EventHandler<ActionEvent>(){
#Override public void handle(ActionEvent e){
circle.setLayoutX(circle.getLayoutX() + .1);
if(circle.getLayoutX() > 150) circle.setLayoutX(0);
}
});
time.getKeyFrames().add(frame);
time.playFromStart();
stage.setScene(scene);
stage.show();
}
}
So I believe the problem is that scaleX / scaleY uses the center of the node as the pivot point. Combine that with the fact that the Group grows as the Circle moves to the right, and the scaling causes the Group to "move" because the new center becomes the pivot point.
When I replace:
/*This line causes the problem*/group.setScaleX(1.5);
/*This line causes the problem*/group.setScaleY(1.5);
With:
// javafx.scene.transform.Scale
Scale scale = new Scale(1.5, 1.5);
group.getTransforms().add(scale);
Your problem goes away. Unlike with scaleX / scaleY, the pivot point used by Scale is not automatically adjusted as the Group grows. Note the above Scale is using (0,0) as the pivot point. I assume that's okay, but if you want then you can set the pivot point to the initial center point of the Group (just don't constantly update the pivot point, or you'll probably run into the same problem as before).
I'm trying to teach myself JavaFX and tried to create a simple smiley face image. But for some reason all my shapes wind up centered instead of at the x&y coordinates that I constructed them with. I can't figure out why. Can anyone help me figure it out?
Here's my code:
import javafx.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class smiley extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) throws Exception {
Circle head = new Circle(250, 250, 150);
head.setFill(Color.YELLOW);
Circle eyeL = new Circle(200, 175, 25);
eyeL.setFill(Color.BLACK);
Circle eyeR = new Circle(300, 175, 25);
eyeR.setFill(Color.BLACK);
double[] points = { 250.0, 200.0, 250.0, 275.0, 290.0, 275.0 };
Polygon nose = new Polygon(points);
Arc smile = new Arc(275.0, 300.0, 75.0, 50.0, 180.0, 180.0);
smile.setStroke(Color.RED);
smile.setFill(Color.YELLOW);
StackPane smiley = new StackPane();
smiley.getChildren().add(head);
smiley.getChildren().add(eyeL);
smiley.getChildren().add(eyeR);
smiley.getChildren().add(nose);
smiley.getChildren().add(smile);
Scene scene = new Scene(smiley, 500, 500);
primaryStage.setTitle("Smiley");
primaryStage.setScene(scene);
primaryStage.show();
}
}
And this is what I wind up with
StackPane lays out its children on top of each other. Just think of a stack of pancakes. The last one goes on top and the first one is at the bottom. If you set a border/padding, then the children will by place in the center within those insets. Additionally, StackPane will resize all the children to fit the content area, but if that's not possible, it will then place it in the center. I don't think that this is your intent here, so try using the Pane class, which StackPane inherits from.
Pane pane = new Pane();
I am playing around with the 3d model importers from interactivemesh.org in Javafx. The import of the models in a scene works without error. However, the models are being displayed in a weird way. Some of the faces that are behind other faces are being displayed even though they should be covered by the front faces. I have tried the tdsImporter, as well as obj and the fxml importer, all encountered the same issue. The models are shown correctly in the model browser, so I guess something is wrong with my code. Here is what the model looks like (tried it on different computers):
The HST Model from interactivemesh.org
Also the source code I use for the 3ds import:
import com.interactivemesh.jfx.importer.tds.TdsModelImporter;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class Test3d extends Application {
Group group = new Group();
#Override
public void start(Stage meineStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene meineScene = new Scene(root, 1280, 800);
meineStage.setTitle("Startbildschirm");
meineStage.setScene(meineScene);
meineStage.show();
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.getTransforms().addAll(
new Rotate(0, Rotate.Y_AXIS),
new Rotate(-45, Rotate.X_AXIS),
new Rotate(-45, Rotate.Z_AXIS),
new Translate(0, 0, -110));
meineScene.setCamera(camera);
camera.setNearClip(0.1);
camera.setFarClip(200);
TdsModelImporter tdsImporter = new TdsModelImporter();
tdsImporter.read("hst.3ds");
Node[] tdsMesh = (Node[]) tdsImporter.getImport();
tdsImporter.close();
for (int i = 0; i < tdsMesh.length; i++) {
tdsMesh[i].setScaleX(0.1);
tdsMesh[i].setScaleY(0.1);
tdsMesh[i].setScaleZ(0.1);
tdsMesh[i].getTransforms().setAll(new Rotate(60, Rotate.Y_AXIS), new Rotate(-90, Rotate.X_AXIS));
}
Group root1 = new Group(tdsMesh);
meineScene.setRoot(root1);
}
public static void main(String[] args) {
launch(args);
}
}
Does anybody have an idea what the problem could be and how to fix it?
According to the Scene javadoc:
An application may request depth buffer support or scene anti-aliasing support at the creation of a Scene. [...] A scene containing 3D shapes or 2D shapes with 3D transforms may use depth buffer support for proper depth sorted rendering; [...] A scene with 3D shapes may enable scene anti-aliasing to improve its rendering quality.
The depthBuffer and antiAliasing flags are conditional features. With the respective default values of: false and SceneAntialiasing.DISABLED.
So in your code, try:
Scene meineScene = new Scene(root, 1280, 800, true);
or even better:
Scene meineScene = new Scene(root, 1280, 800, true, SceneAntialiasing.BALANCED);
I want to draw a line passing through a circle. However, I do not want the line to be shown while its inside the circle. How can I accomplish this? Note that I'm drawing the circle first and then the line.
I used a couple of things like:
Circle.setOpacity to 1, which didn't help!
Used line.toBack() after adding the circle and line in the same group. This didnt help either
line.toBack()
line.toFront()
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class LineUnderCircle extends Application {
#Override
public void start(Stage stage) throws Exception {
Line line = new Line(10, 10, 50, 50);
line.setStrokeWidth(3);
Circle left = new Circle(10, 10, 8, Color.FORESTGREEN);
Circle right = new Circle(50, 50, 8, Color.FIREBRICK);
Button lineToBack = new Button("Line to back");
lineToBack.setOnAction(e -> line.toBack());
Button lineToFront = new Button("Line to front");
lineToFront.setOnAction(e -> line.toFront());
Pane shapePane = new Pane(line, left, right);
HBox controlPane = new HBox(10, lineToBack, lineToFront);
VBox layout = new VBox( 10, controlPane, shapePane);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In JavaFX 8 I would like to specify the css to rotate a Label so that instead of the text going from left to right, it goes from bottom to top.
How can I do that?
Any node can have it's rotation styled via CSS using the -fx-rotate css attribute.
This is the angle of the rotation in degrees. Zero degrees is at 3 o'clock (directly to the right). Angle values are positive clockwise. Rotation is about the center.
So in your code or FXML you can have:
label.setStyle("vertical");
And in your css stylesheet you can define:
.vertical { -fx-rotate: -90; }
Also note James_D's answer suggestion of wrapping the label in a Group to account for the rotation when performing layout bounds calculations.
Call setRotate on the label to rotate it about its center.
To allow layout panes to properly measure the bounds of the label after rotation, wrap it in a Group:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class RotatedLabelTest extends Application {
#Override
public void start(Stage primaryStage) {
Label label1 = new Label("Hello");
Label label2 = new Label("World");
label1.setRotate(-90);
Group labelHolder = new Group(label1);
HBox root = new HBox(5, labelHolder, label2);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 250, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You can easily set a label's rotation by specifying the degrees of rotation as per the code below:
label.setRotate(45)
for 45 degrees, for example.
if you want to set it after some operations, that is, after the label has been displayed in the User Interface, you can use
Platform.runLater() lambda expression.
i.e
Platform.runLater(()->
label.setRotate(45);
)