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

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

问题描述

我是新开发Java应用程序,JavaFx的MVC系统对我来说有点黑暗。


我的问题如下。我做了控制器和视图(fxml)的结构,尽可能多地分离我的代码,我想知道如何在2控制器之间通信。我的意思是,控制器必须调用另一个控制器的一些功能来设置它到最新。




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



           控制器1


             /                \


  ;  fx:include     fx:include


        /    ;                     \


Controller2  ;     Controller3



每个控制器都有自己的fxml视图。


- 控制器1:一个容器控制器,它有一个TabPane元素,有两个标签(每个标签对应一个控制器)


- 控制器2 :a list


- 控制器3:表单



你可能猜到我想要我的表单(控制器3 )自动更新我的列表(控制器2)。
现在,表单只是一个创建表单,所以我只想在我的列表中添加行。




我已经试过用FXMLoader获取Controller 2,并调用函数来重新连接我的tableView,没有成功。




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


$ b b

  package pappu.controllers; 

import pappu.core.controller.AbstractController;

public class FolderController extends AbstractController
{

}


b $ b



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

< VBox fx:id =viewxmlns:fx =http://javafx.com/fxml/1xmlns =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>

Controller 2(.java + .fxml): / strong>

  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可初始化
{
/ **
* TableView对象
* /
@FXML private TableView< Folder> ; foldersTableView;

/ **
* FolderNumber列对象
* /
@FXML private TableColumn< Folder,String> colFolderNumber;

/ **
* Person列对象
* /
@FXML private TableColumn< Folder,String> colPerson;

/ **
*生日日期列对象
* /
@FXML private TableColumn< Folder,Date> colBirthdayDate;

/ **
*文件夹列表
* /
private static List< Folder> foldersList;

/ **
*构造函数
*将调用initializeFoldersList()
* /
public FolderListController()
{
initializeFoldersList();
}


/ **
*初始化Initializable接口的实现
*
* @param location
* @ param resources
* /
@Override
public void initialize(URL location,ResourceBundle resources)
{
initializeTableColumns();
loadData();
}

/ **
*查询数据库以检索文件夹列表
* /
@SuppressWarnings(unchecked)
public void initializeFoldersList()
{
会话session = sessionFactory.getCurrentSession();
session.beginTransaction();
foldersList = session.createQuery(from Folder)。list();
session.close();
}

/ **
*初始化绑定到文件夹属性的列
* /
public void initializeTableColumns()
{
colFolderNumber.setCellValueFactory(
new PropertyValueFactory< Folder,String>(folderNumber)
);
colPerson.setCellValueFactory(
new Callback< CellDataFeatures< Folder,String>,ObservableValue< String>>(){
public ObservableValue& {
return new SimpleStringProperty(p.getValue()。getFirstName()++ p.getValue()。getLastName());
}}
);
colBirthdayDate.setCellValueFactory(
new PropertyValueFactory< Folder,Date>(birthdayDate)
);

}

/ **
*将文件夹列表放在TableView对象中
* /
public void loadData()
{
ObservableList< Folder> listFold = FXCollections.observableArrayList(foldersList);
foldersTableView.setItems(listFold);
}
}


 <?xml version =1.0encoding =UTF-8?& 

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


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

Controller 3(.java + .fxml): / strong>

  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 = new Folder();

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

session.save(folder);
session.getTransaction()。commit();
//这不工作..甚至尝试一个简单的标签
AppFactory app = new AppFactory();
FolderListController flc = app.folderListController();
flc.initializeFoldersList();
flc.loadData();
}
}


 <?xml version =1.0encoding =UTF-8?& 

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

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







我在此基础上提出申请:
http://www.zenjava.com/2011/10/25/views-within-views-controllers-within-controllers/ ,我使用JavaFX 2对Java JDK 7




我觉得在JavaFX应用程序的全局功能中缺少一些东西。

解决方案

我想到了两种方式:


  1. 一节FXML简介(链接),您可以将子控制器(2和3)注入父级(1),并让父级协调其交互:



    FXML 1):

     < fx:include source =FolderList.fxmlfx:id =list/& 
    ...
    < fx:include source =FolderFormAdd.fxmlfx:id =addForm/>

    Java(1)(请注意字段的名称;必须与 ; fx:id> Controller ,ie):

      public class FolderController extends AbstractController {
    @FXML private FolderListController listController;
    @FXML private FolderFormAddController addFormController;
    void initialize(){
    //添加代码以协调它们
    }
    }

    我不喜欢这个解决方案很多这种情况,因为它导致组件之间的强耦合。另一方面,它可能是最快的。 p>


  2. 使用事件总线(例如从 Google Guava )。这实际上可以解耦你的逻辑(例如,列表组件侦听 PersonAdded 事件,无论它是如何创建的;表单生成此事件,无需关心正在侦听 - if任何)。我想我喜欢这种解决方案在你的情况。


查看jewelsea发表的评论指出的答案是伟大的 - 我已经upvoted它自己:)


I'm new to develop Java application and the MVC system of JavaFx stays a little dark for me.
My problem is as follows. 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 :

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

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>

Controller 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>

Controller 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>



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

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

解决方案

Two ways come into my mind:

  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) (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.

  2. 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.

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

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

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