当前位置: 首页 > 知识库问答 >
问题:

从另一个类调用JavaFXML控制器方法来更新tableview

东郭源
2023-03-14

我试图通过从另一个应用程序实用程序类方法GlobalConfig.addSystemMessage()调用特定的方法FXMLDocumentController.onAddSystemMessage()来更新在我的fxml控制器中定义的javafx表视图。

这里是我加载fxml的主要应用程序类:

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是一个实用程序类,它有一些从数据库获取参数的方法,还可以执行一些工作,例如向数据库表添加一些新值。它是从我的应用程序的几个部分调用的,我想获取当前的FXMLDocumentController对象,并调用其方法onAddSystemMessage()来更新UI

以上实现是根据:访问FXML控制器类,但我得到一个:

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)

希望我的目标是明确的,上面的方法没有超出范围。

共有2个答案

梁丘璞瑜
2023-03-14

我为解决这个问题所做的——我并不认为这是最好的方法——:

1-在控制器中使用名为reload的新方法,该方法从数据库加载实体,并将所有实体添加到表中。

2-在initialize()上调用此方法

3-将控制器传递给addSystemMessage()方法(或其他一致性包装方法),并在其末尾调用reload(这就是为什么它可能不太好,因为它涉及到对数据库的另一个调用,但如果您希望确保数据同步,它会很有用)

我没有尝试过的其他方法:

1-让addSystemMessage()返回布尔值,以指示消息被正确添加到数据库,如果为真,则使用system Messages.getItem()addAll()从控制器内部将新的SystemMessage对象添加到表中

2-可能有更好的方法使用javafx绑定将UI表对象与其他与数据库同步的对象绑定(我没有搜索到这个,所以我不确定它的可行性)

金晨
2023-03-14

一个简单的方法是给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到controller类的依赖关系(也就是说,除非你在一个有控制器的环境中,否则你不能重用它)。换句话说,这里有太多的紧密耦合。更好的方法是将功能从控制器抽象到回调,您可以用使用者表示回调

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));

 类似资料:
  • 我想在单击该按钮时从interface_pasienController上的Interface_adminController调用autoRefresh()方法。但是有一个错误“java.lang.NullPointerException”。代码怎么了? 线程“JavaFX Application thread”java.lang.RuntimeException中的异常:java.lang.Re

  • 我有一个进度条,我试图在控制器的javaFX中更新它。我正在根据一个名为Generate()的函数更新进度条,如果它被调用,它应该更新主控制器内的进度条。但是,我拥有的代码不会更新它,而是更新了进度条的新实例。 我的DrawerContentController中的Generate方法是: 在我的主控制器中,我使用场景构建器通过fxml设置了进度条,我正在尝试从DrawerContentContr

  • 问题内容: 我试图通过使用变量在第一控制器中调用第二控制器的方法。这是我的第一个控制器中的一种方法: 我可以设置的值,但是由于某种原因我不能打电话。控制台显示此错误: TypeError:对象#没有方法’getMainCategories’ 有没有一种方法可以调用上述方法? 编辑: 我使用以下方法同时加载两个应用程序。 我肯定可以在这里使用服务,但我想知道是否还有其他选择可以这样做! 问题答案:

  • 问题内容: 在Python中,有没有一种方法可以从另一个类中调用一个类方法?我正在尝试在Python中旋转自己的MVC框架,但无法弄清楚如何从另一个类的一个类调用方法。 这是我想发生的事情: 我正在从PHP慢慢进入Python,因此我正在寻找与PHP等效的Python 。 问题答案: 更新:刚刚在您的帖子中看到了对它的引用。那不一样。用于获取函数对象,然后使用您的参数调用它 现在是一个实际的函数对

  • 我一直在使用Scala的Play框架,但遇到了一些麻烦。 我试图从控制器方法调用另一个控制器方法。起初,我试图使用WSRequest/响应来调用其他控制器方法的路由,但是WS响应不包含任何内容!没有Cookies或标头,即使控制器的方法会返回重定向。 此外,我不确定如何直接调用Controller方法,因为它返回一个EssentialAction,但第一个方法使用隐式请求ActionAsync方法

  • 问题内容: 我正在研究一个问题,但由于刚开始学习Java而感到非常困惑。我可以理解的任何帮助都会很棒。我必须编写一个具有两个类的程序。主类将从文件中读取内容,并使用第二类来查找文件中相同单词被重复的次数,然后将它们添加到包含单词和单词重复次数的数组中。我可以阅读文件部分。我只是似乎不知道如何从第二个类调用方法以将单词添加到数组并增加计数器。到目前为止,这是我的代码,如果您运行它,您将看到多少错误会