Исключение noSuchMethod () при расширении javafx.scene.chart.Линейная диаграмма

#java #javafx #javafx-2

#java #javafx #javafx-2

Вопрос:

Я пытаюсь расширить javafx.scene.chart.LineChart , чтобы добавить некоторые дополнительные функции.

Я реализовал два конструктора

public LiveLineChart(Timeline animation, Axis<Number> xAxis, Axis<Number> yAxis)

и

public LiveLineChart(Timeline animation, Axis<Number> xAxis, Axis<Number> yAxis, ObservableList<Series<Number, Number>> data)

Однако мой проект компилируется, когда я запускаю, я получаю следующее:

 Caused by: java.lang.NoSuchMethodException: org.mypackage.LiveLineChart.<init>()
at java.lang.Class.getConstructor0(Class.java:2971)
at java.lang.Class.newInstance(Class.java:403)
... 20 more
  

Если я пытаюсь реализовать конструктор по умолчанию (пустой), я получаю ошибку компиляции:

 no suitable constructor found for LineChart(no arguments)
constructor LineChart.LineChart(Axis<Number>,Axis<Number>) is not applicable
  (actual and formal argument lists differ in length)
constructor LineChart.LineChart(Axis<Number>,Axis<Number>,ObservableList<Series<Number,Number>>) is not applicable
  (actual and formal argument lists differ in length)
  

Чего мне не хватает, чтобы запустить это?

Ответ №1:

LineChart не имеет конструктора по умолчанию, поэтому вам нужно вызвать один из конструкторов, которые он объявляет явно из определенного вами конструктора. Глядя на конструкторы, которые, по вашим словам, вы объявили, вам, вероятно, нужно что-то вроде этого:

 public LiveLineChart(Timeline animation, Axis<Number> xAxis, Axis<Number> yAxis) {
    super(xAxis, yAxis);
    // ...
}

public LiveLineChart(Timeline animation, Axis<Number> xAxis, Axis<Number> yAxis, ObservableList<Series<Number, Number>> data) {
    super(xAxis, yAxis, data) ;
    // ...
}
  

Если вы хотите иметь возможность создавать LiveLineChart из FXML , вам нужен либо конструктор без аргументов, либо класс builder . Конструктор без аргументов не оставит вам никакого механизма для инициализации осей (поскольку они управляются вашим суперклассом и являются неизменяемыми, т. Е. Невозможно установить их после вызова конструктора суперкласса). Поэтому вам, скорее всего, потребуется определить следующее:

 public class LiveLineChartBuilder {
    private Axis<Number> xAxis ;
    private Axis<Number> yAxis ;
    private Timeline animation ;
    private ObservableList<Series<Number,Number>> data ;

    public static LiveLineChartBuilder create() {
        return new LiveLineChartBuilder();
    }

    public LiveLineChartBuilder xAxis(Axis<Number> xAxis) {
        this.xAxis = xAxis ;
        return this ;
    }

    public LiveLineChartBuilder yAxis(Axis<Number> yAxis) {
        this.yAxis = yAxis ;
        return this ;
    }

    public LiveLineChartBuilder animation(Timeline animation) {
        this.animation = animation ;
        return this ;
    }

    public LiveLineChartBuilder data(Series<Number, Number> data) {
        this.data = data ;
        return this ;
    }

    public LiveLineChart build() {
        // if else may not be necessary, depending on how you define constructors in LiveLineChart
        if (data == null) {
            return new LiveLineChart(animation, xAxis, yAxis);
        } else {
            return new LiveLineChart(animation, xAxis, yAxis, data);
        }
    }
}
  

Это позволит вам сделать

 <LiveLineChart>
<xAxis><NumberAxis><!-- ... --></NumberAxis></xAxis>
<!-- etc -->
</LiveLineChart>
  

в вашем FXML.

Комментарии:

1. Все это выглядит хорошо, но тогда как мне на самом деле ИСПОЛЬЗОВАТЬ конструктор?

2. Вы этого не делаете. Загрузчик FXML автоматически использует его, если у связанного класса нет конструктора по умолчанию. (Он сопоставляет класс X по имени класса с XBuilder .)

Ответ №2:

Поскольку в нем нет конструктора по умолчанию LineChart , и вам нужно явно вызвать один из конструкторов базового класса или использовать цепочку конструкторов:

 public LiveLineChart() {
    super(new ValueAxis<Number>(), new ValueAxis<Number>()); // use LineChart.LineChart(Axis<Number>,Axis<Number>)
    // do further initialisation
}
  

или

 public LiveLineChart() {
    this(new ValueAxis<Number>(), new ValueAxis<Number>()); // use LiveLineChart(Timeline animation, Axis<Number> xAxis, Axis<Number> yAxis)
    // do further initialisation
}
  

Конечно, вы можете использовать любой другой тип оси вместо ValueAxis too .

Комментарии:

1. Спасибо. Я уже многое понял. Проблема сейчас в том, что, хотя я теперь могу компилировать, у меня, похоже, возникла проблема с загрузкой его через объявление FXML, и теперь я получаю следующую ошибку: Вызвано: com.sun.javafx.fxml. Исключение PropertyNotFoundException: свойство «xAxis» не существует или доступно только для чтения. Мое свойство xAxis, определенное в LiveLineChart, определяется следующим образом: @FXML public NumberAxis xAxis;

2. Вы должны инициализировать оси в конструкторе суперкласса; поэтому конструктор без аргументов, вероятно, здесь не будет работать. Для этого вам понадобится класс builder, чтобы FXMLLoader он мог создать экземпляр вашего класса. Смотрите Альтернативный ответ ниже.

Ответ №3:

Поскольку я не могу комментировать, я буду использовать блок ответов. Я никогда не работал с javafx, но это простая проблема java. Определили ли вы конструктор по умолчанию во втором подходе? Похоже, его нет. Загрузчику классов требуется конструктор по умолчанию (без параметров)

Комментарии:

1. Я не уверен, что следую … как указано выше, когда я пытаюсь добавить конструктор по умолчанию без аргументов, я получаю ошибку компиляции, упомянутую выше. Кажется, это говорит о том, что класс, который я пытаюсь расширить, не имеет конструктора по умолчанию.

2. Да, он пытается сказать вам, что LineChart не имеет конструктора по умолчанию. Вы добавляете конструктор по умолчанию в подкласс (ваш класс)? Из вашего конструктора по умолчанию вам нужно будет вызвать super с соответствующими параметрами.