Hello guys, I’m back after my lots of works and stuffs that’s why this post got delayed. Anyway now I’m going to demonstrate today about how to communicate between FXML using FXController classes. Some of my commentator also asked me to share this communication of FXML so I’m blogging for the same. Today I’m going to just continue the blog post of  previous post I’ve blogged about FXML Stuffs (include and define) . So If you have not started reading those previous blog then please have a look because the things I’m going to tell is related to them.

Anyway Let’s summarize the previous blog.

  • Main.fxml (The main container of all fxml)
  • Home.fxml (the tab content of Home Tab)
  • About.fxml (the tab content of About Tab)
  • FXMLTest.java (this is just the executor class)

Now In today’s post we are having one more extras class which is listed below.

  • DockletListener.java (The java interface)

Before going to start this communication between fxml . Let’s have a look at how the flow gets working.


 
DockletListener.java

public interface DockletListener {
    //Dock item being added
    void added(Node n);
    //Dock item being removed
    void removed(String id);
    
}

What we see in above flow is that there is always an Interface DocketListener.java which have functions like added(), removed() . This helps the Main.java(Main.fxml) to know what’s being added/removed. The approach I’m using is like a Swing Listeners style. This interface works by living in the middle of FXController classes. Ok Let’s move to the Main.fxml which helps to listen the event of this interface.

 
Main.fxml

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

<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.effect.*?>
<?import fxmlstuff.Main?>
<?import javafx.geometry.Insets?>

<Main xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlstuff.Main">
    <padding>
        <Insets right="10"/>
    </padding>
    <fx:define>
        <fx:include source="Home.fxml" fx:id="homeContent" />
        <fx:include source="About.fxml" fx:id="aboutContent" />        
   </fx:define>
    <center>        
        <TabPane fx:id="tabpane" translateY="5" translateX="5"  >
            <tabs>                                
                <Tab text="HOME" fx:id="homeTab" content="$homeContent" closable="false" />
                <Tab text="ABOUT" fx:id="aboutTab" content="$aboutContent" closable="false"/>                               
            </tabs>
        </TabPane>
    </center>

    <!-- This is the bottom part containing Dock Panel -->
    <bottom>
        <StackPane translateY="-30" visible="true">
            <effect>
                <Reflection topOpacity="0.7" fraction="0.8" topOffset="-30"/>
            </effect>
            <children>               
                <!-- Dock Panel as Shape -->                
                <Polygon fx:id="dock_bottom" />                
                <!-- Dock Items Panel -->                
                <FlowPane hgap="20" translateY="-25" fx:id="dockPanel" alignment="TOP_CENTER" />                              
            </children>

        </StackPane>
    </bottom>
</Main>

 
Main.java

public class Main extends BorderPane implements Initializable, DockletListener{

    //FXML ATTRIBUTES
    @FXML
    private Home homeContent;
    @FXML
    private About aboutContent;    
    @FXML
    private Polygon dock_bottom;    
    @FXML
    private FlowPane dockPanel;

    @Override
    public void initialize(URL url, ResourceBundle rb) {        
        // Adding Swing style of custom Listener 
        aboutContent.addListener(this);
        homeContent.addListener(this); 

        //This is for Dock bottom part which is a polygon
        double slide=50;
        double height =15;
        double width= 700;
        double offset = 20;        
        dock_bottom.getPoints().addAll(
                slide, 0.0,
                0.0, height,
                width,height ,
                width-slide, 0.0

        );  

        //Default Dock Item added
        added(ButtonBuilder.create()
            .text("Dock")
            .id("default")
            .build()
        );        
    }

    /**
     * This is the implemented method of Node being added to docklet
     * @param n Node
     */
    @Override
    public void added(Node n) {
        if(dockPanel.getChildren().size()<5){            
            //Let's assume currently we make dock item of only Button
            final Button b = (Button) n;
            b.setPrefHeight(50);         
            b.setPrefWidth(60);  
            b.getStyleClass().add("dock-item"); 
            dockPanel.getChildren().add(b);            
        }
    }

    /**
     * This is the implemented method of Node being removed from docklet
     * @param n String
     */
    @Override
    public void removed(String id) {   
        Node rm = null;
        //Checking for dock item according to it's ID
        for(Node n:dockPanel.getChildren()){            
            if(n.getId().equals(id)){
                rm = n;                
                break;
            }            
        }        

        if(rm!=null){
            final Button b = (Button)rm;
            dockPanel.getChildren().remove(b);
        }        
    }    
}

Now What we see in Main.java it implements the DockletListener interface and has overridden the methods added(Node n) and removed(String id). Now this class can easily listen which node to be added in docklet and which is to be removed. Currently We are adding only Button Node as an item in Docklet. These added,removed will be invoked by Home and About fxml. As you can see in highlighted lines above; I’ve added the addListener(this) to help the Home/About class to invoke via this a.k.a. Main.java object which is instance of DockletListener.
We have two tabs “Home” and “About” . I’ll only describe “Home” tab because both fxml and classes have almost identical codes. Here we have distinguish our dock item by the help of id. We can remove the items by the help of “id”. Whenever the id==home then the item will be deleted from the docket. In the Home.fxml I’ve added one button of ‘remove’ and some layout too.

 
Home.fxml

<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import fxmlstuff.Home?>

<Home id="homeContent" xmlns:fx="http://javafx.com/fxml"        
        spacing="10" translateY="40" translateX="20" fx:controller="fxmlstuff.Home" >
    <children>
        <Label text="Add New Dock of Home" />
        <HBox spacing="10">
            <children>                
                <Button text="Add !" onAction="#handleAction"  />        
                <Button text="Remove !" onAction="#handleRemoveAction"  />        
            </children>
        </HBox>        
    </children>
</Home>

Here the “Add” button trigger the function to invoke the add item in docklet. And the “Remove” button to delete the item from docklet.

Home.java

public class Home extends VBox implements Initializable{
    //Static listener instance of DockletListener
    private static DockletListener listener;

    @FXML
    private void handleRemoveAction(ActionEvent event) {  
        if(listener != null){       
            listener.removed("home"); 
        }                
    }

    @FXML
    private void handleAction(ActionEvent event) {
        if(listener != null){       
             listener.added(ButtonBuilder.create()
                    .text("Home")
                    .id("home")
                    .build()); 
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {        
    }

    public void addListener(DockletListener listener){
        Home.listener = listener;
    }   

}

The highlighted lines in above code tell the Home.java to addListener of the DockletListener instance. And now when the “Add” button trigger then the handleAction() takes the job to add item to the docklet by the same instance which was added as Listener.

Now if you run your program with the same FXTest executor then it will now easily take the event of Home.fxml and the effect goes on Main.fxml.

I’ve modified even more in this app and I’m going to give you the screenshot of that app.

To view demo of this app : DockletDemo

That’s all for today. Also you can share your views and ideas about FXML Communicate just below at the comment.
Have a good :) day.
Thanks