I would like to use the custom component in the scene builder.
I want to embed a canvas to custom component. so i try to change the canvas of attributes .
canvas code like this:
package test;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
public class DrawCanvas extends Canvas{
public DrawCanvas() {
draw();
}
private void draw() {
// TODO Auto-generated method stub
double width = getWidth();
double height = getHeight();
GraphicsContext gc = getGraphicsContext2D();
gc.strokeLine(0,0,50,50);
}
}
Custom Component code like this:
package test;
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
public class Test extends BorderPane{
public Test() {
super();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Test.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.canvas.Canvas?>
<fx:root xmlns:fx="http://javafx.com/fxml" type="javafx.scene.layout.BorderPane">
<center>
</center>
</fx:root>
I've tried in this way , but it failed.
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.canvas.Canvas?>
<?import org.korecky.myjavafx.fxml10.DrawCanvas?>
<fx:root xmlns:fx="http://javafx.com/fxml" type="javafx.scene.layout.BorderPane">
<center>
<DrawCanvas ></DrawCanvas>
</center>
</fx:root>
Please give me advice and tips .
Your approach is working for me, but you need to create a valid canvas, providing some dimensions, otherwise those will be 0x0. For instance:
private void draw() {
setWidth(50);
setHeight(50);
GraphicsContext gc = getGraphicsContext2D();
gc.strokeLine(0,0,50,50);
}
Now you can import your DrawCanvas component into SceneBuilder, as #jewelsea suggests, and you'll be able to drag it to your scene:
You could add some properties to the class, like canvasWidth and canvasHeight.
public class DrawCanvas extends Canvas {
private final GraphicsContext gc;
public DrawCanvas() {
gc = getGraphicsContext2D();
draw();
}
private void draw() {
setWidth(canvasWidth.get());
setHeight(canvasHeight.get());
gc.clearRect(0,0,canvasWidth.get(),canvasHeight.get());
gc.strokeLine(0,0,canvasWidth.get(),canvasHeight.get());
}
private final DoubleProperty canvasWidth = new SimpleDoubleProperty(50){
#Override
protected void invalidated() {
draw();
}
};
public double getCanvasWidth() {
return canvasWidth.get();
}
public void setCanvasWidth(double value) {
canvasWidth.set(value);
}
public DoubleProperty canvasWidthProperty() {
return canvasWidth;
}
private final DoubleProperty canvasHeight = new SimpleDoubleProperty(50){
#Override
protected void invalidated() {
draw();
}
};
public double getCanvasHeight() {
return canvasHeight.get();
}
public void setCanvasHeight(double value) {
canvasHeight.set(value);
}
public DoubleProperty canvasHeightProperty() {
return canvasHeight;
}
}
This will allow you to set them on the Inspector panel:
or in your fxml files:
<fx:root type="javafx.scene.layout.BorderPane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<center>
<DrawCanvas canvasWidth="150" canvasHeight="250" />
</center>
</fx:root>
Related
how are you ?
I've been looking for how to update a Label for one application for another application for days and I can't find it.
I have the main application where I have a layout with a Label:
package updatelistener;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* #author programmer
*/
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
private StringProperty line1 = new SimpleStringProperty(String.valueOf(Config.get("LINE_1")));
#Override
public void initialize(URL url, ResourceBundle rb) {
label.setText("Hello World!");
Updater.Connecting(this);
}
public void setLabelText(String text) {
System.out.println("CONTROLLER SET LABEL CHAMADO");
label.setText(text);
}
}
I have the secondary application, where I will update the Label of the main app:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package updatelistener;
import java.io.IOException;
/**
*
* #author programmer
*/
public class Updater {
static FXMLDocumentController controllerGlobal;
public static void Connecting(FXMLDocumentController controller) {
controllerGlobal = controller;
controller.setLabelText("Bye World");
}
public static void main(String[] args) throws IOException {
controllerGlobal.setLabelText("Update!!!");
}
}
When I run the first time, the label is updated correctly to "Bye World", but I would like to update the Label at run time with the value I typed there in the controllerGlobal.setLabelText ("Update !!!"); and when I ran the app, it would update the text value on the screen.
When I'm running the app to update the Label value, I'm getting a NullPointerException.
Can anyone help me with a solution for this scenario?
.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="updatelistener.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="100.0" layoutY="120" minHeight="16" minWidth="69" prefWidth="200.0" text="Saque">
<font>
<Font size="25.0" />
</font></Label>
</children>
</AnchorPane>
I got it
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws Exception {
try {
new Thread(listner).start();
while (true) {
Thread.sleep(100);
//LINE1
line_1 = ApplicationConfiguration.getInstance()
.getConfiguration("LINE_1");
if (!oldLine_1.equals(line_1)) {
System.out.println("NEW VALUE[" + line_1 + "]");
updateMessage(line_1);
}
oldLine_1 = line_1;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
};
task.messageProperty().addListener((obs, oldMessage, newMessage) -> label.setText(newMessage));
new Thread(task).start();
ApplicationConfiguration.getInstance().getConfiguration("LINE_1");
It is reading my property file all the time and when it finds a new value it updates the variable value.
I have a problem with context menus. The items in the context menu can be styled, but it doesn't work dynamic. I mean for example at the initialize I add a styleclass to the MenuItem and by an event I remove it, but the style still remains there. How can it be solved?
Here is a simple example to play with it:
Controller.java:
public class Controller implements Initializable {
private static final String STYLED = "styled";
#FXML
private ListView<String> listView;
#FXML
private Button change;
#Override
public void initialize(URL location, ResourceBundle resources) {
ContextMenu cm = new ContextMenu();
MenuItem miAdd = new MenuItem("Add");
miAdd.setOnAction(event -> listView.getItems().add("Apple"));
MenuItem miRemove = new MenuItem("Remove");
miRemove.disableProperty().bind(listView.getSelectionModel().selectedItemProperty().isNull());
miRemove.setOnAction(event -> listView.getItems().remove(listView.getSelectionModel().getSelectedItem()));
cm.getItems().addAll(miAdd, miRemove);
listView.setContextMenu(cm);
miRemove.getStyleClass().add(STYLED);
change.setOnAction(event -> {
if (!miRemove.getStyleClass().contains(STYLED)) {
miRemove.getStyleClass().add(STYLED);
} else {
miRemove.getStyleClass().remove(STYLED);
}
});
}
}
View.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="textField.Controller"
stylesheets="css/layout.css">
<VBox>
<Button fx:id="change" text="ChangeStyle"/>
<ListView fx:id="listView"/>
</VBox>
</AnchorPane>
layout.css:
.styled .text {
-fx-strikethrough: true;
}
.styled {
-fx-background-color: gray;
}
How can I manage to add/remove style to my MenuItem ?
I have a login stage (300 x 250), I want to open another main stage (fullscreen) if the credentials are correct.
I have figured out how to check the login credentials, but how can I close the login stage and open another stage?
If my application is supposed to work in one window I prefer using a GUI manager singleton class, which manages changing windows. Below I provided the complete code of a simple application which uses this mechanism. Let's assume all the files are in one package, called sample.
Main.java - you initialize the JavaFX components here:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/sample/root.fxml"));
try{
StackPane rootPane;
rootPane = loader.load();
GuiManager guiModel = GuiManager.getInstance();
guiModel.setRootPane(rootPane);
Scene scene = new Scene(rootPane);
primaryStage.setScene(scene);
primaryStage.show();
guiModel.changeWindow("/sample/firstwindow.fxml");
} catch (IOException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
root.fxml - all the windows are supposed to be based on it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="rootPane"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
prefWidth="1" prefHeight="1"/>
firstwindow.fxml - first actual window which will be displayed:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.FirstWindowController">
<Label text="First window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
FirstWindowController.java - a controller class of the first window:
package sample;
import javafx.fxml.FXML;
public class FirstWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/secondwindow.fxml");
}
}
secondwindow.fxml - it will be displayed after clicking the button of the first window:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.SecondWindowController" >
<Label text="Second window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
SecondWindowController.java - a controller class of the second window:
package sample;
import javafx.fxml.FXML;
public class SecondWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/firstwindow.fxml");
}
}
GuiManager.java - a class that manages changing windows based on the root:
package sample;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.io.IOException;
public class GuiManager {
private StackPane rootPane;
private static GuiManager instance;
public static GuiManager getInstance() {
if (instance == null) {
instance = new GuiManager();
}
return instance;
}
private GuiManager() {}
public void changeWindow(String path) {
changeWindow(rootPane, path, this);
rootPane.setPrefWidth(-1);
rootPane.setPrefHeight(-1);
}
public static void changeWindow(Pane pane, String newWindowPath, Object callingController) {
Window window = pane.getScene().getWindow();
double x = window.getX() + getHorizontalMidpoint(window);
double y = window.getY() + getVerticalMidpoint(window);
ObservableList<Node> childrenList = pane.getChildren();
removeAllIncludedChildren(childrenList);
FXMLLoader loader = new FXMLLoader(callingController.getClass().getResource(newWindowPath));
try {
pane.getChildren().add(loader.load());
Stage primaryStage = (Stage) window;
primaryStage.setMinHeight(0);
primaryStage.setMinWidth(0);
window.sizeToScene();
window.setX(x - getHorizontalMidpoint(window));
window.setY(y - getVerticalMidpoint(window));
primaryStage.setMinHeight(window.getHeight());
primaryStage.setMinWidth(window.getWidth());
} catch (IOException exception) {
exception.printStackTrace();
}
}
private static double getHorizontalMidpoint(Window window) {
int horizontalBisectionCoefficient = 2;
return window.getWidth() / horizontalBisectionCoefficient;
}
private static double getVerticalMidpoint(Window window) {
int verticalBisectionCoefficient = 2;
return window.getHeight() / verticalBisectionCoefficient;
}
private static void removeAllIncludedChildren(ObservableList<Node> childrenList) {
for (int childIndex = 0; childIndex < childrenList.size(); childIndex++) {
childrenList.remove(childIndex);
}
}
public void setRootPane(StackPane rootPane) {
this.rootPane = rootPane;
}
}
I just run in the same issue and this answer solved my issue perfectly while being short and clean.
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!
Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));
}
PS.: Remember to click the original answer and upvote it. The guy deserves...
PPS.: I am not sure just copying an answer is okay(instead of just share the link through a comment) but since this doesnt have a correct answer yet i decided to do it for visibility.
So I followed this blog (part 2 in particular) to create a custom control and import it into Scene Builder.
This is what it looks like:
Here is the fxml File:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="150.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox alignment="CENTER" layoutX="-65.0" layoutY="-56.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Button fx:id="previousButton" minWidth="25.0" mnemonicParsing="false" prefWidth="25.0" text="<" />
<Label fx:id="label" alignment="CENTER" contentDisplay="CENTER" prefWidth="500.0" text="Label" />
<Button fx:id="nextButton" minWidth="25.0" mnemonicParsing="false" prefWidth="25.0" text=">" />
</children>
</HBox>
</children>
</fx:root>
Here is the class File:
package swipeselector;
import java.io.IOException;
import java.util.ArrayList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
/**
*
* #author patrickb
*/
public class SwipeSelector extends AnchorPane {
#FXML
private Button previousButton;
#FXML
private Label label;
#FXML
private Button nextButton;
ArrayList<String> items;
int selectedIndex;
private boolean repetitive;
public SwipeSelector() {
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("swipeSelectorFXML.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
items = new ArrayList<>();
selectedIndex = 0;
previousButton.setOnAction((ActionEvent event) -> {
setPrevious();
});
nextButton.setOnAction((ActionEvent event) -> {
setNext();
});
}
public void setItems(ArrayList<String> items) {
this.items = items;
selectFirst();
}
public void setPrevious() {
updateItem(selectedIndex - 1);
}
public void setNext() {
updateItem(selectedIndex + 1);
}
public void selectFirst() {
updateItem(0);
}
private void selectLast() {
updateItem(items.size() - 1);
}
private void updateItem() {
if (items.isEmpty()) {
label.setText("");
} else {
if (selectedIndex < 0) {
if (repetitive) {
selectedIndex = items.size() - 1;
} else {
selectedIndex = 0;
}
}
if (selectedIndex >= items.size()) {
if (repetitive) {
selectedIndex = 0;
} else {
selectedIndex = items.size() - 1;
}
}
label.setText(items.get(selectedIndex));
}
}
private void updateItem(int selectedIndex) {
this.selectedIndex = selectedIndex;
updateItem();
}
public void setRepetitive(boolean cyclesThrough) {
this.repetitive = cyclesThrough;
}
}
Everything works fine, BUT: When I click the next or previous button, I want something to happen in my original project. I would usually do this by adding a setOnAction(new EventHandler ... method to the object. This method does not exist though, so I somehow need to add this to my custom control. How do I make my custom control invoke a ActionEvent every time one of the two buttons is clicked, and how do I create a setOnAction Method for my object that will work?
You'll need to create a custom event. Unfortunately, there is little information about this. You can have a look at the source code of ButtonBase to get a sample.
You'll need to define an onAction property:
ObjectProperty<EventHandler<ActionEvent>> onAction
I've implemented a utility class for this: SimpleEventHandlerProperty
You can find a complete sample using SimpleEventHandlerProperty here: LeftTestPane.java
You can get the library from Maven Central:
<dependency>
<groupId>org.drombler.commons</groupId>
<artifactId>drombler-commons-fx-core</artifactId>
<version>0.6</version>
</dependency>
I found a way to make it work. The following code is added to the Class File (it is basically copied from ButtonBase.
public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }
public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }
private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() {
#Override protected void invalidated() {
setEventHandler(ActionEvent.ACTION, get());
}
#Override
public Object getBean() {
return SwipeSelector.this;
}
#Override
public String getName() {
return "onAction";
}
};
Also, whenever something happens where you want that Action Event to be fired, invoking the method fireEvent(new ActionEvent()); will do this for you. This method goes back to the Node Class, which is inherited to this class as it extends AnchorPane (which inherited the fireEvent method from Node).
So in my case, I replaced my two onAction methods for the two buttons I have by this:
previousButton.setOnAction((ActionEvent event) -> {
setPrevious();
fireEvent(event);
});
nextButton.setOnAction((ActionEvent event) -> {
setNext();
fireEvent(event);
});
Now, whenever one of the two buttons are pressed, an ActionEvent is fired (I just passed on the Buttons Event for this purpose) and I can catch that in my project by adding
swipeSelector.setOnAction((ActionEvent event) -> {
System.out.println("Event fired!!!");
//DO SOMETHING
});
as usual.
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
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.