Почему я не могу сгенерировать карту, используя текстовые поля JavaFX, вызвав метод из другого класса? - PullRequest
2 голосов
/ 11 октября 2019

* Я новичок в Java / программировании.

Я написал следующие примеры кода, чтобы попытаться выяснить мою проблему, а затем дать четкие примеры моей проблемы. Я хочу, чтобы моя программа была разделена на отдельные классы на основе их функций в приложении: Main MainController - управляет графическим интерфейсом JavaFX. Инициализатор - семантическая проверка введенных данных. Модель - выполняет расчеты с данными и отправляет результаты обратно в MainController.

Я застрял в том, что инициализатор, в частности, связанная карта и первая проверка, выдают исключение nullpointerexception. ЭТОГО НЕ случается, если все в одном классе (я начал со всего в одном классе, сейчас учусь структурировать в отдельных классах и т. Д.). Это также не произойдет, если я не использую какие-либо функции JavaFX.

Например, это работает:

package helloWorld;
public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello world!");

        HashmapExample hashy = new HashmapExample();

        System.out.println(hashy.initialiser());
    }
}
package helloWorld;

import java.util.LinkedHashMap;
import java.util.Map;

public class HashmapExample {

    private Map<String,String> testMap = new LinkedHashMap<>();

    public void mapper() {

    testMap.put("one","a");
    testMap.put("two","b");
    testMap.put("three","c");

    }

    public String initialiser() {

        mapper();

        String errorField = testMap.entrySet().stream().filter(entry -> entry.getKey().isBlank()).map(Map.Entry::getValue).findFirst().orElse(null);

        String message;

        if (errorField != null) {
            return message = errorField + " blank!";
        } else {
            return message = "OK!";
        }

    }

}

Ноэто не так:

package helloWorldFX;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = (VBox)FXMLLoader.load(getClass().getResource("MainGUI.fxml"));
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;

public class MainController {

    @FXML private TextArea outputMessage;

    public void run(ActionEvent event) {

        Initialiser initialiser = new Initialiser();

        outputMessage.setText(initialiser.checker());

    }

}
package helloWorldFX;

import java.util.LinkedHashMap;
import java.util.Map;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;

public class Initialiser {

    @FXML   private TextField one;
    @FXML   private TextField two;
    @FXML   private TextField three;

private Map<TextField,String> testMap = new LinkedHashMap<>();

    public void mapper() {

    testMap.put(one,"a");
    testMap.put(two,"b");
    testMap.put(three,"c");

    }

    public String checker() {

        mapper();

        String errorField = testMap.entrySet().stream().filter(entry -> entry.getKey().getText().isBlank()).map(Map.Entry::getValue).findFirst().orElse(null);

        String message;

        if (errorField != null) {
            return message = errorField + " blank!";
        } else {
            return message = "OK!";
        }

    }

}

Когда я выполняю охват покрытия в затмении, я могу сказать, что это, вероятно, вызвано линией String errorField = testMap.entrySet().stream().filter(entry -> entry.getKey().isBlank()).map(Map.Entry::getValue).findFirst().orElse(null);, но я неполностью уверен.

Я только что заметил в конструкторе сцены, что поля 'one', 'two' и 'three' не отображаются в качестве допустимых идентификаторов для текстовых полей, потому что они не находятся вкласс MainController. Это должно быть как-то связано с проблемой, но я не понимаю, как ее исправить.

Файл FXML, как и было запрошено: просто запомните, это пример кода, а неэто настоящая программа, поэтому макет бессмысленный.

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>

<VBox prefHeight="300.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="helloWorldFX.MainController">
   <children>
      <TextField />
      <TextField />
      <TextField />
      <Button mnemonicParsing="false" onAction="#run" text="Button" />
      <TextArea fx:id="outputMessage" prefHeight="200.0" prefWidth="200.0" />
   </children>
</VBox>

Сообщения об ошибках:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1787)
    at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8890)
    at javafx.controls/javafx.scene.control.Button.fire(Button.java:203)
    at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
    at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3862)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2590)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:409)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:299)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:447)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:411)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:446)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:273)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1782)
    ... 46 more
Caused by: java.lang.NullPointerException
    at helloWorldFX.Initialiser.lambda$0(Initialiser.java:29)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176)
    at java.base/java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
    at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
    at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
    at helloWorldFX.Initialiser.checker(Initialiser.java:29)
    at helloWorldFX.MainController.run(MainController.java:15)
    ... 58 more

1 Ответ

1 голос
/ 11 октября 2019

Обходной путь:

Итак, основываясь на комментариях и еще нескольких размышлениях о том, что может быть причиной, я придумал этот обходной путь.

Я создаю экземпляр и заполняю Map в MainController, а затем создаю экземпляр класса Initialiser, который теперь принимает Map в качестве параметра через конструктор. Затем я вызываю метод checker из объекта Initialiser, который выполняет семантическую проверку данных, отправленных объекту при его создании.

Насколько я могу судить, проблема в том, что один файл fxmlможет иметь дело только с одним классом контроллера, поэтому вы не можете заполнить карту TextFields из любого места, кроме основного класса контроллера. Если вы это сделаете, метод getText выдаст nullpointerexception, потому что он указывает на TextFields, который технически не существует в fxml.

См. Исправленный код:

package helloWorldFX;

import java.util.LinkedHashMap;
import java.util.Map;

import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.control.TextArea;
import javafx.event.ActionEvent;

public class MainController {

    @FXML   private TextField one;
    @FXML   private TextField two;
    @FXML   private TextField three;

    @FXML   private TextArea outputMessage;

    public void run(ActionEvent event) {

        Map<TextField, String> testMap = new LinkedHashMap<>();

        testMap.put(one,"a");
        testMap.put(two,"b");
        testMap.put(three,"c");

        Initialiser initialiser = new Initialiser(testMap);

        outputMessage.setText(initialiser.checker());

    }

}
package helloWorldFX;

import java.util.Map;

import javafx.scene.control.TextField;

public class Initialiser {

    private Map<TextField, String> values;

    public Initialiser(Map<TextField, String> mappedValues) {
        this.values = mappedValues;
    }

    String message;

    public String checker() {

        String errorField = values.entrySet().stream().filter(entry -> entry.getKey().getText().isBlank()).map(Map.Entry::getValue).findFirst().orElse(null);

        if (errorField != null) {
            return message = errorField + " blank!";
        } else {
            return message = "OK!";
        }

    }

}

На данный момент, из-за отсутствия у меня опыта, я не знаю, действительно ли это обходной путь или действительно правильный способ сделать это - может быть, кто-то может помочь заполнить эточасть в.

...