Search code examples
javafxfxmleventhandler

javafx : pass parameter to the eventhandler function in fxml file


Is there a way to call the event handler method from the fxml file which holds parameter? please find the files:

My Fxml Looks like:

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

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

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.cognizant.iotworkbench.View.AddImageController">
   <children>
      <Label layoutX="270.0" layoutY="14.0" text="Add Sensor" />
      <BorderPane layoutY="-1.0" prefHeight="400.0" prefWidth="602.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <left>
            <HBox fx:id="source" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
               <children>
                  <ImageView fx:id="sourceimg" fitHeight="114.0" fitWidth="142.0" onDragDetected="#setUpGestureSource" pickOnBounds="true" preserveRatio="true">
                     <image>
                        <Image url="file:Images/Project.png" />
                     </image>
                  </ImageView>
               </children>
            </HBox>
         </left>
         <right>
            <HBox fx:id="target" onDragDropped="#setUpGestureTarget" onDragOver="#setUpGestureTarget" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
         </right>
      </BorderPane>
  </children>
</AnchorPane>

My controller class looks like

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;

/**
 * FXML Controller class
 *
 */
public class AddImage implements Initializable,ControlledScreen {

    ScreensController myController;
    /**
     * Initializes the controller class.
     */
 @FXML
    final HBox target=new HBox();
    @FXML
    final HBox source=new HBox();

    @FXML
    final ImageView sourceimg=new ImageView();



  @FXML
        public void setUpGestureSource()
        {
            System.out.println("source");
        source.setOnDragDetected(new EventHandler <MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                /* drag was detected, start drag-and-drop gesture*/
                System.out.println("onDragDetected");

                /* allow MOVE transfer mode */
                Dragboard db = source.startDragAndDrop(TransferMode.COPY);

                /* put a string on dragboard */
                ClipboardContent content = new ClipboardContent();
                Image sourceImage = sourceimg.getImage();
               content.putImage(sourceImage);
               db.setContent(content);

                event.consume();
            }
        });
        }
        @FXML
        public void setUpGestureTarget(){
            System.out.println("target");
        target.setOnDragOver(new EventHandler <DragEvent>() {
            @Override
             public void handle(DragEvent event) {

                Dragboard db = event.getDragboard();

                if(db.hasImage()){
                    event.acceptTransferModes(TransferMode.COPY);
                }

                event.consume();
            }
        });
         target.setOnDragDropped(new EventHandler <DragEvent>() {
            @Override
            public void handle(DragEvent event) {

                Dragboard db = event.getDragboard();

                if(db.hasImage()){

                    insertImage(db.getImage(), target);

                    event.setDropCompleted(true);
                }else{
                    event.setDropCompleted(false);
                }

                event.consume();
            }
        });
}
       void insertImage(Image i, HBox hb){

        ImageView iv = new ImageView();
        iv.setImage(i);

        setUpGestureSource();
        hb.getChildren().add(iv);
    }
    @Override
    public void setScreenParent(ScreensController screenParent) {

         myController=screenParent;
    }
        @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    



}

Drag and Drop event is not getting fired. I dont know what's wrong with the code. Please help


Solution

  • All methods that are annotated with @FXML may or may not have a parameter. If you need a parameter, you can directly pass the specific Event as a parameter to the method.

    Let us take an example and say you have an onDragOver event added for a HBox in the fxml.

    <HBox fx:id="targetBox" onDragOver="#setupGestureTarget">
    ...
    </HBox>
    

    Then you may have a method which does the needful inside the controller class.

    @FXML
    public void setupGestureTarget(DragEvent event) {
         Dragboard db = event.getDragboard();
         if(db.hasImage()){
               event.acceptTransferModes(TransferMode.COPY);
         }
         event.consume();
    }
    

    If you need the source node for which the method was called, you can get an access to it by getSource() of the event, then type-caste it to Node.

    public void setupGestureTarget(DragEvent event) {
         ...
         ((Node)event.getSource()).setId("myHbox");
         System.out.println(targetBox.getId()); // Prints - myHbox
    }
    

    Note : For using methods specific to HBox, you can type-caste it to a HBox instead of a Node.


    EDIT - As per user comments and updates

    There are multiple issues with your approach. Let me address them all.

    1.Values to the fields annotated with @FXML are injected while the FXML is getting loaded and should not carry new keyword.

    @FXML
    final HBox target=new HBox(); 
    

    should be replaced by

    @FXML
    final HBox target;
    

    2.As I have already stated your method can have a parameter which defines the Event. So the methods setUpGestureSource() and setUpGestureTarget() can be defined as :

    @FXML
    public void setUpGestureSource(DragEvent event) {
    ...
    }
    
    @FXML
    public void setUpGestureTarget(DragEvent event) {
    ...
    }
    

    3.The method setUpGestureSource is called when a drag-event occurs on the ImageView, so you don't need to add another EventHandler for it.

    @FXML
    public void setUpGestureSource(MouseEvent event) {
         /* drag was detected, start drag-and-drop gesture*/
         System.out.println("onDragDetected");
    
         * allow MOVE transfer mode */
         Dragboard db = source.startDragAndDrop(TransferMode.COPY);
    
         /* put a string on dragboard */
         ClipboardContent content = new ClipboardContent();
         Image sourceImage = sourceimg.getImage();
         content.putImage(sourceImage);
         db.setContent(content);
         event.consume();
    } 
    

    Similarly, change the other method as well.