两个 JavaFx 控制器之间的通信 [英] Communication between two JavaFx controllers

查看:39
本文介绍了两个 JavaFx 控制器之间的通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了控制器和视图 (fxml) 的结构来尽可能地分离我的代码,我想知道如何在 2 个控制器之间进行通信.我的意思是,一个控制器必须调用另一个控制器的某些功能才能将其设置为最新.

I made a structure to of Controllers and Views (fxml) to separate my code as much as I could, and I'm wondering how to communicate between 2 controllers. I mean, a controller have to call some functions of another controller to set it up to date.

我认为我当前结构的模式会更明确:

I think a schema of my current structure will be more explicit:

       控制器 1
        /        ;
   fx:include   fx:include
     /           ;  
控制器2    控制器3

          Controller 1
           /              
   fx:include    fx:include
       /                     
Controller2      Controller3

每个控制器都有自己的 fxml 视图.
- 控制器 1:一个容器控制器,它有一个带有 2 个选项卡的 TabPane 元素(每个选项卡对应 1 个控制器)
- 控制器 2:一个列表
- 控制器 3:一个表格

您可能已经猜到我希望我的表单(控制器 3)自动更新我的列表(控制器 2).目前,表单只是一个创建表单",所以我只想在我的列表中添加行.

我已经尝试使用 FXMLoader 获取我的 Controller 2 并调用函数来重新加载我的 tableView,但没有成功..

控制器 1(.java + .fxml):

Each controller has is own fxml view.
- Controller 1 : a container controller which has a TabPane element with 2 tabs (each tab correspond to 1 controller)
- Controller 2 : a list
- Controller 3 : a form

You've probably guessed that I want my form (controller 3) to automatically update my list (controller 2). For the moment, the form is only a "creation form", so I just want to add row in my list.

I've already tried to get my Controller 2 with FXMLoader and call the functions to relaod my tableView, no success..

Controller 1 (.java + .fxml) :

package pappu.controllers;

import pappu.core.controller.AbstractController;

public class FolderController extends AbstractController
{

}


<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox fx:id="view" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="pappu.controllers.FolderController">
  <TabPane>
    <tabs>
      <Tab text="RECHERCHE">
        <content>
          <AnchorPane id="Content">
            <children>
                <fx:include source="FolderList.fxml" />  
            </children>
          </AnchorPane>
        </content>
      </Tab>
      <Tab text="DOSSIER">
        <content>
          <AnchorPane id="Content">
            <children>
                <fx:include source="FolderFormAdd.fxml" />  
            </children>
          </AnchorPane>
        </content>
      </Tab>
    </tabs>
  </TabPane>
</VBox>

控制器 2(.java + .fxml):

package pappu.controllers;

import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.ResourceBundle;

import org.hibernate.Session;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.Callback;
import pappu.core.controller.AbstractController;
import pappu.entities.Folder;

public class FolderListController extends AbstractController implements Initializable
{
    /**
     * TableView object
     */
    @FXML private TableView<Folder> foldersTableView;

    /**
     * FolderNumber column object
     */
    @FXML private TableColumn<Folder, String> colFolderNumber;

    /**
     * Person column object
     */
    @FXML private TableColumn<Folder, String> colPerson;

    /**
     * Birthday date column object
     */
    @FXML private TableColumn<Folder, Date> colBirthdayDate;

    /**
     * List of folders
     */
    private static List<Folder> foldersList;

    /**
     * Constructor
     * Will make a call to initializeFoldersList()
     */
    public FolderListController()
    {
        initializeFoldersList();
    }


    /**
     * Initialize implementation of the Initializable interface
     * 
     * @param location
     * @param resources
     */
    @Override 
    public void initialize(URL location, ResourceBundle resources) 
    {
        initializeTableColumns();
        loadData();
    }

    /**
     * Query the database to retrieve the folder list
     */
    @SuppressWarnings("unchecked") 
    public void initializeFoldersList()
    {
        Session session = sessionFactory.getCurrentSession();
        session.beginTransaction();
        foldersList = session.createQuery("from Folder").list();
        session.close();
    }

    /**
     * Initialize columns binding to folders properties
     */
    public void initializeTableColumns()
    {
        colFolderNumber.setCellValueFactory(
                  new PropertyValueFactory<Folder,String>("folderNumber")
                      );
        colPerson.setCellValueFactory(
                new Callback<CellDataFeatures<Folder, String>, ObservableValue<String>>() {
                     public ObservableValue<String> call(CellDataFeatures<Folder, String> p) {
                         return new SimpleStringProperty(p.getValue().getFirstName() + " " + p.getValue().getLastName());
                     }}
          );
        colBirthdayDate.setCellValueFactory(
                  new PropertyValueFactory<Folder,Date>("birthdayDate")
                      );

    }

    /**
     * Put the folders list in the TableView object
     */
    public void loadData()
    {   
        ObservableList<Folder> listFold = FXCollections.observableArrayList(foldersList);       
        foldersTableView.setItems(listFold);
    }   
}


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

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.Label?>


<VBox fx:id="view" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="pappu.controllers.FolderListController">
    <Label fx:id="lblTest"></Label>
    <TableView fx:id="foldersTableView">
        <columns>
            <TableColumn prefWidth="75.0" text="N°" fx:id="colFolderNumber">
            </TableColumn>
            <TableColumn prefWidth="75.0" text="Personne" fx:id="colPerson">
            </TableColumn>
            <TableColumn prefWidth="75.0" text="Date de naissance" fx:id="colBirthdayDate">
            </TableColumn>
        </columns>
    </TableView>
</VBox>

控制器 3 (.java + .fxml):

package pappu.controllers;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import org.hibernate.Session;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import pappu.core.AppFactory;
import pappu.core.controller.AbstractController;
import pappu.entities.Folder;
import pappu.entities.Gender;

public class FolderFormAddController extends AbstractController
{   
    @FXML TextField folderNumber;
    @FXML TextField firstName;
    @FXML TextField lastName;
    public void submitForm() throws IOException
    {   
        Session session = sessionFactory.getCurrentSession();
        session.beginTransaction();

        Folder folder = new Folder();

        folder.setFolderNumber(folderNumber.getText());
        folder.setFirstName(firstName.getText());
        folder.setLastName(lastName.getText());
        folder.setGender(Gender.m);

        session.save(folder);
        session.getTransaction().commit();
            // This doesn't work.. even tried with a simple Label
        AppFactory app = new AppFactory();
        FolderListController flc = app.folderListController();
        flc.initializeFoldersList();
        flc.loadData();
    }
}


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

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox fx:id="view" prefHeight="216.0" prefWidth="421.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="pappu.controllers.FolderFormAddController">
  <children>
    <Label prefHeight="26.0" prefWidth="102.0" text="Numéro de dossier" />
    <TextField prefWidth="200.0" fx:id="folderNumber"/>
    <Label text="Prénom" />
    <TextField prefWidth="200.0" fx:id="firstName"/>
    <Label text="Nom" />
    <TextField prefWidth="200.0" fx:id="lastName"/>
    <Button mnemonicParsing="false" onAction="#submitForm" text="Enregistrer" />
  </children>
</VBox>

精确度:
我在这个基础上提出了我的申请:http://www.zenjava.com/2011/10/25/views-within-views-controllers-within-controllers/,我在 Java JDK 7 上使用 JavaFX 2

Precisions:
I made my application on this base: http://www.zenjava.com/2011/10/25/views-within-views-controllers-within-controllers/ and I use JavaFX 2 on Java JDK 7

我觉得 JavaFX 应用程序的全局功能缺失了一些东西.

I feel something missing in global functioning of a JavaFX application.

推荐答案

我想到了两种方法:

  1. 基于FXML 简介"的嵌套控制器"部分(link),您可以将子控制器(2 和 3)注入父控制器 (1) 并让父控制器协调它们的交互:

  1. Based on the "Nested Controllers" section of "Introduction to FXML" (link), you could inject the children controllers (2 & 3) into the parent (1) and have the parent coordinate their interactions:

FXML (1):

<fx:include source="FolderList.fxml" fx:id="list" />
...
<fx:include source="FolderFormAdd.fxml" fx:id="addForm" />

Java (1)(注意字段的名称;必须匹配 Controller,即):

Java (1) (beware the names of the fields; must match <fx:id>Controller, i.e.):

public class FolderController extends AbstractController {
    @FXML private FolderListController listController;
    @FXML private FolderFormAddController addFormController;
    void initialize() {
        // add code to coordinate them
    }
}

我不太喜欢这种情况下的解决方案,因为它会导致组件之间的强耦合.另一方面,它可能是最快的.

I do not like this solution much for this case, as it leads to strong coupling between the components. On the other hand, it may be the quickest.

使用事件总线(例如来自 Google Guava).这实际上可以解耦您的逻辑(例如,列表组件侦听 PersonAdded 事件,无论它是如何创建的;表单生成此事件,而不关心谁在侦听 - 如果有的话).我想在你的情况下我更喜欢这个解决方案.可以选择使用依赖注入来检索事件总线.

Use an event bus (e.g. from Google Guava). This can actually decouple your logic (e.g. the list component listens to the PersonAdded event, no matter how it was created; the form generates this event, without caring who is listening - if any). I think I would prefer this solution in your case. The event bus can optionally be retrieved using dependency injection.

查看jewelsea评论中指出的答案,很棒 - 我自己已经投票了:)

Check out the answer pointed by the comment from jewelsea, it is great - I have already upvoted it myself :)

这篇关于两个 JavaFx 控制器之间的通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆