在 java 8 中,它声明不推荐使用构建器:http: //mail.openjdk.java.net/pipermail/openjfx-dev/2013-March/006725.html
我正在尝试扩展图表以向图表添加水平和垂直标记。在这种情况下,我正在扩展 LineChart。我希望在开始抛出的 FXML 中使用所述 LineChart:java.lang.NoSuchMethodException: ...chart.LineChartWithMarkers.() 这是由于没有默认构造函数引起的。
由于 Linechart 的构造函数为 XAxis 和 YAxis 使用 2 个参数,因此不推荐使用构建器。我应该如何让 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>