Properly create new instance of JavaFX Chart - javafx

I can't find a solution of the problem how to create new instance of chart. I tested the below code:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
import javafx.util.Duration;
public class MainApp extends Application
{
private StackedBarChart<String, Number> schart;
private CategoryAxis xAxis = new CategoryAxis();
private NumberAxis yAxis = new NumberAxis();
private StackedBarChart<String, Number> inits()
{
schart = new StackedBarChart<>(xAxis, yAxis);
schart.setAnimated(false);
schart.setTitle("Some_value");
return schart;
}
GenDatService data = new GenDatService();
#Override
public void start(Stage stage) throws Exception
{
StackedBarChart<String, Number> inits = inits();
data.setPeriod(new Duration(1000));
data.setOnSucceeded(new EventHandler<WorkerStateEvent>()
{
#Override
public void handle(final WorkerStateEvent workerStateEvent)
{
HashMap<String, Integer> value = data.getValue();
visuData(value);
}
});
data.setOnFailed(new EventHandler<WorkerStateEvent>()
{
#Override
public void handle(WorkerStateEvent t)
{
}
});
data.start();
Scene scene = new Scene(schart);
stage.setTitle("JavaFX and Maven");
stage.setScene(scene);
stage.show();
}
public void visuData(HashMap<String, Integer> map)
{
Set<String> keySet = map.keySet();
ObservableList<XYChart.Series<String, Number>> observableArrayList = FXCollections.observableArrayList();
ObservableList<String> observabtd = FXCollections.observableArrayList();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext())
{
String column = iterator.next();
Integer value = map.get(column);
XYChart.Series<String, Number> series1 = new XYChart.Series<>();
XYChart.Data<String, Number> dataS1 = new XYChart.Data<>();
observabtd.add(column);
series1.setName(column);
dataS1.setXValue(column);
dataS1.setYValue(value);
series1.getData().add(dataS1);
observableArrayList.add(series1);
}
xAxis.setCategories(observabtd);
yAxis.setLabel("Some Value");
Scene scene = schart.getScene();
schart = new StackedBarChart<>(xAxis, yAxis);
scene.setRoot(schart);
schart.setAnimated(false);
schart.setData(observableArrayList);
}
public static void main(String[] args)
{
launch(args);
}
class GenDatService extends ScheduledService<HashMap<String, Integer>>
{
#Override
protected Task<HashMap<String, Integer>> createTask()
{
return new Task<HashMap<String, Integer>>()
{
#Override
protected HashMap<String, Integer> call() throws Exception
{
HashMap<String, Integer> usageData = new HashMap<>();
usageData.put("val_1", (int) (Math.random() * 100));
usageData.put("val_2", (int) (Math.random() * 100));
usageData.put("val_3", (int) (Math.random() * 100));
usageData.put("val_4", (int) (Math.random() * 100));
return usageData;
}
};
}
}
}
This code works fine, but the only problem is that I can't think of a way to properly set new instance of the StackedBarChart. This is the code whih I need to fix.
Scene scene = schart.getScene();
schart = new StackedBarChart<>(xAxis, yAxis);
scene.setRoot(schart);
Can you help me to fix this issue?

Related

JavaFx Chart unrefresh in subscene with Oracle JDK10

I write a JavaFX Demo to add a bar chart in Subscene and change the bar chart series value in KeyFrame in Timeline.
In Oracle JDK8, the bar chart graphic refresh correct,But in Oracle JDK 10,the bar chart graphic do not refresh.
I tried Platform.requestNextPulse,but it donot useful.
Sorry for my poor English.
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Rectangle2D;
import javafx.scene.*;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
public class HMIBrowserDemoTest extends Application {
private Scene backScene=new Scene(new Group());
SubScene subScene =null;
private Group picGroup=null;
public HMIBrowserDemoTest(){
super();
}
private void initUI(Stage primaryStage) {
Rectangle2D screenBounds=Screen.getPrimary().getBounds();
primaryStage.setWidth(screenBounds.getWidth());
primaryStage.setHeight(screenBounds.getHeight());
primaryStage.centerOnScreen();
primaryStage.setTitle("hmi.browser.title");
primaryStage.setScene(backScene);
Group rootGroup=(Group) backScene.getRoot();
Group aa=new Group();
aa.getChildren().add(createContent1());
subScene =new SubScene(aa,800,700);
subScene.setFill(Color.BEIGE);
subScene.setManaged(false);
rootGroup.getChildren().add(subScene);
}
#Override
public void start(Stage primaryStage) throws Exception {
initUI(primaryStage);
primaryStage.show();
init1();
}
public static void main(String[] args) {
System.out.println(System.getProperty("java.library.path"));
launch(args);
}
private void init1(){
Timeline tl = new Timeline();
tl.getKeyFrames().add(
new KeyFrame(Duration.millis(150),
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
XYChart.Series series= (XYChart.Series) chart.getData().get(0);
int value= (int) (Math.random() * 5000);
XYChart.Data<String, Number> data= (XYChart.Data<String, Number>) series.getData().get(0);
System.out.println(value+"-----------");
data.setYValue(value);
subScene.toFront();
}
}
));
tl.setCycleCount(Animation.INDEFINITE);
tl.setAutoReverse(true);
tl.play();
}
private BarChart chart;
private CategoryAxis xAxis;
private NumberAxis yAxis;
public Parent createContent1() {
String[] years = {"2007", "2008", "2009"};
xAxis = new CategoryAxis();
xAxis.setCategories(FXCollections.<String>observableArrayList(years));
yAxis = new NumberAxis("Units Sold", 0.0d, 3000.0d, 1000.0d);
ObservableList<BarChart.Series> barChartData = FXCollections.observableArrayList(
new BarChart.Series("Apples", FXCollections.observableArrayList(
new BarChart.Data(years[0], 567d),
new BarChart.Data(years[1], 1292d),
new BarChart.Data(years[2], 1292d)
)),
new BarChart.Series("Lemons", FXCollections.observableArrayList(
new BarChart.Data(years[0], 956),
new BarChart.Data(years[1], 1665),
new BarChart.Data(years[2], 2559)
)),
new BarChart.Series("Oranges", FXCollections.observableArrayList(
new BarChart.Data(years[0], 1154),
new BarChart.Data(years[1], 1927),
new BarChart.Data(years[2], 2774)
))
);
chart = new BarChart(xAxis, yAxis, barChartData, 25.0d);
chart.setLayoutX(0);
chart.setLayoutY(0);
chart.setPrefSize(300,300);
return chart;
}
}

Using String Time stamps in LineChart

I'm using JavaFX.
I've modified an example of a Zoom function on a LineChart. I get an exception when doing the zoom. I've figured out that there is a mismatch between Types on the xAxis, it wants Numbers and I'm using String Time stamps. How can I adapt this to work with time strings like "12:33:23" on xAxis?
package javafxapplication28;
import java.util.Collections;
import java.util.Random;
import static java.util.UUID.fromString;
import javafx.application.Application;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.beans.property.StringProperty;
import javafx.util.StringConverter;
public class JavaFXApplication28 extends Application {
private static final int NUM_DATA_POINTS = 1000 ;
#Override
public void start(Stage primaryStage) {
final LineChart<Number, Number> chart = createChart();
final StackPane chartContainer = new StackPane();
chartContainer.getChildren().add(chart);
final Rectangle zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
chartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, chart);
final HBox controls = new HBox(10);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
final Button zoomButton = new Button("Zoom");
final Button resetButton = new Button("Reset");
zoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
doZoom(zoomRect, chart);
}
});
resetButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final NumberAxis xAxis = (NumberAxis)chart.getXAxis();
xAxis.setLowerBound(10);
xAxis.setUpperBound(200);
final NumberAxis yAxis = (NumberAxis)chart.getYAxis();
yAxis.setLowerBound(0);
yAxis.setUpperBound(200);
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
});
final BooleanBinding disableControls =
zoomRect.widthProperty().lessThan(5)
.or(zoomRect.heightProperty().lessThan(5));
zoomButton.disableProperty().bind(disableControls);
controls.getChildren().addAll(zoomButton, resetButton);
final BorderPane root = new BorderPane();
root.setCenter(chartContainer);
root.setBottom(controls);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private LineChart<Number, Number> createChart() {
final NumberAxis xAxis = createAxis_x();
final NumberAxis yAxis = createAxis_y();
final LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis);
chart.setAnimated(false);
chart.setCreateSymbols(false);
chart.setData(generateChartData());
return chart ;
}
//Set range of x axis
private NumberAxis createAxis_x() {
final NumberAxis xAxis = new NumberAxis();
xAxis.setAutoRanging(false);
String xMin = "12:30:12";
String xMax = "13:21:01";
double xminDouble = Double.parseDouble(xMin);
double xmaxDouble = Double.parseDouble(xMax);
xAxis.setLowerBound(xminDouble);
xAxis.setUpperBound(xmaxDouble);
return xAxis;
}
//Set range of y axis
private NumberAxis createAxis_y() {
final NumberAxis yAxis = new NumberAxis();
yAxis.setAutoRanging(false);
String yMin = "40";
String yMax = "400";
double yminDouble = Double.parseDouble(yMin);
double ymaxDouble = Double.parseDouble(yMax);
yAxis.setLowerBound(yminDouble);
yAxis.setUpperBound(ymaxDouble);
return yAxis;
}
private ObservableList<Series<Number, Number>> generateChartData() {
final Series<Number, Number> series = new Series<>();
series.setName("Data");
final Random rng = new Random();
for (int i=0; i<NUM_DATA_POINTS; i++) {
Data<Number, Number> dataPoint = new Data<Number, Number>(i, rng.nextInt(1000));
series.getData().add(dataPoint);
}
return FXCollections.observableArrayList(Collections.singleton(series));
}
private void setUpZooming(final Rectangle rect, final Node zoomingNode) {
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
mouseAnchor.set(new Point2D(event.getX(), event.getY()));
rect.setWidth(0);
rect.setHeight(0);
}
});
zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double x = event.getX();
double y = event.getY();
rect.setX(Math.min(x, mouseAnchor.get().getX()));
rect.setY(Math.min(y, mouseAnchor.get().getY()));
rect.setWidth(Math.abs(x - mouseAnchor.get().getX()));
rect.setHeight(Math.abs(y - mouseAnchor.get().getY()));
}
});
}
private void doZoom(Rectangle zoomRect, LineChart<Number, Number> chart) {
Point2D zoomTopLeft = new Point2D(zoomRect.getX(), zoomRect.getY());
Point2D zoomBottomRight = new Point2D(zoomRect.getX() + zoomRect.getWidth(), zoomRect.getY() + zoomRect.getHeight());
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
Point2D yAxisInScene = yAxis.localToScene(0, 0);
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
System.out.println(xAxis);
Point2D xAxisInScene = xAxis.localToScene(0, 0);
double xOffset = zoomTopLeft.getX() - yAxisInScene.getX() ;
double yOffset = zoomBottomRight.getY() - xAxisInScene.getY();
double xAxisScale = xAxis.getScale();
double yAxisScale = yAxis.getScale();
xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale);
xAxis.setUpperBound(xAxis.getLowerBound() + zoomRect.getWidth() / xAxisScale);
yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale);
yAxis.setUpperBound(yAxis.getLowerBound() - zoomRect.getHeight() / yAxisScale);
System.out.println(yAxis.getLowerBound() + " " + yAxis.getUpperBound());
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
public static void main(String[] args) {
launch(args);
}
}
It works like this. Draw a rectangle in the Linechart for the area to zoom in. Then press the zoom button.
The sample code above gives an exception due to the problem with time strings. To get it to work use this instead:
String xMin = "40";
String xMax = "300";
Thanks for ur help!

Display Circle progress bar during charts loading

I'm working on this code with Barchart and Piechart.
import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Scene scene = new Scene(initGeneralAgentsData(), 800, 800);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
private final StackPane stackPane = new StackPane();
private List<DownloadTrafficObj> obj = new LinkedList<>();
public StackPane initGeneralAgentsData() throws Exception
{
stackPane.setAlignment(Pos.TOP_RIGHT);
stackPane.setStyle("-fx-background-color: white;");
SQLSelect(30);
stackPane.getChildren().addAll(chartChoose());
return stackPane;
}
private List<DownloadTrafficObj> SQLSelect(int history_value)
{
for (int i = 0; i < history_value; i++)
{
obj.add(new DownloadTrafficObj(String.valueOf(randomDate()), Long.valueOf(randomNumber())));
}
return obj;
}
private Timestamp randomDate()
{
long offset = Timestamp.valueOf("2012-01-01 00:00:00").getTime();
long end = Timestamp.valueOf("2013-01-01 00:00:00").getTime();
long diff = end - offset + 1;
Timestamp rand = new Timestamp(offset + (long) (Math.random() * diff));
return rand;
}
private int randomNumber()
{
Random rand = new Random();
int n = rand.nextInt(50) + 1;
return n;
}
public StackPane chartChoose()
{
final ComboBox comboBox = new ComboBox();
comboBox.getItems().addAll("Bar Chart", "Pie Chart");
ComboBox cb = new ComboBox();
cb.getItems().addAll(10, 20, 30, 60);
cb.setValue(30);
final StackPane stack = new StackPane();
comboBox.getSelectionModel().selectedIndexProperty()
.addListener((ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
-> setVisibility(stack, comboBox)
);
cb.getSelectionModel().selectedIndexProperty()
.addListener((ObservableValue<? extends Number> observable,
Number oldValue, Number newValue)
->
{
SQLSelect((int) cb.getSelectionModel().getSelectedItem());
bc.getData().clear();
generateBarChartData();
}
);
stack.getChildren().add(generateBarChart());
stack.getChildren().add(generatePieChart());
// Placing it after adding rectangle to stack
// will trigger the changelistener to show default rectangle
comboBox.setValue("Bar Chart");
VBox vBox = new VBox();
vBox.setPadding(new Insets(10, 10, 10, 10));
vBox.setSpacing(5);
Label labelon = new Label("Chart type");
Label label = new Label("Days history");
HBox hBossx = new HBox(15, labelon, comboBox, label, cb);
hBossx.setAlignment(Pos.CENTER_RIGHT);
ProgressIndicator progress = new ProgressIndicator();
progress.setMaxSize(90, 90);
Task<ObservableList<DownloadTrafficObj>> task = new Task<ObservableList<DownloadTrafficObj>>()
{
#Override
protected ObservableList<DownloadTrafficObj> call() throws Exception
{
for (int i = 0; i < 99; i++)
{
Thread.sleep(20);
}
return (FXCollections.observableArrayList(obj));
}
};
progress.progressProperty().bind(task.progressProperty());
task.setOnSucceeded(ev ->
{
});
new Thread(task).start();
BorderPane bp = new BorderPane();
bp.centerProperty().bind(
Bindings
.when(task.runningProperty())
.then(progress)
.otherwise((ObservableObjectValue<ProgressIndicator>) stack));
vBox.getChildren().addAll(hBossx, bp);
StackPane root = new StackPane();
root.getChildren().add(vBox);
return root;
}
public void setVisibility(Pane pane, ComboBox comboBox)
{
// Make all children invisible
pane.getChildren().stream().forEach((node) ->
{
node.setVisible(false);
});
// make the selected rectangle visible
int selectedIndex = comboBox.getSelectionModel()
.selectedIndexProperty().getValue();
pane.getChildren().get(selectedIndex).setVisible(true);
}
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final BarChart<String, Number> bc = new BarChart<>(xAxis, yAxis);
XYChart.Series series1 = new XYChart.Series();
public BarChart<String, Number> generateBarChart()
{
bc.setTitle("Network Download");
xAxis.setLabel("Groups");
yAxis.setLabel("Value");
series1.setName("Network Download");
generateBarChartData();
// TO DO... Very quick fix.
bc.widthProperty().addListener((obs, b, b1) ->
{
// Chart Bar column is not automatically resized. We need to wait for next JavaFX releases to fix this.
Platform.runLater(() -> setMaxBarWidth(bc, xAxis, 40, 10));
});
bc.getData().addAll(series1);
return bc;
}
private void generateBarChartData()
{
obj.stream().map((get) -> new XYChart.Data(get.getDate(), get.getDownloadTraffic())).map((data) ->
{
data.nodeProperty().addListener(new ChangeListener<Node>()
{
#Override
public void changed(ObservableValue<? extends Node> ov, Node oldNode, final Node node)
{
if (node != null)
{
//setNodeStyle(data);
displayLabelForData(data);
}
}
});
return data;
}).forEach((data) ->
{
series1.getData().add(data);
});
}
private void setMaxBarWidth(BarChart<String, Number> bc, CategoryAxis xAxis, double maxBarWidth, double minCategoryGap)
{
double barWidth = 0;
do
{
double catSpace = xAxis.getCategorySpacing();
double avilableBarSpace = catSpace - (bc.getCategoryGap() + bc.getBarGap());
barWidth = (avilableBarSpace / bc.getData().size()) - bc.getBarGap();
if (barWidth > maxBarWidth)
{
avilableBarSpace = (maxBarWidth + bc.getBarGap()) * bc.getData().size();
bc.setCategoryGap(catSpace - avilableBarSpace - bc.getBarGap());
}
}
while (barWidth > maxBarWidth);
do
{
double catSpace = xAxis.getCategorySpacing();
double avilableBarSpace = catSpace - (minCategoryGap + bc.getBarGap());
barWidth = Math.min(maxBarWidth, (avilableBarSpace / bc.getData().size()) - bc.getBarGap());
avilableBarSpace = (barWidth + bc.getBarGap()) * bc.getData().size();
bc.setCategoryGap(catSpace - avilableBarSpace - bc.getBarGap());
}
while (barWidth < maxBarWidth && bc.getCategoryGap() > minCategoryGap);
}
public PieChart generatePieChart()
{
ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
obj.stream().forEach((activeAgentGroup) ->
{
pieChartData.add(new PieChart.Data(activeAgentGroup.getDate(), activeAgentGroup.getDownloadTraffic()));
});
final PieChart chart = new PieChart(pieChartData);
chart.setTitle("Label");
return chart;
}
private void displayLabelForData(XYChart.Data<String, Number> data)
{
final Node node = data.getNode();
final Text dataText = new Text(data.getYValue().toString());
node.parentProperty().addListener(new ChangeListener<Parent>()
{
#Override
public void changed(ObservableValue<? extends Parent> ov, Parent oldParent, Parent parent)
{
Group parentGroup = (Group) parent;
parentGroup.getChildren().add(dataText);
}
});
node.boundsInParentProperty().addListener(new ChangeListener<Bounds>()
{
#Override
public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds)
{
dataText.setLayoutX(
Math.round(
bounds.getMinX() + bounds.getWidth() / 2 - dataText.prefWidth(-1) / 2
)
);
dataText.setLayoutY(
Math.round(
bounds.getMinY() - dataText.prefHeight(-1) * 0.5
)
);
}
});
}
}
I ant to add circular progress bar during switch of the charts and loading of the data. Usually it takes 2-3 seconds to load data from the database, so I need a way to display progress bay because the charts are stacked.
Also is there any much easy way to implement the switching of the charts?
Short and sweet:
Use a BorderPane as parent container for your charts.
Use Bindings, Task.runningProperty() and BorderPane.centerProperty()
For example something like this:
myBorderPane.centerProperty().bind(
Bindings
.when(myLongTask.runningProperty())
.then(myProggressIndicator)
.otherwise(myChart));

Set action for press the mouse on Axis in StackPane. Please

I have a StackPane with charts (multiple axis chart). I want to set some action for yAxis. There is no result in GUI, but it is well for baseChart (isn't in StackPane). How can I set an action for Axis?
MCVE
mainclass with JFrame:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.function.Function;
public abstract class mainClass extends Application {
public static final int X_NUMBER = 20;
static StackChart chart;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
private static void initAndShowGUI() {
// This method is invoked on Swing thread
JFrame frame = new JFrame("FX");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setVisible(true);
frame.setSize((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(), (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight());
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on JavaFX thread
Scene scene = createScene();
fxPanel.setScene(scene);
}
private static Scene createScene() {
Group root = new Group();
Scene scene = new Scene(root, 1024, 600);
BorderPane borderPane = new BorderPane();
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Scale 1");
LineChart baseChart = new LineChart(xAxis, yAxis);
baseChart.getData().add(prepareSeries("Serie 1", (x) -> (double) x));
chart = new StackChart(baseChart, Color.RED);
chart.addSeries(prepareSeries("Serie 2", (x) -> (double) -2*x * x), Color.BLUE);
borderPane.setCenter(chart);
borderPane.setPrefSize(800, 600);
borderPane.setBottom(chart.getLegend());
root.getChildren().add(borderPane);
return scene;
}
private static XYChart.Series<Number, Number> prepareSeries(String name, Function<Integer, Double> function) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName(name);
for (int i = 0; i < X_NUMBER; i++) {
series.getData().add(new XYChart.Data<>(i, function.apply(i)));
}
return series;
}
}
StackChart class:
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
public class StackChart extends StackPane {
private final LineChart baseChart;
private final ObservableList<LineChart> backCharts = FXCollections.observableArrayList();
private final double yAxisWidth = 60;
private final AnchorPane details;
private final double yAxisSeparation = 20;
private double strokeWidth = 0.3;
public int _formatType = 1;
public StackChart(LineChart baseChart, Color lineColor) {
this(baseChart, lineColor, null);
}
public StackChart(LineChart baseChart, Color lineColor, Double strokeWidth) {
if (strokeWidth != null) {
this.strokeWidth = strokeWidth;
}
this.baseChart = baseChart;
baseChart.setCreateSymbols(false);
baseChart.setLegendVisible(false);
baseChart.getXAxis().setAutoRanging(false);
baseChart.getXAxis().setAnimated(false);
baseChart.getXAxis().setStyle("-fx-font-size:" + 18);
baseChart.getYAxis().setAnimated(false);
baseChart.getYAxis().setStyle("-fx-font-size:" + 18);
setStyle(baseChart, lineColor);
setFixedAxisWidth(baseChart);
setAlignment(Pos.CENTER_LEFT);
backCharts.addListener((Observable observable) -> rebuildChart());
details = new AnchorPane();
bindMouseEvents(baseChart, this.strokeWidth);
rebuildChart();
}
private void bindMouseEvents(LineChart baseChart, Double strokeWidth) {
getChildren().add(details);
details.prefHeightProperty().bind(heightProperty());
details.prefWidthProperty().bind(widthProperty());
details.setMouseTransparent(true);
setOnMouseMoved(null);
setMouseTransparent(false);
final Axis xAxis = baseChart.getXAxis();
final Axis yAxis = baseChart.getYAxis();
final Line xLine = new Line();
final Line yLine = new Line();
yLine.setFill(Color.GRAY);
xLine.setFill(Color.GRAY);
yLine.setStrokeWidth(strokeWidth/2);
xLine.setStrokeWidth(strokeWidth/2);
xLine.setVisible(false);
yLine.setVisible(false);
final Node chartBackground = baseChart.lookup(".chart-plot-background");
for (Node n: chartBackground.getParent().getChildrenUnmodifiable()) {
if (n != chartBackground && n != xAxis && n != yAxis) {
n.setMouseTransparent(true);
}
}
chartBackground.setCursor(Cursor.CROSSHAIR);
chartBackground.setOnMouseEntered((event) -> {
chartBackground.getOnMouseMoved().handle(event);
xLine.setVisible(true);
yLine.setVisible(true);
details.getChildren().addAll(xLine, yLine);
});
chartBackground.setOnMouseExited((event) -> {
xLine.setVisible(false);
yLine.setVisible(false);
details.getChildren().removeAll(xLine, yLine);
});
chartBackground.setOnMouseMoved(event -> {
double x = event.getX() + chartBackground.getLayoutX();
double y = event.getY() + chartBackground.getLayoutY();
xLine.setStartX(65);
xLine.setEndX(details.getWidth()-10);
xLine.setStartY(y+5);
xLine.setEndY(y+5);
yLine.setStartX(x+5);
yLine.setEndX(x+5);
yLine.setStartY(12);
yLine.setEndY(details.getHeight()-28);
});
}
private void setFixedAxisWidth(LineChart chart) {
chart.getYAxis().setPrefWidth(yAxisWidth);
chart.getYAxis().setMaxWidth(yAxisWidth);
}
private void rebuildChart() {
getChildren().clear();
getChildren().add(resizeBaseChart(baseChart));
for (LineChart lineChart : backCharts) {
getChildren().add(resizeBackgroundChart(lineChart));
}
getChildren().add(details);
}
private Node resizeBaseChart(LineChart lineChart) {
HBox hBox = new HBox(lineChart);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.prefHeightProperty().bind(heightProperty());
hBox.prefWidthProperty().bind(widthProperty());
lineChart.minWidthProperty().bind(widthProperty().subtract((yAxisWidth+yAxisSeparation)*backCharts.size()));
lineChart.prefWidthProperty().bind(widthProperty().subtract((yAxisWidth+yAxisSeparation)*backCharts.size()));
lineChart.maxWidthProperty().bind(widthProperty().subtract((yAxisWidth+yAxisSeparation)*backCharts.size()));
return lineChart;
}
private Node resizeBackgroundChart(LineChart lineChart) {
HBox hBox = new HBox(lineChart);
hBox.setAlignment(Pos.CENTER_LEFT);
hBox.prefHeightProperty().bind(heightProperty());
hBox.prefWidthProperty().bind(widthProperty());
hBox.setMouseTransparent(true);
lineChart.minWidthProperty().bind(widthProperty().subtract((yAxisWidth + yAxisSeparation) * backCharts.size()));
lineChart.prefWidthProperty().bind(widthProperty().subtract((yAxisWidth + yAxisSeparation) * backCharts.size()));
lineChart.maxWidthProperty().bind(widthProperty().subtract((yAxisWidth + yAxisSeparation) * backCharts.size()));
lineChart.translateXProperty().bind(baseChart.getYAxis().widthProperty());
lineChart.getYAxis().setTranslateX((yAxisWidth + yAxisSeparation) * backCharts.indexOf(lineChart));
return hBox;
}
public void addSeries(XYChart.Series series, Color lineColor) {
NumberAxis yAxis = new NumberAxis();
NumberAxis xAxis = new NumberAxis();
// xAxis
xAxis.setAutoRanging(false);
xAxis.setVisible(false);
xAxis.setOpacity(0.0);
xAxis.lowerBoundProperty().bind(((NumberAxis) baseChart.getXAxis()).lowerBoundProperty());
xAxis.upperBoundProperty().bind(((NumberAxis) baseChart.getXAxis()).upperBoundProperty());
xAxis.tickUnitProperty().bind(((NumberAxis) baseChart.getXAxis()).tickUnitProperty());
// yAxis
yAxis.setSide(Side.RIGHT);
yAxis.setLabel(series.getName());
// create chart
LineChart lineChart = new LineChart(xAxis, yAxis);
lineChart.setAnimated(false);
lineChart.setLegendVisible(false);
lineChart.getData().add(series);
//HERE
for (LineChart ch : backCharts) {
ch.getYAxis().setCursor(Cursor.CLOSED_HAND);
ch.getYAxis().setOnMousePressed(event -> {
ch.getYAxis().setLabel("123");
});
}
styleBackChart(lineChart, lineColor);
setFixedAxisWidth(lineChart);
backCharts.add(lineChart);
}
private void styleBackChart(LineChart lineChart, Color lineColor) {
setStyle(lineChart, lineColor);
Node contentBackground = lineChart.lookup(".chart-content").lookup(".chart-plot-background");
contentBackground.setStyle("-fx-background-color: transparent;");
lineChart.setVerticalZeroLineVisible(false);
lineChart.setHorizontalZeroLineVisible(false);
lineChart.setVerticalGridLinesVisible(false);
lineChart.setHorizontalGridLinesVisible(false);
lineChart.setCreateSymbols(false);
lineChart.getXAxis().setStyle("-fx-font-size:" + 18);
lineChart.getYAxis().setStyle("-fx-font-size:" + 18);
}
private String toRGBCode(Color color) {
return String.format("#%02X%02X%02X",
(int) (color.getRed() * 255),
(int) (color.getGreen() * 255),
(int) (color.getBlue() * 255));
}
private void setStyle(LineChart chart, Color lineColor) {
chart.getYAxis().lookup(".axis-label").setStyle("-fx-text-fill: " + toRGBCode(lineColor) + "; -fx-font-size: 24;");
Node seriesLine = chart.lookup(".chart-series-line");
seriesLine.setStyle("-fx-stroke: " + toRGBCode(lineColor) + "; -fx-stroke-width: " + strokeWidth + ";");
}
public Node getLegend() {
HBox hbox = new HBox();
final CheckBox baseChartCheckBox = new CheckBox(baseChart.getYAxis().getLabel());
baseChartCheckBox.setSelected(true);
baseChartCheckBox.setDisable(true);
baseChartCheckBox.getStyleClass().add("readonly-checkbox");
baseChartCheckBox.setOnAction(event -> baseChartCheckBox.setSelected(true));
hbox.getChildren().add(baseChartCheckBox);
for (final LineChart lineChart : backCharts) {
CheckBox checkBox = new CheckBox(lineChart.getYAxis().getLabel());
checkBox.setSelected(true);
checkBox.setOnAction(event -> {
if (backCharts.contains(lineChart)) {
backCharts.remove(lineChart);
} else {
backCharts.add(lineChart);
}
});
hbox.getChildren().add(checkBox);
}
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(20);
hbox.setStyle("-fx-padding: 0 10 20 10");
return hbox;
}
public int is_formatType() {
return _formatType;
}
public void set_formatType(int formatType) {
this._formatType = formatType;
this.requestLayout();
}
}
Regards,
Julia.

how can i call the JavaFX_Charts Application from java and update its values

I have created a gui application that reads some data and stores them in a file. I want to call from java the JavaFX_Charts application to create and show me on screen the data from file.
The file contains two columns with numbers one for each axis's. I read the file and create two
List<Integer> l1 = new ArrayList<Integer>();
List<Integer> l2 = new ArrayList<Integer>();
How can I call JavaFX_Charts and update it with my values on the 2 lists?
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class JavaFX_Charts extends Application {
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
root.getChildren().add(createChart());
}
protected LineChart<Number, Number> createChart() {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number, Number> lc = new LineChart<Number, Number>(
xAxis, yAxis);
// setup chart
lc.setTitle("Basic LineChart");
xAxis.setLabel("X Axis");
yAxis.setLabel("Y Axis");
// add starting data
XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
series.setName("Data Series 1");
series.getData().add(new XYChart.Data<Number, Number>(20d, 50d));
series.getData().add(new XYChart.Data<Number, Number>(40d, 80d));
series.getData().add(new XYChart.Data<Number, Number>(50d, 90d));
series.getData().add(new XYChart.Data<Number, Number>(70d, 30d));
series.getData().add(new XYChart.Data<Number, Number>(170d, 122d));
lc.getData().add(series);
return lc;
}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have created two list and filled it up with Random data, then parsing the list to fill the data into the chart
An example to show populating data from list
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class JavaFX_Charts extends Application {
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
root.getChildren().add(createChart());
}
protected LineChart<Number, Number> createChart() {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number, Number> lc = new LineChart<Number, Number>(
xAxis, yAxis);
// setup chart
lc.setTitle("Basic LineChart");
xAxis.setLabel("X Axis");
yAxis.setLabel("Y Axis");
// add starting data
List<Integer> l1 = new ArrayList<Integer>();
List<Integer> l2 = new ArrayList<Integer>();
//Populating the List with Random data
for(int i=0; i<10; i++){
l1.add((int) (Math.random()*10*i));
l2.add((int) (Math.random()*10*i));
}
XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
series.setName("Data Series 1");
//Fetching data from the list
/**
* Using the size of l1, taking into
* consideration that l1 and l2 are of same size
*/
for(int i=0; i<l1.size(); i++){
series.getData().add(new XYChart.Data<Number, Number>(l1.get(i), l2.get(i)));
}
lc.getData().add(series);
return lc;
}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Update as per comments
To run the same thing in a Swing application, you just need to use a JFXPanel and use the setScene() to set a JavaFX scene into it
Example with Swing
import java.util.ArrayList;
import java.util.List;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class JFX_Charts_Swing {
private static void initAndShowGUI() {
// This method is invoked on Swing thread
JFrame frame = new JFrame("Chart FX");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setBounds(400, 400, 600, 600);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
// To run on the Javafx thread
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
Group root = new Group();
Scene scene = new Scene(root);
root.getChildren().add(createChart());
fxPanel.setScene(scene);
}
protected static LineChart<Number, Number> createChart() {
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
final LineChart<Number, Number> lc = new LineChart<Number, Number>(
xAxis, yAxis);
// setup chart
lc.setTitle("Basic LineChart");
xAxis.setLabel("X Axis");
yAxis.setLabel("Y Axis");
// add starting data
List<Integer> l1 = new ArrayList<Integer>();
List<Integer> l2 = new ArrayList<Integer>();
// Populating the List with Random data
for (int i = 0; i < 10; i++) {
l1.add((int) (Math.random() * 10 * i));
l2.add((int) (Math.random() * 10 * i));
}
XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
series.setName("Data Series 1");
// Fetching data from the list
/**
* Using the size of l1, taking into consideration that l1 and l2 are of
* same size
*/
for (int i = 0; i < l1.size(); i++) {
series.getData().add(
new XYChart.Data<Number, Number>(l1.get(i), l2.get(i)));
}
lc.getData().add(series);
return lc;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
}

Resources