1

別のアプリケーション ユーティリティ クラス メソッド GlobalConfig.addSystemMessage() から特定のメソッド FXMLDocumentController.onAddSystemMessage() を呼び出して、fxml コントローラで定義された javafx テーブルビューを更新しようとしています。

fxmlをロードするメインのApplicationクラスは次のとおりです。

public class Main extends Application {
    ...
    public static void main(String[] args) throws IOException {
        Application.launch(args);
    }
    ...
    @Override
    public void start(Stage primaryStage) throws IOException {
        AnchorPane page = (AnchorPane) FXMLLoader.load(Main.class.getResource("FXMLDocument.fxml"));
        Scene scene = new Scene(page, initWidth, initHeight);
        primaryStage.setScene(scene);

        currentPane(scene, page);
        primaryStage.show();
    }

FXMLDocumentController の一部を次に示します。

public class FXMLDocumentController implements Initializable {
    ...
    @FXML
    private TableView<SystemMessage> systemMessages;
    @FXML
    private TableColumn<SystemMessage, DateTime> dateSysReceived;
    @FXML
    private TableColumn<SystemMessage, String> messageText;
    @FXML
    private TableColumn<SystemMessage, String> messageType;
    ...
    private ObservableList<SystemMessage> messagesData;
    ...
    private GlobalConfig globalConfig;
    ...
    @Override
    @FXML
    public void initialize(URL url, ResourceBundle rb) {
        config = new GlobalConfig();
        ...
        messagesData = FXCollections.observableArrayList();
        messagesData = getAllMessages();
        systemMessages.getItems().setAll(messagesData);
        dateSysReceived.setCellValueFactory(new PropertyValueFactory<>("dateSysReceived"));
        messageText.setCellValueFactory(new PropertyValueFactory<>("messageText"));
        messageType.setCellValueFactory(new PropertyValueFactory<>("messageType"));
    ...
    }
    ...
    private ObservableList<SystemMessage> getAllMessages() {
        ObservableList<SystemMessage> data = FXCollections.observableArrayList();
        data = FXCollections.observableArrayList();

        SystemMessageDAO msgDAO = new SystemMessageDAOImpl();
        List<SystemMessage> allMessages = new ArrayList<>();
        allMessages = msgDAO.listSystemMessage();

        for(SystemMessage msg: allMessages) {
            data.add(msg);
        }

        return data;
    }
    ... // and here is the method that i would like to call to add new record to tableview

    public void onAddSystemMessage(SystemMessage systemMessage) {
        log.info("Add System Message called!");
        // to DO ... add item to tableview
        //this method should be called when inserting new systemMessage (DAO)
    }

これは、システム メッセージをデータベースに追加するためのメソッドを備えたユーティリティ クラスでもあります。さらに、 FXMLDocumentController.onAddSystemMessage(...) メソッドを呼び出して、テーブルビューを新しいアイテムで更新したいと思います:

public final class GlobalConfig {
    ...
    //constructor
    public GlobalConfig () {
        ...
    }

    public void addSystemMessage(String messageText, String messageType) {

        SystemMessage msg = new SystemMessage();
        DateTime cur = DateTime.now();

        try {
            msg.setDateSysReceived(cur);
            msg.setMessageText(messageText);
            msg.setMessageType(messageType);
            SystemMessageDAO msgDAO = new SystemMessageDAOImpl();
            msgDAO.addSystemMessage(msg);

            FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocumentController.fxml"));
            FXMLDocumentController controller = (FXMLDocumentController)loader.getController();
            //just call my Controller method and pass msg
            controller.onAddSystemMessage(msg);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • GlobalConfig は、db テーブルに新しい値を追加するなどのジョブを実行するだけでなく、db からパラメーターを取得するためのいくつかのメソッドを持つユーティリティ クラスです。アプリケーションのいくつかの部分から呼び出され、現在の FXMLDocumentController オブジェクトを取得し、そのメソッド onAddSystemMessage() を呼び出して UI を更新したいと考えています。

上記の実装は次のとおりです: Accessing FXML controller class but I am get a:

java.lang.NullPointerException
at com.npap.utils.GlobalConfig.addSystemMessage(GlobalConfig.java:85)
at com.npap.dicomrouter.FXMLDocumentController.startDcmrcvService(FXMLDocumentController.java:928)
at com.npap.dicomrouter.FXMLDocumentController.initialize(FXMLDocumentController.java:814)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at com.npap.dicomrouter.Main.start(Main.java:141)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$174(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)

私の目的が明確で、上記のアプローチが範囲外でないことを願っています。

4

2 に答える 2

2

途中でGlobalConfig、コントローラーへの参照を与えるだけです。

public final class GlobalConfig {

    private FXMLDocumentController controller ;

    public void setController(FXMLDocumentController controller) {
        this.controller = controller ;
    }

    ...
    public void addSystemMessage(String messageText, String messageType) {

        SystemMessage msg = new SystemMessage();
        DateTime cur = DateTime.now();

        try {
            msg.setDateSysReceived(cur);
            msg.setMessageText(messageText);
            msg.setMessageType(messageType);
            SystemMessageDAO msgDAO = new SystemMessageDAOImpl();
            msgDAO.addSystemMessage(msg);

            if (controller != null) {
                controller.onAddSystemMessage(msg);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

次に、作成時にコントローラーへの参照を渡しますGlobalConfig

public void initialize(URL url, ResourceBundle rb) {
    config = new GlobalConfig();
    config.setController(this));
    ...
    messagesData = FXCollections.observableArrayList();
    messagesData = getAllMessages();
    systemMessages.getItems().setAll(messagesData);
    dateSysReceived.setCellValueFactory(new PropertyValueFactory<>("dateSysReceived"));
    messageText.setCellValueFactory(new PropertyValueFactory<>("messageText"));
    messageType.setCellValueFactory(new PropertyValueFactory<>("messageType"));
...
}

この解決策はあまり好きではありません。GlobalConfigコントローラー クラスへの依存関係を導入するからです (つまり、コントローラーがある環境にいない限り再利用できません)。つまり、ここでは密結合が多すぎます。より良いアプローチは、コントローラーからコールバックに機能を抽象化することです。これは、次のように表すことができますConsumer<SystemMesage>

public final class GlobalConfig {

    private Consumer<SystemMessage> messageProcessor ;

    public void setMessageProcessor(Consumer<SystemMessage> messageProcessor) {
        this.messageProcessor = messageProcessor ;
    }

    ...
    public void addSystemMessage(String messageText, String messageType) {

        SystemMessage msg = new SystemMessage();
        DateTime cur = DateTime.now();

        try {
            msg.setDateSysReceived(cur);
            msg.setMessageText(messageText);
            msg.setMessageType(messageType);
            SystemMessageDAO msgDAO = new SystemMessageDAOImpl();
            msgDAO.addSystemMessage(msg);

            if (messageProcessor != null) {
                messageProcessor.accept(msg);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

そして、あなたはすることができます

public void initialize(URL url, ResourceBundle rb) {
    config = new GlobalConfig();
    config.setMessageProcessor(this::onAddSystemMessage);
    ...
    messagesData = FXCollections.observableArrayList();
    messagesData = getAllMessages();
    systemMessages.getItems().setAll(messagesData);
    dateSysReceived.setCellValueFactory(new PropertyValueFactory<>("dateSysReceived"));
    messageText.setCellValueFactory(new PropertyValueFactory<>("messageText"));
    messageType.setCellValueFactory(new PropertyValueFactory<>("messageType"));
...
}

GlobalConfigバックグラウンド スレッドで実行している場合は、FX アプリケーション スレッドで UI を更新する必要があります。

config.setMessageProcessor((SystemMessage msg) -> 
    Platform.runLater(() -> onAddSystemMessage(msg));
于 2015-10-20T12:01:08.433 に答える
1

この問題を解決するために私がしたこと-最善のアプローチであるとは主張していません-:

1- reload と呼ばれるコントローラーの新しいメソッドを利用します。これは、データベースからエンティティをロードし、そのすべてをテーブルに追加します。

2- initialize() でこのメソッドを呼び出します

3- コントローラーを addSystemMessage() メソッド (またはコヒーレンスのための他のラッパー メソッド) に渡し、その最後で reload を呼び出します (そのため、データベースへの別の呼び出しを伴うため、あまり良くないかもしれませんが、必要な場合には便利です)データが同期されていることを確認してください)

私が試していない他のアプローチ:

1- addSystemMessage() がブール値を返して、メッセージが DB に正しく追加されたことを示します。true の場合、systemMessages.getItems()addAll() を使用してコントローラー内から新しい SystemMessage オブジェクトをテーブルに追加します。

2-javafxバインディングを使用して、UIテーブルオブジェクトをデータベースと同期された他のオブジェクトにバインドするより良い方法があるかもしれません(私はそれについて検索しなかったので、その実現可能性についてはわかりません)

于 2015-10-20T12:18:25.333 に答える