В java 8 указано, что Builders устарели: http://mail.openjdk.java.net/pipermail/openjfx-dev/2013-March/006725.html
Я пытаюсь расширить диаграмму, чтобы добавить на нее горизонтальные и вертикальные маркеры. В этом случае я расширяю LineChart. Я хочу использовать указанный LineChart в FXML, который начинает бросать: java.lang.NoSuchMethodException: ...chart.LineChartWithMarkers.() это вызвано отсутствием конструктора по умолчанию.
Поскольку конструктор Linechart принимает 2 аргумента для XAxis и YAxis, компоновщики устарели. Как я должен заставить FXML загружать мой класс, или я пропустил что-то важное?
Я действительно хочу обобщить это для любого класса, расширяющего Node, который не имеет конструктора по умолчанию и работает с библиотеками Java 8 (8u40+) FXML. Я еще не нашел окончательного ответа на этот вопрос. Все, что я слышал, это то, что сборщики устарели и полностью удалены в JDK9, но нет решения о том, что их заменяет или какой метод вам нужно переопределить, чтобы заставить это работать, если вы используете его в FXML.
Насколько я могу судить, по-старому строители не создавали экземпляр класса, пока не были добавлены какие-либо обязательные поля.
Надеюсь, кто-нибудь откликнется и покажет мне, что я пропустил.
Класс Java для пользовательской диаграммы
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);
}
}
И 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>