I want to add the data to the chart after the chart has been added to the scene. Because of that order, the animation of the rising bars is available:
answer = FXCollections.observableArrayList();
Series<String, Number> aSeries = new Series<String, Number>();
aSeries.getData().add(new XYChart.Data("Mytest", 120));
answer.addAll(aSeries);
chartFxPanel.setScene(new Scene(chart));
chart.setData(answer);
The only problem I have is, that the bars do not use the full available space in the chart.
I tried to add the bars with yValue=1 to register the bars and after that I added the chart to the scene and updated the values. But then there is again no animation:
answer = FXCollections.observableArrayList();
Series<String, Number> aSeries = new Series<String, Number>();
aSeries.getData().add(new XYChart.Data("Mytest", 1));
answer.addAll(aSeries);
chart.setData(answer);
chartFxPanel.setScene(new Scene(chart));
new Timeline(
new KeyFrame(
Duration.millis(500),
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
answer.get(0).getData().get(0).setYValue(120);
}
})).play();
So, how can the bars use the full space but with animation?
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
I am currently experimenting with JavaFX's scene graph. I came across a strange problem that i can't really explain. Have a look at the following code:
final BorderPane bp1 = new BorderPane();
final Button button = new Button("CLICK ME");
Scene sc1 = new Scene(bp1,100,100);
bp1.setCenter(button);
stage1.setScene(sc1);
stage1.show();
Stage stage2 = new Stage();
final BorderPane bp2 = new BorderPane();
Scene sc2 = new Scene(bp2,100,100);
stage2.setScene(sc2);
stage2.setX(250);
stage2.show();
bp2.setCenter(button);
bp1.setCenter(button);
What i am trying to do here is to add a node (Button) to a Borderpane which lies within a scene on stage1. At the end of the code i try to add the node to a different scene(pane) on stage2. This actually works. But the last line does not. The button remains on stage2. The strange thing is that if i replace the borderpane with a gridpane, the code works as intended. Why does the borderpane behave different from the gridpane in this situation?
Another question which came to my mind in this case: I assume that there is exactly 1 scene graph per scene (or stage). Is that correct?
I guess you found a bug in the BorderPane implementation. The BorderPane has a bit of peculiar way how it manages its children. You can find the BorderPane implementation here. I suggest you file a bug report at the javafx jira
My testcase:
final BorderPane bp1 = new BorderPane();
final BorderPane bp2 = new BorderPane();
System.out.println("bp1 "+bp1);
System.out.println("bp2 "+bp2);
final Button button = new Button("CLICK ME");
button.parentProperty().addListener(new ChangeListener<Parent>() {
#Override
public void changed(ObservableValue<? extends Parent> observableValue, Parent parent, Parent parent2) {
System.out.println("changed");
System.out.println(button.getParent());
}
});
bp1.centerProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
System.out.println("bp1 center invalidated ");
}
});
bp2.centerProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
System.out.println("bp2 center invalidated ");
}
});
// bp1.centerProperty().addListener(new ChangeListener<Node>() {
// #Override
// public void changed(ObservableValue<? extends Node> observableValue, Node node, Node node2) {
// System.out.println("bp1 center changed "+node+" -> "+node2);
// }
// });
// bp2.centerProperty().addListener(new ChangeListener<Node>() {
// #Override
// public void changed(ObservableValue<? extends Node> observableValue, Node node, Node node2) {
// System.out.println("bp2 center changed "+node+" -> "+node2);
// }
// });
Scene sc1 = new Scene(bp1,100,100);
bp1.setCenter(button);
primaryStage.setScene(sc1);
primaryStage.show();
Stage stage2 = new Stage();
Scene sc2 = new Scene(bp2,100,100);
stage2.setScene(sc2);
stage2.setX(250);
stage2.show();
bp2.setCenter(button);
bp1.setCenter(button);
output:
bp1 BorderPane#48a80c67
bp2 BorderPane#10c66375
changed
BorderPane#48a80c67[styleClass=root]
bp1 center invalidated
changed
null
changed
BorderPane#10c66375[styleClass=root]
bp2 center invalidated
Explanation:
I found that bp1's center property is not invalidated and thus not updated when the button is added to the second scene. Adding a node to another scene should normally cause it to be removed from the previous scene. However, since BorderPane uses a peculiar way to hold its values (object properties for center, left and so on), after the button is added to the second scene, the button is not removed from the center property of the BorderPane. Setting the button a second time on the same BorderPane doesn't add the button to its children because it thinks that it is already set as the center node.
To your second question:
yes, only one scene graph per stage/scene.
This question already has answers here:
Add fixed positioned Combobox inside FlowPane
(2 answers)
Closed 9 years ago.
I have a FlowPane with panels which will be used to display data in front of the user.
![enter image description here][1]
I added also scrollpane when the number of the panels is bigger than the visible area.
I also want to add filter which will sort the panels by type and will display only the appropriate. The red area will hold the ComboBox which will be the filter.
And as you can see the red are pushes down the FlowPane which will make a gap between the top component and the scroll when I make the area transparent.
Is there a way to use the z-index and place the red are in front of the FlowPane? Or some other solution?
This is the result that I would like to get:
![enter image description here][2]
Investigate this example based on your code in previous questions:
public class Demo extends Application {
#Override
public void start(Stage stage) throws Exception {
StackPane stackPane = new StackPane();
stackPane.setAlignment(Pos.TOP_LEFT);
stackPane.getChildren().addAll(infrastructurePane(), getFilterPane());
Scene scene = new Scene(stackPane);
stage.setScene(scene);
stage.show();
}
public Pane getFilterPane() {
ObservableList<String> options =
FXCollections.observableArrayList(
"Option 1", "Option 2", "Option 3");
ComboBox<String> combo = new ComboBox<String>(options);
HBox pane = new HBox();
pane.setPadding(new Insets(20));
pane.setStyle("-fx-background-color: rgba(255,0,85,0.4)");
pane.getChildren().add(combo);
pane.setMaxHeight(40);
// Optional
//pane.setEffect(new DropShadow(15, Color.RED));
return pane;
}
public ScrollPane infrastructurePane() {
final FlowPane flow = new FlowPane();
flow.setPadding(new Insets(5, 5, 5, 5));
flow.setVgap(5);
flow.setHgap(5);
flow.setAlignment(Pos.CENTER);
final ScrollPane scroll = new ScrollPane();
scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); // Horizontal scroll bar
scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); // Vertical scroll bar
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
scroll.setContent(flow);
// scroll.viewportBoundsProperty().addListener(new ChangeListener<Bounds>() {
// #Override
// public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds) {
// flow.setPrefWidth(bounds.getWidth());
// flow.setPrefHeight(bounds.getHeight());
// }
// });
//flow.setPrefWrapLength(170); // preferred width allows for two columns
flow.setStyle("-fx-background-color: yellow;");
for (int i = 0; i < 28; i++) {
flow.getChildren().add(generateRectangle());
}
String cssURL = "/com/dx57dc/css/ButtonsDemo.css";
String css = this.getClass().getResource(cssURL).toExternalForm();
flow.getStylesheets().add(css);
return scroll;
}
public Rectangle generateRectangle() {
final Rectangle rect2 = new Rectangle(10, 10, 10, 10);
rect2.setId("app");
rect2.setArcHeight(8);
rect2.setArcWidth(8);
//rect2.setX(10);
//rect2.setY(160);
rect2.setStrokeWidth(1);
rect2.setStroke(Color.WHITE);
rect2.setWidth(220);
rect2.setHeight(180);
rect2.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
rect2.setFill(Color.ALICEBLUE);
}
});
return rect2;
}
public static void main(String[] args) {
launch(args);
}
}
EDIT:
As per comment, here is the combo without pane. Since there is no pane the mouse events will not be blocked. Replace only this method with above one:
public ComboBox getFilterPane() {
ObservableList<String> options =
FXCollections.observableArrayList(
"Option 1", "Option 2", "Option 3");
ComboBox<String> combo = new ComboBox<String>(options);
combo.setTranslateX(10);
combo.setTranslateY(10);
return combo;
}
if you're using JavaFX 8, you can try a Notification Pane from ControlsFX project
It looks like:
It's pretty unclear to get which behaviour you don't want and which one you want.
This sentence "And as you can see the red are pushes down the FlowPane which will make a gap between the top component and the scroll when I make the area transparent." is particularly hard to understand.
But if you just want to "use the z-index and place the red are in front of the FlowPane?", maybe all you're asking for is just a StackPane ?
StackPane lays out its children in a back-to-front stack.
The z-order of the children is defined by the order of the children
list with the 0th child being the bottom and last child on top. If a
border and/or padding have been set, the children will be layed out
within those insets.
http://docs.oracle.com/javafx/2/api/javafx/scene/layout/StackPane.html
If you want the red area be part of the ScrollPane:
Create a VBox
Add The Red Area Component to VBox
Add the FlowPane to VBox
Set VBox as the ScrollPanes Content
If the Layout with VBox's doenst look statisfying try Borderpane and set the "Red Area" top and your flowpane as center.
Is there a way to use the z-index and place the red are in front of the FlowPane? Or some other solution?
see QuidNovi's answer
ListView appears to already have a scrollbar. I want the scrollbar to always be visible. The reason is because I'm putting a header on it and a button in the corner between the scrollbar and header. How can I get the ListView scrollbar to always display?
you could put it into a properly sized ScrollPane and set the vbar policy of the ScrollPane to ALWAYS:
#Override
public void start(Stage primaryStage) throws Exception {
ScrollPane pane = new ScrollPane();
ListView<String> list = new ListView<String>();
ObservableList<String> items = FXCollections.observableArrayList(
"Single", "Double", "Suite", "Family App");
list.setItems(items);
pane.prefWidthProperty().bind(list.widthProperty());
pane.prefHeightProperty().bind(list.heightProperty());
pane.setContent(list);
pane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
Group group = new Group();
group.getChildren().add(pane);
Scene scene = new Scene(group, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
The following program fails to resize the line chart horizontally when embedded in a Pane (or borderpane of anchorpane for the matter)
If the line chart is directly parented to the VBox instead, then everything works as expected.
I found I needed to bind the chart size to the parent pane, which I assume must be done automatically by VBox and HBox.
After trying different combination of enclosing in HBox/VBox, setting growing and alignment policies, I am quite confused about how layouts work.
I observe that there are differences in how ui components behave wrt resizing.
Any clarification (or digest insight on javadoc unclear documentation) is appreciated.
Best regards.
Source edited and clarified
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage stage) {
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("X");
yAxis.setLabel("Y");
final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setTitle("x = f(y)");
XYChart.Series data = new XYChart.Series();
data.setName("Serie 1");
for (int i = 0; i < 10; i++) {
data.getData().add(new XYChart.Data(i, i * i));
}
lineChart.getData().add(data);
VBox vb = new VBox();
vb.setFillWidth(true);
HBox hb = new HBox();
hb.getChildren().add(lineChart);
hb.setFillHeight(true);
vb.getChildren().add(hb);
HBox.setHgrow(lineChart, Priority.ALWAYS);
VBox.setVgrow(hb, Priority.ALWAYS);
Scene scene = new Scene(vb);
stage.setScene(scene);
stage.centerOnScreen();
stage.setResizable(true);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
For the record, the problem of the provided example is solved after modifying this typo:
HBox.setHgrow(hb, Priority.ALWAYS);
to:
HBox.setHgrow(lineChart, Priority.ALWAYS);
This fixes resizing horizontally.
When embedded directly in VBox, the chart's size is recomputed on resize, as it is anchored to the VBox, which boundaries change.
When embedded in a HBox, we have to provide a hint for the HBox to grow horizontally, and vertically.
Vertically it's done with:
VBox.setVgrow(hb, Priority.ALWAYS);
Horizontally it's done by requesting its content to occupy all available space, which the fix above is about.