In java 8 it states Builders are deprecated: http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-March/006725.html
I am trying to extend a chart to add Horizontal and Vertical Markers to the chart. In this case I am extending LineChart. I wish to use said LineChart in FXML which begins throwing: java.lang.NoSuchMethodException: ...chart.LineChartWithMarkers.() this is caused by there not being a Default constructor.
Since Linechart's constructor Takes 2 Arguments for XAxis and YAxis, and builders are deprecated. How am I supposed to get FXML to be able to load my class, or did I miss something big?
I really want to Generalize this for any class that extends Node that does not have a default constructor, and working on the Java 8 (8u40+) FXML libraries. I have yet to find a definitive answer to this. All i hear is builders are being deprecated and removed completely in JDK9 but no solution to what supersedes them or what method you need to override to get this to work, if you are using it in FXML.
From what I can Tell the old way the builders would not make an instance of the class until any required fields were added.
Hopefully someone will chime in and show me what I've missed.
Java Class for Custom Chart
package custom.chart;
import java.util.Objects;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.ValueAxis;
import javafx.scene.shape.Line;
public class LineChartWithMarkers<X,Y> extends LineChart<X, Y> {
@FXML
protected ObservableList<Data<X,Y>> hzMarkers;
@FXML
protected ObservableList<Data<X,Y>> vtMarkers;
public LineChartWithMarkers(Axis<X> arg0, Axis<Y> arg1) {
super(arg0, arg1);
hzMarkers = FXCollections.observableArrayList( d -> new Observable[] { d.YValueProperty() });
vtMarkers = FXCollections.observableArrayList( d -> new Observable[] { d.XValueProperty() });
hzMarkers.addListener( (InvalidationListener)observable -> layoutPlotChildren() );
vtMarkers.addListener( (InvalidationListener)observable -> layoutPlotChildren() );
}
public LineChartWithMarkers(Axis<X> arg0, Axis<Y> arg1,
ObservableList<javafx.scene.chart.XYChart.Series<X, Y>> arg2) {
super(arg0, arg1, arg2);
hzMarkers = FXCollections.observableArrayList( d -> new Observable[] { d.YValueProperty() });
vtMarkers = FXCollections.observableArrayList( d -> new Observable[] { d.XValueProperty() });
hzMarkers.addListener( (InvalidationListener)observable -> layoutPlotChildren() );
vtMarkers.addListener( (InvalidationListener)observable -> layoutPlotChildren() );
}
@Override
protected void layoutPlotChildren() {
super.layoutPlotChildren();
for (Data<X, Y> horizontalMarker : hzMarkers) {
double lower = ((ValueAxis<?>) getXAxis()).getLowerBound();
X lowerX = getXAxis().toRealValue(lower);
double upper = ((ValueAxis<?>) getXAxis()).getUpperBound();
X upperX = getXAxis().toRealValue(upper);
Line line = (Line) horizontalMarker.getNode();
line.setStartX(getXAxis().getDisplayPosition(lowerX));
line.setEndX(getXAxis().getDisplayPosition(upperX));
line.setStartY(getYAxis().getDisplayPosition(horizontalMarker.getYValue()));
line.setEndY(line.getStartY());
}
for (Data<X, Y> verticalMarker : vtMarkers) {
double lower = ((ValueAxis<?>) getYAxis()).getLowerBound();
Y lowerY = getYAxis().toRealValue(lower);
double upper = ((ValueAxis<?>) getYAxis()).getUpperBound();
Y upperY = getYAxis().toRealValue(upper);
Line line = (Line) verticalMarker.getNode();
line.setStartX(getXAxis().getDisplayPosition(verticalMarker.getXValue()));
line.setEndX(line.getStartX());
line.setStartY(getYAxis().getDisplayPosition(lowerY));
line.setEndY(getYAxis().getDisplayPosition(upperY));
}
}
/**
* Add horizontal value marker. The marker's Y value is used to plot a
* horizontal line across the plot area, its X value is ignored.
*
* @param marker must not be null.
*/
public void addHorizontalValueMarker(Data<X, Y> marker) {
Objects.requireNonNull(marker, "the marker must not be null");
if (hzMarkers.contains(marker)) return;
Line line = new Line();
marker.setNode(line );
getPlotChildren().add(line);
hzMarkers.add(marker);
}
public void removeHorizontalValueMarker(Data<X, Y> marker) {
Objects.requireNonNull(marker, "the marker must not be null");
if (marker.getNode() != null) {
getPlotChildren().remove(marker.getNode());
marker.setNode(null);
}
hzMarkers.remove(marker);
}
public void addVerticalValueMarker(Data<X, Y> marker) {
Objects.requireNonNull(marker, "the marker must not be null");
if (hzMarkers.contains(marker)) return;
Line line = new Line();
marker.setNode(line );
getPlotChildren().add(line);
vtMarkers.add(marker);
}
public void removeVerticalValueMarker(Data<X, Y> marker) {
Objects.requireNonNull(marker, "the marker must not be null");
if (marker.getNode() != null) {
getPlotChildren().remove(marker.getNode());
marker.setNode(null);
}
vtMarkers.remove(marker);
}
}
And the FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.chart.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import custom.chart.*?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="768.0" prefWidth="1024.0" type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
<children>
<StackPane prefHeight="150.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
<children>
<Group>
<children>
<ProgressIndicator fx:id="prg" progress="0.0" />
</children>
</Group>
<LineChartWithMarkers fx:id="chart" createSymbols="false" horizontalZeroLineVisible="false" opacity="1" title="Heater Data" verticalZeroLineVisible="false">
<xAxis>
<NumberAxis forceZeroInRange="false" side="BOTTOM" fx:id="xAxis" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxis" forceZeroInRange="false" side="LEFT" />
</yAxis>
</LineChartWithMarkers>
</children>
</StackPane>
<TableView fx:id="tblChartOptions" editable="true" prefHeight="513.0" prefWidth="299.0">
<columns>
<TableColumn fx:id="txSelect" prefWidth="34.0" text="X" />
<TableColumn fx:id="tcName" editable="false" prefWidth="143.0" text="Value" />
<TableColumn fx:id="tcStyle" prefWidth="61.0" text="Style" visible="false" />
<TableColumn fx:id="tcDisplayName" prefWidth="113.0" text="Display Name" />
</columns>
</TableView>
</children>
</HBox>
<HBox alignment="BOTTOM_LEFT" nodeOrientation="RIGHT_TO_LEFT" prefWidth="200.0">
<children>
<Button fx:id="btnSaveChart" mnemonicParsing="false" onAction="#onSaveChart" text="Save Image" HBox.hgrow="ALWAYS" />
<GridPane prefWidth="320.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="X Axis Title" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Y Axis Title" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextField fx:id="txtXaxis" nodeOrientation="LEFT_TO_RIGHT" text="Time" GridPane.halignment="LEFT" GridPane.rowIndex="1" />
<TextField fx:id="txtYaxis" nodeOrientation="LEFT_TO_RIGHT" text="Temp (C)" GridPane.halignment="LEFT" GridPane.rowIndex="2" />
<CheckBox fx:id="cbIgnoreZeroValues" mnemonicParsing="false" onAction="#onZeroChangeState" text="IgnoreZeros" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Label text="Chart Title" GridPane.columnIndex="1" />
<TextField fx:id="txtChartTitle" nodeOrientation="LEFT_TO_RIGHT" text="Heater Data" />
</children>
</GridPane>
</children>
</HBox>
</children>
</fx:root>