I have done animations in FlashProfessional (CS 6), which sucks by the way (crashes constantly without saving last modifications, produces enormous files, works inconsistently and so on). I have hard time to figure out how the following simple task can be done in JavaFX 2.x (probably because my background is in Flash): a rectangle that exists in a constant location from t=0 to t=100, and after that it is deleted from the Scene.
In Flash, I could create a keyframe at t=0 in which I draw a rectangle. Then I create second keyframe at t=100 in which the rectangle is deleted. That simple.
In JavaFX, why I can’t just write timeline.getKeyFrames().addAll(new KeyFrame(new Duration(100), new Rectangle(10, 10, 25, 25))); or like.
Please help me and provide the code. I’m lost in these KeyValues and Java properties, why I need those anyway…
To achieve that task you can just remove rectangle after 100 ms. JavaFX unlike Flash is not built about keyframes -- they are optional functionality and used only if you need real animation, e.g. scaling of an object. See next tutorial for more info: http://docs.oracle.com/javafx/2/animations/jfxpub-animations.htm
And demonstrating code:
public void start(Stage primaryStage) {
final Rectangle rect1 = new Rectangle(10, 70, 50, 50);
final Rectangle rect2 = new Rectangle(10, 150, 50, 50);
Button btn = new Button("Play");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
// this "timeline" just call a handler after 500 ms which hides rectangle
TimelineBuilder.create().keyFrames(new KeyFrame(Duration.millis(500), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
rect1.setVisible(false);
}
})).build().play();
// this timeline hides rectangle 2 with animation
// changing scaleXProperty() from 1 (default) to 0
TimelineBuilder.create().keyFrames(
new KeyFrame(
Duration.millis(500),
new KeyValue(rect2.scaleXProperty(), 0))
).build().play();
}
});
Pane root = new Pane();
root.getChildren().addAll(rect1, rect2, btn);
Scene scene = new Scene(root, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
Related
Please go through the image below.
In the above image you can find that horizontal scrolling is not started.
Now visit the After Scroll image of the same contents...
Now in the second image you can see that horizontal scrolling is done ...
JFXPanel contents are scroll horizontally... Which was perfect...
Now the third image will describe the problem....
It is liitle bit stretched to see as it is maximized...
You can see that the JFXPanel contents have changed their original position...
Moreover the contents must start with X_DisplaceMent = 0.0 [X-Cordinate], which was done automatically in the first two images...
All the contents are nodes like [Rectangle,Line etc.. ], after that all are placed in Group node...
And this Group node is set in the ScrollPane through
js.setContent(Group node);
Each component is placed with given x,y cordiante value .. then how did this happen while doing the maximized ?
Please help me to find the root cause ...
Thanks in advance...
Here are some facts that cause the problem.
- Start Position of Scene : 0.0
- Start Position of Group in Scene : 49.5
- Width of the root : 364.5
- Start Position of Scene : 0.0
- Start Position of Group in Scene : 63.5
- Width of the root : 364.5
- Start Position of Scene : 0.0
- Start Position of Group in Scene : 83.5
- Width of the root : 364.5
Whenever we drag the window horizontally Group is moving in the scene... That should not happen... how to avoid this ...
Ok... Here is the MCVE.....
There is a Frame. which contain SplitPane having vertical split.
The SplitPane will show the contents of two JFxPanels.
Both fxpanels are having rectangle on same x cordinate but Y cordinate is different.
And both the fxPanels are horizontal scroll sync. Not bi-directional. When you scroll lower panel horizonatally, the upper panel will get scrolled due to horizontal sync.
Here is the code for fxPanel 1...
public class FxPanel1 extends JFXPanel
{
private ScrollPane scroll ;
public ScrollPane getJs() {
return scroll;
}
public void setJs(ScrollPane js) {
this.scroll = js;
}
private boolean initFX(JFXPanel fxPanel) {
Scene scene = createScene();
fxPanel.setScene(scene);
return true;
//craneAssignmentChartView.setFxPanel(fxPanel);
}
private Scene createScene() {
Group root = new Group();
Rectangle rect = new Rectangle(10.0, 20.0, 800, 40);
rect.setFill(javafx.scene.paint.Color.TRANSPARENT);
rect.setStroke(javafx.scene.paint.Color.RED);
AnchorPane anchor = new AnchorPane();
anchor.getChildren().add(rect);
GridPane grid = new GridPane();
grid.setHgap(0);
grid.setVgap(0);
grid.setPadding(new Insets(0, 0, 0, 0));
grid.add(anchor, 1, 0);
root.getChildren().add(grid);
ScrollPane scroll = new ScrollPane();
scroll.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
scroll.setContent(root);
setJs(scroll);
return new Scene(scroll, javafx.scene.paint.Color.WHITE);
}
private void createUI(final JFXPanel fxPanel)
{
Platform.runLater(new Runnable() {
#Override
public void run()
{
initFX(fxPanel);
}
});
}
public FxPanel1( JFXPanel fxPanel)
{
createUI(fxPanel);
}
}
Now the code for second fxPanel looks like ...
public class FxPanel2 extends JFXPanel
{
private ScrollPane scroll ;
public ScrollPane getJs() {
return scroll;
}
public void setJs(ScrollPane js) {
this.scroll = js;
}
private boolean initFX(JFXPanel fxPanel) {
Scene scene = createScene();
fxPanel.setScene(scene);
return true;
//craneAssignmentChartView.setFxPanel(fxPanel);
}
private Scene createScene() {
Group root = new Group();
Rectangle rect = new Rectangle(10.0, 180.0, 800, 40);
rect.setFill(javafx.scene.paint.Color.TRANSPARENT);
rect.setStroke(javafx.scene.paint.Color.RED);
AnchorPane anchor = new AnchorPane();
anchor.getChildren().add(rect);
GridPane grid = new GridPane();
grid.setHgap(0);
grid.setVgap(0);
grid.setPadding(new Insets(0, 0, 0, 0));
grid.add(anchor, 1, 0);
root.getChildren().add(grid);
ScrollPane scroll = new ScrollPane();
scroll.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollBarPolicy.NEVER);
scroll.setContent(root);
setJs(scroll);
return new Scene(scroll, javafx.scene.paint.Color.WHITE);
}
private void createUI(final JFXPanel fxPanel)
{
Platform.runLater(new Runnable() {
#Override
public void run()
{
initFX(fxPanel);
}
});
}
public FxPanel2( JFXPanel fxPanel)
{
createUI(fxPanel);
}
}
The main class looks like ....
public class DemoToCheckUIAlignment extends JFrame
{
public static void main(String[] args)
{
final DemoToCheckUIAlignment demo = new DemoToCheckUIAlignment();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFXPanel panel1 = new JFXPanel();
FxPanel1 fxObj1 = new FxPanel1(panel1);
JFXPanel panel2 = new JFXPanel();
FxPanel2 fxObj2 = new FxPanel2(panel2);
DemoToCheckUIAlignment frame = new DemoToCheckUIAlignment();
frame.setSize(800, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JSplitPane chartSplitPane = new JSplitPane();
chartSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
chartSplitPane.setDividerLocation(200);
chartSplitPane.setDividerSize(2);
chartSplitPane.setTopComponent(panel1);
chartSplitPane.setBottomComponent(panel2);
demo.provideScrollSyncBetweenFXPanels(fxObj1.getJs(), fxObj2.getJs());
frame.getContentPane().add(chartSplitPane);
//frame.getContentPane().add(panel2);
frame.setVisible(true);
}
});
}
public static void provideScrollSyncBetweenFXPanels(final ScrollPane upperSP, final ScrollPane lowerSP)
{
lowerSP.hvalueProperty().addListener(new ChangeListener<Number>()
{
public void changed(ObservableValue<? extends Number> ov,
Number old_val, Number new_val)
{
upperSP.hvalueProperty().set(new_val.doubleValue());
}
});
}
}
Now to check the problem follow the simple steps...
Ofcorse run the program...
Scroll the bottom Panel ....that is FxPanel2...
And maximized the window .... The x - position for the inner contents is changed now...
which does not happen with Swing....
Here are the screen shots where the problem reproduce for the attached MCVE....Please go through the images....
You may use setFitToWidth of the ScrollPane Object to match a particular dimension. For more details you may refer to the link http://docs.oracle.com/javafx/2/ui_controls/scrollpane.htm at down the page, Resizing Components in the Scroll Pane, you may find more on the solution
When to use translate and when relocate in order to move a node? In the end of the day it seems they do the same thing (visually); move the node; the first by doing a translation on the origin (the x, y stays the same), the second by changing the x, y coords.
So suppose i want to move a node in a specific point in the screen.. should i use node.relocate(x,y) or node.setTranslateX(x), node.setTranslateY(y)?
To demostrate what I mean I have made a sample program you can play with:
A rectangle on the screen, whose position is determined by 4 sliders (2 of them controlling the layout x, y the other two controlling the translate x, y).
/* imports are missing */
public class TransReloc extends Application{
#Override
public void start(Stage primaryStage) throws Exception {
Group root = new Group();
Rectangle rect = new Rectangle(100, 50, Color.BLUE);
root.getChildren().add(rect);
VBox controlGroup = new VBox();
Slider relocX = new Slider(-100, 100, 0 );
Slider relocY = new Slider(-100, 100, 0 );
Slider transX = new Slider(-100, 100, 0 );
Slider transY = new Slider(-100, 100, 0 );
rect.layoutXProperty().bind(relocX.valueProperty());
rect.layoutYProperty().bind(relocY.valueProperty());
rect.translateXProperty().bind(transX.valueProperty());
rect.translateYProperty().bind(transY.valueProperty());
controlGroup.getChildren().addAll(relocX, relocY, transX, transY);
root.getChildren().add(controlGroup);
controlGroup.relocate(0, 300);
Scene scene = new Scene(root, 300, 400, Color.ALICEBLUE);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
layout coordinates are used by Layout Managers like StackPane or VBox to control their children location. Group (and Pane) leaves children layout to developer thus there is no difference from translate functionality.
So generally you should only change translate coordinates for fine location tuning and leave layout to layout managers (actually you can't change layoutX, layoutY for nodes inside non Group/Pane layout managers)
As an example try to run next code and resize window to see how StackPane recalculates layoutBounds
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
Rectangle rect = new Rectangle(100, 50, Color.BLUE);
root.getChildren().add(rect);
Scene scene = new Scene(root, 300, 300, Color.ALICEBLUE);
rect.layoutXProperty().addListener( (e) -> {
System.out.println(rect.getLayoutX() + ":" + rect.getLayoutY());
});
primaryStage.setScene(scene);
primaryStage.show();
}
Another difference is that when you call Node.getBoundsInLocal(), will calculate the LayoutX, LayoutY and all the applied Effects. But, Node.getBoundsInParent() will get calculated with LayoutX, LayoutY, all applied Effects plus all transformations (rotation, translation and scaling). So you can use LayoutX/Y properties as a main position and use translateX/Y as a second or an alternative way to move the node. And the other difference is discussed above, I mean not to copy from Sergey Grinev.
This question already has answers here:
Get the height of a node in JavaFX (generate a layout pass)
(2 answers)
Closed 8 years ago.
I am developing an application for which it is necessary to layout nodes besides each other (or on top of each other etc.). However, this layout is only an initial placement and the user is able to move these nodes arbitrarily. How is this done in the correct way in JavaFX? I will explain my problem with a simplified example:
Assume I have 2 rectangles and want to place rect2 to the right of rect1.
// create first rectangle at position x= 5, y=5
rect1 = rectangle(5,5);
// create second rectangle to the right of rect1
rect2 = rectangle(5+rect1.width(), 5);
In this scenario JavaFX will not yet have determined the width of rect1 and it will be zero. Intuitively, I would perform a call that lets JavaFX draw rect1 and thus determine its width and afterwards add rect2. See the following example:
// create first rectangle at position x= 5, y=5
rect1 = rectangle(5,5);
// let JavaFX draw rect1 (width will be calculated and set)
draw();
// create second rectangle to the right of rect1
rect2 = rectangle(5+rect1.width(), 5);
Unfortunately I haven't found a method that does what I want. My current workaround makes use of Platform.runLater() but this does not work properly all the time. If my understanding of bindings is correct, bindings are also not suitable for this problem. I only want to initially layout the nodes, so I would have to remove the binding after the initial layout (or else rect2 would move if rect1 is moved).
Thanks in advance for any help.
EDIT: Here is a minimal working example. The width of the button is 0. I tried calling root.layout() to force a layout pass etc. but it does not seem to work.
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
btn.setText("Say 'Hello World'");
root.getChildren().add(btn);
// prints out 0
System.out.println(btn.getWidth());
}
}
Given the example from above, if I set the scene of the stage to null and then reset it, the button width will be set correctly when calling System.out.println(). It seems that this forces a layout pass on the whole stage? However, this just seems to be another workaround, in particular I have performance concerns.
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
btn.setText("Say 'Hello World'");
root.getChildren().add(btn);
// reset scene
primaryStage.setScene(null);
primaryStage.setScene(scene);
// prints out 107.0
System.out.println(btn.getWidth());
}
I am new to Java Fx using Netbeans 7.3.1.I am experimenting new things with Gridpane and I just want to place a Gridpane in a another position other than the left topmost position of the window..The root.getChildren().add(gridpane); adds the gridpane to the topmost left corner of the window.. How can i place the Gridpane on another place of the window without adding any new child or root!!My root is just a group and the current code just overlaps the gridpane with the Menubar.. My full code is this!!
public class Menu extends Application {
#Override
public void start(Stage primaryStage){
Group root = new Group();
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
MenuBar menuBar = new MenuBar();
javafx.scene.control.Menu m = new javafx.scene.control.Menu("File");
m.getItems().add(new MenuItem("New"));
m.getItems().add(new SeparatorMenuItem());
m.getItems().add(new MenuItem("Exit"));
menuBar.getMenus().add(m);
javafx.scene.control.Menu tools = new javafx.scene.control.Menu("Cameras");
tools.getItems().add(CheckMenuItemBuilder.create()
.text("Show Camera 1")
.selected(false)
.build());
menuBar.getMenus().add(tools);
root.getChildren().add(menuBar);
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(5));
gridpane.setHgap(5);
gridpane.setVgap(5);
Label fNameLbl = new Label("First Name");
TextField fNameFld = new TextField();
Label lNameLbl = new Label("First Name");
TextField lNameFld = new TextField();
Button saveButt = new Button("Save");
// First name label
GridPane.setHalignment(fNameLbl, HPos.RIGHT);
gridpane.add(fNameLbl, 0, 0);
// Last name label
GridPane.setHalignment(lNameLbl, HPos.RIGHT);
gridpane.add(lNameLbl, 0, 1);
// First name field
GridPane.setHalignment(fNameFld, HPos.LEFT);
gridpane.add(fNameFld, 1, 0);
// Last name field
GridPane.setHalignment(lNameFld, HPos.LEFT);
gridpane.add(lNameFld, 1, 1);
// Save button
GridPane.setHalignment(saveButt, HPos.RIGHT);
gridpane.add(saveButt, 1, 2);
root.getChildren().add(gridpane);
primaryStage.setScene(scene);
primaryStage.show();
}
try Scene Builder...it is used for designing javafx pages...
you can design all your pages according you need.
I'm not sure if it works but try using the following:
grid.setAlignment(Pos.CENTER);
Centre can be replaced with any other position as far as I am aware. I hope this helps somewhat.
Has anyone else found that adding -fx-effect in a style prevents opacity working?
Here is a simple example
public class TestGUI extends Application {
#Override
public void start(final Stage primaryStage) {
Line line = LineBuilder.create()
.startX(150)
.startY(0)
.endX(150)
.endY(250)
.build();
Button btn = ButtonBuilder.create()
.text("Open countdown!")
// this breaks the opacity!
.style("-fx-effect: dropshadow(three-pass-box, grey, 5, 0.5, 2, 5);")
.opacity(0.6)
.build();
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Button clicked");
}
});
StackPane root = new StackPane();
root.getChildren().addAll(line, btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Test Application");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Take out the style clause and you can see the line through the button.
Is this a bug or am I missing something.
The shadow is actually a shadow of the translucent node and translucent itself but because you are layering a translucent node on top of a tranlucent shadow, the overall result is still translucent, but much more opaque than if no shadow had been applied to the node. Similar to layering two 50 percent opaque nodes. The intersected area of the two layered nodes will be 75 percent opaque.
In your sample, you set the opacity to 0.6, so the combined opacity of the node + shadow is 0.6 + 0.4 * 0.6 = 0.84. Plus the shadow is a darker color than the effected node to begin with. This makes it difficult to see the line behind the effected node - but you can still just see it because the node + it's effect is not fully opaque. To show what is going on more clearly, I set the opacity of your sample to 0.2, making the combined opacity 0.36. You can see the result in the screenshot below where the line behind the effected node is still clearly visible.
Generally, shadows and opaque nodes visually don't mix and look all that good together