1

I have two XY charts and I want them to be placed one on the top and the other at the bottom of a JavaFX application.

Both graph widths should fill their "container" and the bottom graph should be x times smaller than the top graph.

For the sake of reproducibility, here is an example built from Oracle's tutorial:

import javafx.application.Application;
import javafx.geometry.Side;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Test extends Application {

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart Sample");
        final CategoryAxis xAxis1 = new CategoryAxis();
        final NumberAxis yAxis1 = new NumberAxis();
        xAxis1.setLabel("Month");
        final LineChart<String, Number> lineChart1 =
                new LineChart<>(xAxis1, yAxis1);

        final CategoryAxis xAxis2 = new CategoryAxis();
        xAxis2.setLabel("Month");
        final NumberAxis yAxis2 = new NumberAxis();
        final LineChart<String, Number> lineChart2 =
                new LineChart<>(xAxis2, yAxis2);

        lineChart1.setLegendVisible(false);
        lineChart2.setLegendVisible(false);

        XYChart.Series series1 = new XYChart.Series();
        series1.setName("Portfolio 1");

        series1.getData().add(new XYChart.Data("Jan", 23));
        series1.getData().add(new XYChart.Data("Feb", 14));
        series1.getData().add(new XYChart.Data("Mar", 15));
        series1.getData().add(new XYChart.Data("Apr", 24));
        series1.getData().add(new XYChart.Data("May", 34));
        series1.getData().add(new XYChart.Data("Jun", 36));
        series1.getData().add(new XYChart.Data("Jul", 22));
        series1.getData().add(new XYChart.Data("Aug", 45));
        series1.getData().add(new XYChart.Data("Sep", 43));
        series1.getData().add(new XYChart.Data("Oct", 17));
        series1.getData().add(new XYChart.Data("Nov", 29));
        series1.getData().add(new XYChart.Data("Dec", 25));

        XYChart.Series series2 = new XYChart.Series();
        series2.setName("Portfolio 2");
        series2.getData().add(new XYChart.Data("Jan", 33));
        series2.getData().add(new XYChart.Data("Feb", 34));
        series2.getData().add(new XYChart.Data("Mar", 25));
        series2.getData().add(new XYChart.Data("Apr", 44));
        series2.getData().add(new XYChart.Data("May", 39));
        series2.getData().add(new XYChart.Data("Jun", 16));
        series2.getData().add(new XYChart.Data("Jul", 55));
        series2.getData().add(new XYChart.Data("Aug", 54));
        series2.getData().add(new XYChart.Data("Sep", 48));
        series2.getData().add(new XYChart.Data("Oct", 27));
        series2.getData().add(new XYChart.Data("Nov", 37));
        series2.getData().add(new XYChart.Data("Dec", 29));

        lineChart1.getData().addAll(series1);
        lineChart2.getData().addAll(series2);

        Scene scene = new Scene(createVBoxLayout(lineChart1, lineChart2), 800, 600);

        stage.setScene(scene);
        stage.show();
    }

    private Parent createVBoxLayout(XYChart chart1, XYChart chart2) {
        VBox vBox = new VBox(chart1, chart2);
        chart1.prefHeight(200);
        chart1.minHeight(200);
        chart1.maxHeight(200);
        chart2.prefHeight(400);
        chart2.minHeight(400);
        chart2.maxHeight(400);
        return vBox;
    }

    private Parent createGridLayout(XYChart chart1, XYChart chart2) {
        GridPane gridPane = new GridPane();
        gridPane.add(chart1, 0, 0, 1, 1);
        gridPane.add(chart2, 0, 1, 1, 2);

        return gridPane;
    }

    public static void main(String[] args) {
        launch(args);
    }

}

The graph on the bottom should be twice as big as the one on the top.

I have tried two approaches:

  • Method createVBoxLayout creates a VBox and uses the prefered/min/max sizes to modify the chart size.

Here is the result:

enter image description here

Clearly, the bottom graph is not twice as big as the graph at the top. Moreover, the size ratio would not be kept when the window is resized.

  • The method createGridLayout creates a GridPane, here is the result:

enter image description here

Now, it's the top graph that is twice as big as the bottom one, which is the opposite of what is coded in the method! Moreover, the graphs do not fill the width of the window. Finally, when resizing the window, the charts overlap and don't keep their relative sizes (should be 1/3 - 2/3).

Ben
  • 6,321
  • 9
  • 40
  • 76

1 Answers1

1

The methods prefHeight(...), minHeight(...), etc do not set the preferred height, etc. They return the computed values for those, with the argument being the width for the chart (i.e. chart1.prefHeight(200) means "tell me the preferred height if the width is 200"). See the documentation.

You need

chart1.setPrefHeight(200);
chart1.setMinHeight(200);
chart1.setMaxHeight(200);

etc.

For the grid pane version, use RowConstraints and ColumnConstraints to control the layout of the grid. The rows are simply resized to contain the nodes they contain, so making a chart span two rows will probably just give one of the rows zero height. (Again, see the documentation.)

private Parent createGridLayout(XYChart chart1, XYChart chart2) {
    GridPane gridPane = new GridPane();
    gridPane.add(chart1, 0, 0, 1, 1);
    gridPane.add(chart2, 0, 1, 1, 2);

    RowConstraints top = new RowConstraints(200);
    RowConstraints bottom = new RowConstraints(400);
    gridPane.getRowConstraints().addAll(top, bottom);

    ColumnConstraints cc = new ColumnConstraints();
    cc.setHgrow(Priority.ALWAYS);
    gridPane.getColumnConstraints().add(cc);

    return gridPane;
}

or

private Parent createGridLayout(XYChart chart1, XYChart chart2) {
    GridPane gridPane = new GridPane();
    gridPane.add(chart1, 0, 0);
    gridPane.add(chart2, 0, 1);

    RowConstraints top = new RowConstraints();
    top.setPercentHeight(100.0 / 3.0);
    RowConstraints bottom = new RowConstraints();
    bottom.setPercentHeight(200.0 / 3.0);
    gridPane.getRowConstraints().addAll(top, bottom);

    ColumnConstraints cc = new ColumnConstraints();
    cc.setHgrow(Priority.ALWAYS);
    gridPane.getColumnConstraints().add(cc);

    return gridPane;
}
James_D
  • 201,275
  • 16
  • 291
  • 322