首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从另一个类调用javafx fxml控制器方法来更新tableview

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

Stack Overflow用户
提问于 2015-10-20 10:52:34
回答 2查看 11.6K关注 0票数 1

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

下面是我的主Application类,其中加载了fxml:

代码语言:javascript
运行
复制
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的一些部分:

代码语言:javascript
运行
复制
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(...)方法使用新项更新表视图:

代码语言:javascript
运行
复制
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实现的,但是我得到了一个:

代码语言:javascript
运行
复制
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)

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-20 12:01:08

在此过程中,只需向GlobalConfig提供对控制器的引用:

代码语言:javascript
运行
复制
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时将引用传递给控制器。

代码语言:javascript
运行
复制
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来表示回调。

代码语言:javascript
运行
复制
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();
        }
    }

}

然后你就可以

代码语言:javascript
运行
复制
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运行在后台线程中,则需要更新上的UI,您可以使用

代码语言:javascript
运行
复制
config.setMessageProcessor((SystemMessage msg) -> 
    Platform.runLater(() -> onAddSystemMessage(msg));
票数 2
EN

Stack Overflow用户

发布于 2015-10-20 12:18:25

我为解决这个问题所做的事情,-Which,我并不认为是最好的方法-:

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

2-在初始化()时调用此方法

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

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

让addSystemMessage()返回布尔值以指示消息正确地添加到DB中,如果为真,则使用systemMessages.getItems()addAll()将新的SystemMessage对象从控制器内部添加到表中

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33234712

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档