I have simple code that draws a circle and prints Hello World! text. Currently the text is inside the circle, while I want it to be below it. Both circle and text are inside a Group.
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class CircleArc extends Application {
#Override
public void start(Stage applicationStage) {
ScrollPane scrollPane = new ScrollPane();
scrollPane.setFitToWidth(true);
FlowPane flowPane = new FlowPane();
flowPane.setOrientation(Orientation.HORIZONTAL);
Circle circle = new Circle(100);
circle.setFill(Color.GREEN);
double rate = 0.6;
Arc arc = new Arc(0, 0, 100, 100,
0, -360*rate);
arc.setType(ArcType.ROUND);
arc.setFill(Color.GRAY);
Text text = new Text("Hello World!");
text.setLayoutX(text.getLayoutX() / 2);
text.setLayoutY(text.getLayoutY());
Group group = new Group();
group.getChildren().add(circle);
group.getChildren().add(arc);
group.getChildren().add(text);
flowPane.getChildren().add(group);
scrollPane.setContent(flowPane);
Scene scene = new Scene(scrollPane);
applicationStage.setScene(scene);
applicationStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
It currently looks like this:
However I want it to look like this:
I tried using the setLayout methods but they didn't work.
EDIT:
Turned out the simple
text.setLayoutX(text.getLayoutX() - 50);
text.setLayoutY(text.getLayoutY() + 120);
worked well enough.
Use a Label. Set the circle as the graphic, position the text underneath.
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
stage.setTitle("Centered Text Under Graphic");
Circle circle = new Circle(100);
circle.setFill(Color.GREEN);
double rate = 0.6;
Arc arc = new Arc(0, 0, 100, 100,
0, -360 * rate);
arc.setType(ArcType.ROUND);
arc.setFill(Color.GRAY);
Group circles = new Group(circle, arc);
Label label = new Label("Hello World!", circles);
label.setContentDisplay(ContentDisplay.TOP);
Pane p = new Pane(label);
Scene scene = new Scene(p);
stage.setScene(scene);
stage.show();
}
}
That will handle keeping the text centered if it changes.
Related
I'm just looking to make my red rectangle jump up when you press that jump button. I can't really seem to find any thing like an animation or even a go up, wait a certain amount of time and then come back down.
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.Button;
import javafx.event.EventHandler;
import javafx.event.ActionEvent;
import javafx.animation.PathTransition;
import javafx.scene.shape.*;
import javafx.util.Duration;
public class GUIPractice extends Application{
public static void main (String [] args)
{
launch(args);
}
public void start (Stage primaryStage)
{
Rectangle screen = new Rectangle(20, 20, 986, 500);
Button JumpBtn = new Button("Jump");
JumpBtn.setLayoutX(410);
JumpBtn.setLayoutY(530);
JumpBtn.setMinWidth(200);
JumpBtn.setMinHeight(100);
Rectangle player = new Rectangle(450, 420, 50, 100);
player.setFill(Color.RED);
Path path = new Path();
I believe right here below is where the jumping would go but the only thing I could figure out is how to get the rectangle to move up on the screen and not move back down.
JumpBtn.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e) {
player.setTranslateY(-40);
}
});
Group root = new Group(screen, JumpBtn, player);
Scene scene = new Scene(root, 1024, 768);
scene.setFill(Color.GREY);
primaryStage.setTitle("GUIPractice");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Use a animation such as timeline to move the Node, e.g.
double ty = player.getTranslateY();
// quadratic interpolation to simulate gravity
Interpolator interpolator = new Interpolator() {
#Override
protected double curve(double t) {
return t * (2 - t);
}
};
Timeline timeline = new Timeline(new KeyFrame(Duration.ZERO,
new KeyValue(player.translateYProperty(), ty, interpolator)),
new KeyFrame(Duration.seconds(1),
new KeyValue(player.translateYProperty(), ty-40, interpolator)));
// play forward once, then play backward once
timeline.setCycleCount(2);
timeline.setAutoReverse(true);
JumpBtn.setDisable(true);
timeline.setOnFinished(evt -> JumpBtn.setDisable(false));
timeline.play();
I'm having some difficulty with ScrollPane in JavaFX 8 showing the scrollbar as needed. What I'm currently doing is simply creating a FlowPane with x number of elements, and setting that as the content of the ScrollPane.
The problem happens when I shrink down perpendicular to the orientation of the FlowPane. When elements begin to wrap and go out of bounds, the scrollbar does not appear. This does not happen when I shrink parallel to the orientation. I have a small Java program to exemplify the issue.
Start
Shrinking Parallel
Shrinking Perpendicular
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FlowPane flow = new FlowPane();
flow.setStyle("-fx-border-color: red");
addPanes(flow, 16);
ScrollPane scroll = new ScrollPane(flow);
scroll.setStyle("-fx-border-color: green");
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
Scene scene = new Scene(scroll, 450, 450);
primaryStage.setScene(scene);
primaryStage.show();
}
public void addPanes(FlowPane root, int panes) {
for(int i = 0; i < panes; i++) {
StackPane filler = new StackPane();
filler.setStyle("-fx-border-color: black");
filler.setPrefSize(100, 100);
root.getChildren().add(filler);
}
}
}
Have a look at the code below and tell me if that's what you want to achieve. I am still not sure what cause the problem, I will have to look the documentation of ScrollPane to find out. My suspicion is at setFitToWidth & setFitToHeight methods. Although I still believe it's not a bug.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FlowPane flow = new FlowPane();
flow.setStyle("-fx-border-color: red");
addPanes(flow, 16);
ScrollPane scroll = new ScrollPane(flow);
scroll.setStyle("-fx-border-color: green");
// Apparently this cause the issue here.
// scroll.setFitToHeight(true);
// scroll.setFitToWidth(true);
// Instead just make the flow pane take the dimensions of the ScrollPane
// the -5 is to not show the Bars when both of panes have the same dimensions
flow.prefWidthProperty().bind(Bindings.add(-5, scroll.widthProperty()));
flow.prefHeightProperty().bind(Bindings.add(-5, scroll.heightProperty()));
Scene scene = new Scene(scroll, 450, 450);
primaryStage.setScene(scene);
primaryStage.show();
}
public void addPanes(FlowPane root, int panes) {
for (int i = 0; i < panes; i++) {
HBox filler = new HBox();
filler.setStyle("-fx-border-color: black");
filler.setPrefSize(100, 100);
root.getChildren().add(filler);
}
}
}
Looking documentation of the ScrollPane, and in specific the setFitToHeight you will find that :
Property description:
If true and if the contained node is a
Resizable, then the node will be kept resized to match the height of
the ScrollPane's viewport. If the contained node is not a Resizable,
this value is ignored.
And because the node inside the ScrollPane will be kept resized to match the width and height of the ScrollPane's viewport thats why the Vertical ScrollBar will never appear.
You can add the code below to always show your vertical scrollbar.
scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
When the required height of the FlowPane inside the ScrollPane is calculated a width value of -1 is passed. The flow pane will then report the height required when all its content fits into a single line.
As a workaround you could pass the width from the last layout calculation in this case.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FlowPane flow = new FlowPane() {
#Override protected double computeMinHeight(double width) {
double minHeight = super.computeMinHeight(width != -1 ? width :
/* When no width is specified, use the current contol size*/
getWidth());
return minHeight;
}
};
flow.setStyle("-fx-border-color: red");
addPanes(flow, 16);
ScrollPane scroll = new ScrollPane(flow);
flow.maxWidthProperty().bind(scroll.widthProperty());
scroll.widthProperty().addListener((observable, oldValue, newValue)->{
/* clearSizeCache */
flow.requestLayout();
});
scroll.setStyle("-fx-border-color: green");
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
Scene scene = new Scene(scroll, 450, 450);
primaryStage.setScene(scene);
primaryStage.show();
}
public void addPanes(FlowPane root, int panes) {
for(int i = 0; i < panes; i++) {
StackPane filler = new StackPane();
filler.setStyle("-fx-border-color: black");
filler.setPrefSize(100, 100);
root.getChildren().add(filler);
}
}
}
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.
I am using RotateTransiton to rotate a line, but it seems to rotate through center of the line. I would like to rotate it with pivot as one end of the line. How to do this?
The RotateTransition works by changing the rotate property, which - as you have observed - defines a rotation around the center of the Node.
If you want to rotate around a different point, define a Rotate transform, set its pivot, add it to the line's list of transforms, and use a Timeline to manipulate its angle.
Here's an example:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
public class RotateLineAboutEnd extends Application {
#Override
public void start(Stage primaryStage) {
Line line = new Line(200, 200, 200, 350);
Pane pane = new Pane(line);
Rotate rotation = new Rotate();
rotation.pivotXProperty().bind(line.startXProperty());
rotation.pivotYProperty().bind(line.startYProperty());
line.getTransforms().add(rotation);
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rotation.angleProperty(), 0)),
new KeyFrame(Duration.seconds(1), new KeyValue(rotation.angleProperty(), 360)));
Button button = new Button("Rotate");
button.setOnAction(evt -> timeline.play());
button.disableProperty().bind(timeline.statusProperty().isEqualTo(Animation.Status.RUNNING));
HBox controls = new HBox(button);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(12));
BorderPane root = new BorderPane(pane, null, null, controls, null);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
(on JavaFX 2.2 and JavaFX 8)
The best way in my opinion is translating the layoutBounds of the node (which contains the pivot point) and translating the node itself the opposite way.
An example:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Group root = new Group();
primaryStage.setScene(new Scene(root, 140, 140));
Rectangle rect = new Rectangle(1, 1, 40, 40);
// comment movePivot to get the default rotation
movePivot(rect, -20, -20);
RotateTransition rt = new RotateTransition(Duration.seconds(4),rect);
rt.setToAngle(720);
rt.setCycleCount(Timeline.INDEFINITE);
rt.setAutoReverse(true);
rt.play();
primaryStage.show();
}
// this is the function you want
private void movePivot(Node node, double x, double y){
node.getTransforms().add(new Translate(-x,-y));
node.setTranslateX(x); node.setTranslateY(y);
}
public static void main(String[] args) {
launch(args);
}
}
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);
}
}