How to change the image of Imageview on MouseClick - javafx

i am creating an application in javafx using scene builder. i have an imageview and i want to change the image when someone clicks on it. i have added a mouse event to the image view but it's not changing the image when i click on it. please find below the code for the same.
public class HomeScreenController implements Initializable {
#FXML
public ImageView updateproject;
public String updateprojectstyle="-fx-image:url(\"../../../../Images/update-enable.png\");";
}
#FXML
private void updateProject(MouseEvent event) throws IOException
{
System.out.println("hello");
updateproject.setStyle(updateprojectstyle);
}
#Override
public void initialize(URL location, ResourceBundle resources) {
//To change body of generated methods, choose Tools | Templates.
}
}
Updated Question (MCVE)
My FXML looks like:
<VBox prefHeight="658.0" prefWidth="162.0" styleClass="sidepanel" BorderPane.alignment="CENTER">
<children>
<Pane maxHeight="138.0" maxWidth="162.0" prefHeight="200.0" prefWidth="200.0">
<children>
<ImageView fx:id="addproject" fitHeight="60.0" fitWidth="66.0" layoutX="48.0" layoutY="39.0" pickOnBounds="true" preserveRatio="true" styleClass="addproject-img" />
</children>
</Pane>
<Pane maxHeight="138.0" maxWidth="162.0" prefHeight="200.0" prefWidth="200.0">
<children>
<ImageView fx:id="updateproject" fitHeight="57.0" fitWidth="84.0" layoutX="41.0" layoutY="32.0" onMouseClicked="#updateProject" pickOnBounds="true" preserveRatio="true" styleClass="updateproject-img" />
</children>
</Pane>
<Pane layoutX="10.0" layoutY="148.0" maxHeight="138.0" maxWidth="162.0" prefHeight="200.0" prefWidth="200.0">
<children>
<ImageView fx:id="deleteproject" fitHeight="59.0" fitWidth="80.0" layoutX="41.0" layoutY="32.0" pickOnBounds="true" preserveRatio="true" styleClass="deleteproject-img" />
</children>
</Pane>
</children>
</VBox>
My Controller looks like:
public class HomeScreenController implements Initializable {
#FXML
public ImageView updateproject;
#FXML
public ImageView addproject;
#FXML
public ImageView deleteproject;
public String updateprojectstyle="-fx-image:url(\"../../../../Images/update-enable.png\");";
public String addprojectstyle="-fx-image:url(\"../../../../Images/add-disable.png\");";
#FXML
private void updateProject(MouseEvent event) throws IOException
{
System.out.println("hello");
updateproject.setStyle(updateprojectstyle);
addproject.setStyle(addprojectstyle);
}
#Override
public void initialize(URL location, ResourceBundle resources) {
//To change body of generated methods, choose Tools | Templates.
}
}
My css looks like:
.updateproject-img{
-fx-image:url("../../../../Images/update-disable1.png");
}
.addproject-img{
-fx-image:url("../../../../Images/add-active.png");
}
.deleteproject-img{
-fx-image:url("../../../../Images/delete-disable1.png");
}
i want to disable the add project icon and enable the update project icon when the user clicks on update project image view. click event is firing but it's not loading the image.

Here is a code with the css style on the ImageView.
Images on ImageView are set via -fx-image:url(...) and not via -fx-background-image:url(...), as you have used in your code.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class ChangeImageViewImage extends Application {
private static final String IMAGE1 = "http://img1.wikia.nocookie.net/__cb20130120032553/dragonball/images/3/32/Chibi-Ichigo-bleach-anime-33253004-332-400.png";
private static final String IMAGE2 = "https://40.media.tumblr.com/68f246eef26984be8a44e4367cfedd47/tumblr_n3lsszuyj41txcp2ko1_500.jpg";
#Override
public void start(Stage primaryStage) throws Exception {
ImageView imageView = new ImageView();
imageView.setFitHeight(400);
imageView.setFitWidth(300);
imageView.setStyle("-fx-image: url(\""+ IMAGE1 + "\");");
imageView.setOnMouseClicked(event -> {
imageView.setStyle("-fx-image: url(\""+ IMAGE2 + "\");");
});
Pane pane = new Pane();
pane.getChildren().add(imageView);
Scene scene = new Scene(pane, 300, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

Can not create clearable textField using ControlsFX

I have created TextField using Scene Builder but when I tried it with KeyEvent but it doesn't work.
public class FXMLDocumentController implements Initializable {
#FXML
private TextField searchPatient;
#FXML
void keyTyped(KeyEvent event) {
this.searchPatient = TextFields.createClearableTextField();
}
}
Here is main class:
public class MyFX extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Here is FXMLDocument.fxml:
<AnchorPane id="AnchorPane" prefHeight="597.0" prefWidth="726.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.homeo.home.FXMLDocumentController">
<children>
<TextField fx:id="searchPatient" layoutX="14.0" layoutY="109.0" onKeyTyped="#keyTyped" prefHeight="26.0" prefWidth="372.0" promptText="Search" />
</children>
</AnchorPane>
I don't want to relay on code for designing that's why I want to use ControlsFX with IDE generated code.
I'm expecting textfield must show clear icon as I enter few text in a textfield that's called clearableTextFieldf.
But with the all code above doesn't work as I expected.
It does not create ClearableTextField
You're creating the TextField in the KEY_TYPED event handler of a conventional TextField placed in your scene. The newly created TextField is never added to any scene though.
You could use the fx:factory attribute to use the static method for creating the TextField that FXMLLoader adds to the scene:
...
<?import org.controlsfx.control.textfield.TextFields?>
<AnchorPane id="AnchorPane" prefHeight="597.0" prefWidth="726.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.homeo.home.FXMLDocumentController">
<children>
<TextFields fx:factory="createClearableTextField" fx:id="searchPatient" layoutX="14.0" layoutY="109.0" prefHeight="26.0" prefWidth="372.0" promptText="Search" />
</children>
</AnchorPane>
You could alternatively use the initialize method to create&add your TextField instead:
public class FXMLDocumentController implements Initializable {
...
#FXML
private AnchorPane anchorPane;
#Override
public void initialize(URL location, Resources resources)
searchPatient = TextFields.createClearableTextField();
searchPatient.setLayoutX(14.0);
searchPatient.setLayoutY(109.0);
searchPatient.setPrefSize(372.0, 26.0);
searchPatient.setPromptText("Search");
anchorPane.getChildren().add(searchPatient);
...
}
}
<AnchorPane fx:id="anchorPane" id="AnchorPane" prefHeight="597.0" prefWidth="726.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.homeo.home.FXMLDocumentController" />

Javafx Issue in dragging selected text from TextArea

I have strange problem while dragging selected text from TextArea. The text is properly selected but when iam dragging to be place on the target position, the selection of text is changed, it reduce the selection for 2-3 characters randomly.
Here is the complete class :
public class DnDMainController extends Application {
ClipboardContent cb = new ClipboardContent();
ObservableList<String> list = FXCollections.observableArrayList();
#FXML
private TextArea sourceText;
#FXML
private ListView<String> listView;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/main/DnD.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Simple Drag and Drop ExampleGame");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
#FXML
void _detectDrag(MouseEvent event) {
Dragboard db = sourceText.startDragAndDrop(TransferMode.COPY);
cb.putString(sourceText.getSelectedText());
db.setContent(cb);
event.consume();
}
#FXML
void _dragExited(DragEvent event) {
String st = event.getDragboard().getString();
if (!(list.contains(st.trim()))) {
list.add(st);
listView.getItems().addAll(list);
}}
}
[![gif for DnD Issue][1]][1]
I have tried the same on TextField and it is working perfectly on TextField. But unfortunatelly i can not use the TextField due to large string of text. I dont know what Iam doing wrong...
FXML CODE:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="549.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.DnDMainController">
<children>
<TextArea fx:id="sourceText" layoutY="273.0" onDragDetected="#_detectDrag" prefHeight="127.0" prefWidth="550.0" text="There was once a velveteen rabbit, and in the beginning he was really splendid. He was fat and bunchy, as a rabbit should be; his coat was spotted brown and white, he had real thread whiskers, and his ears were lined with pink sateen. On Christmas morning, when he sat wedged in the top of the Boy’s stocking, with a sprig of holly between his paws, the effect was charming." wrapText="true">
<font>
<Font size="19.0" />
</font></TextArea>
<ListView fx:id="listView" layoutY="40.0" onDragExited="#_dragExited" onMouseClicked="#_callContext" prefHeight="200.0" prefWidth="516.0" />
<Label alignment="CENTER" contentDisplay="CENTER" layoutX="-2.0" layoutY="2.0" prefHeight="38.0" prefWidth="550.0" text="List of Words" textAlignment="CENTER" />
<Label alignment="CENTER" contentDisplay="CENTER" layoutX="7.0" layoutY="240.0" prefHeight="32.0" prefWidth="542.0" text="Story" textAlignment="CENTER" />
</children>
</AnchorPane>```
I ran into a few problems trying to implement this in a straightforward way. I had to create a toggle that would allow me to select text and then drag the text. During the drag, I noticed that it would not grab all of the selected text unless the drag was started at the end of the selected text. I fixed that by grabbing the selected text after it was selected and the toggle mode is changed to drag mode. MCVE below.
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Parent;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Test.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Simple Drag and Drop ExampleGame");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="583.0" prefWidth="851.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javaapplication12.TestController">
<children>
<ListView fx:id="listView" layoutX="326.0" layoutY="14.0" onDragDropped="#dragDropped" onDragEntered="#dragEntered" onDragOver="#dragOver" prefHeight="200.0" prefWidth="200.0" />
<TextArea fx:id="textArea" layoutX="224.0" layoutY="274.0" onDragDetected="#dragDetected" prefHeight="247.0" prefWidth="426.0" text="There was once a velveteen rabbit, and in the beginning he was really splendid. He was fat and bunchy, as a rabbit should be; his coat was spotted brown and white, he had real thread whiskers, and his ears were lined with pink sateen. On Christmas morning, when he sat wedged in the top of the Boy’s stocking, with a sprig of holly between his paws, the effect was charming." wrapText="true" />
<ToggleButton fx:id="tbtnDragMode" layoutX="44.0" layoutY="26.0" mnemonicParsing="false" onAction="#handleTbtnDragMode" text="Select Text Mode" />
</children>
</AnchorPane>
Controller
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleButton;
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;
public class TestController implements Initializable {
#FXML TextArea textArea;
#FXML ListView listView;
#FXML ToggleButton tbtnDragMode;
ObservableList<String> list = FXCollections.observableArrayList();
String selectedText = "";
#Override
public void initialize(URL url, ResourceBundle rb) {
listView.setItems(list);
list.add("test");
}
#FXML private void handleTbtnDragMode(ActionEvent actionEvent)
{
if(tbtnDragMode.isSelected())
{
System.out.println("Drag Mode On");
tbtnDragMode.setText("Drag Mode");
selectedText = textArea.getSelectedText().isBlank() ? "" : textArea.getSelectedText();
}
else {
System.out.println("Drag Mode Off");
tbtnDragMode.setText("Select Text Mode");
}
}
#FXML
private void dragDetected(MouseEvent event) {
System.out.println("drag detected 1");
System.out.println(tbtnDragMode.isSelected());
if(tbtnDragMode.isSelected())
{
System.out.println("drag detected 2");
/* drag was detected, start a drag-and-drop gesture*/
/* allow any transfer mode */
Dragboard db = textArea.startDragAndDrop(TransferMode.ANY);
/* Put a string on a dragboard */
ClipboardContent content = new ClipboardContent();
content.putString(selectedText);
db.setContent(content);
event.consume();
}
}
#FXML
private void dragEntered(DragEvent event) {
System.out.println("dragEntered");
event.consume();
}
#FXML
private void dragDropped(DragEvent event)
{
System.out.println("Drag dropped");
/* data dropped */
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
list.add(db.getString());
success = true;
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
}
#FXML
private void dragDone(DragEvent event) {
/* the drag and drop gesture ended */
/* if the data was successfully moved, clear it */
System.out.println("drag done");
if (event.getTransferMode() == TransferMode.MOVE) {
//clear textarea selection
System.out.println("drag done");
}
event.consume();
}
#FXML
private void dragExited(DragEvent event) {
System.out.println("dragExited");
event.consume();
}
#FXML
private void dragOver(DragEvent event) {
/* data is dragged over the target */
/* accept it only if it is not dragged from the same node
* and if it has a string data */
System.out.println(event.getGestureSource() + " - " + event.getTarget());
if (event.getGestureSource() != event.getTarget() &&
event.getDragboard().hasString()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
}
}

Binding an ImageView size to an AnchorPane always gives a size of 0

I have an ImageView inside an AnchorPane, built using FXML.
<fx:root prefHeight="600.0" prefWidth="800.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.LifeMandelbrot">
<children>
<ImageView fx:id="view" fitHeight="600.0" fitWidth="800.0" onMouseClicked="#moveCenter" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<HBox alignment="CENTER" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<Button fx:id="zoomOut" mnemonicParsing="false" onAction="#zoomOut" text="Zoom-" />
<Button fx:id="zoomIn" mnemonicParsing="false" onAction="#zoomIn" text="Zoom+" />
<Button fx:id="defaultView" mnemonicParsing="false" onAction="#defaultView" text="Vue par défaut" />
</children>
</HBox>
</children>
</fx:root>
As you can see, the ImageView fits the AnchorPane using anchors.
When I click one of the button, the ImageView is repainted.
Problem:
view.getFitWidth() always shows 0, same for the height.
EDIT
The controller code looks like that:
package application;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
public class LifeMandelbrot extends AnchorPane implements Initializable {
private static final double DEFAULT_ZOOM = 200.0;
private static final Complex DEFAULT_CENTER = new Complex(0, 0);
private static final double ZOOM_RATIO = 1.2;
#FXML
private Button zoomOut;
#FXML
private Button zoomIn;
#FXML
private Button defaultView;
#FXML
private Button julia;
#FXML
ImageView view;
private double zoom;
private Complex center;
private List<Color> colors;
private int colorStep;
public LifeMandelbrot() {
zoom = DEFAULT_ZOOM;
center = DEFAULT_CENTER;
colors = new ArrayList<Color>();
colors.add(Color.RED);
colors.add(Color.GREEN);
colors.add(Color.BLUE);
colorStep = 20;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
repaint();
view.fitWidthProperty().bind(widthProperty());
view.fitHeightProperty().bind(heightProperty());
}
#FXML
void defaultView(ActionEvent event) {
zoom = DEFAULT_ZOOM;
center = DEFAULT_CENTER;
repaint();
}
#FXML
void julia(ActionEvent event) {
}
#FXML
void zoomIn(ActionEvent event) {
zoom *= ZOOM_RATIO;
repaint();
}
#FXML
void zoomOut(ActionEvent event) {
zoom /= ZOOM_RATIO;
repaint();
}
#FXML
void moveCenter(MouseEvent event) {
center = fractalFromView(event.getX(), event.getY());
repaint();
}
private void repaint() {
WritableImage image = new WritableImage((int) view.getFitWidth(), (int) view.getFitHeight());
PixelWriter pw = image.getPixelWriter();
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
Complex c = fractalFromView(x, y);
int iterations = Fractal.mandelbrot(c);
if (iterations == -1) {
pw.setColor(x, y, new Color(0, 0, 0, 1));
} else {
int colorIndex = iterations / colorStep;
int colorAdd = iterations % colorStep;
Color color1 = colors.get(colorIndex % colors.size());
Color color2 = colors.get((colorIndex + 1) % colors.size());
Color color = color1.interpolate(color2, (double) colorAdd / colorStep);
pw.setColor(x, y, color);
}
}
}
view.setImage(image);
}
private Complex fractalFromView(double x, double y) {
return new Complex((x - view.getFitWidth() / 2) / zoom + center.getReal(),
(y - view.getFitHeight() / 2) / zoom + center.getImaginary());
}
}
Loaded from there:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("../lifeMandelbrot.fxml"));
loader.setRoot(new LifeMandelbrot());
AnchorPane root = loader.load();
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("LIFE Is a Fractal Explorer");
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
You have two instances of LifeMandelbrot: one you create by calling the constructor and explicitly set as the dynamic root of the FXML; the other is created for you by the FXMLLoader and is used as the controller. The one you create you use in the scene graph (scene = new Scene(root)). The one that is created as the controller is never placed in the scene graph. Consequently it never undergoes layout and always has width and height of zero.
Of course, the handler methods and initialize() methods are called on the "controller instance", not the "root instance", so you bind fitWidth and fitHeight to zero.
You need
FXMLLoader loader = new FXMLLoader(getClass().getResource("../lifeMandelbrot.fxml"));
LifeMandelbrot root = new LifeMandelbrot();
loader.setRoot(root);
loader.setController(root);
loader.load();
Scene scene = new Scene(root);
and then you need to remove the fx:controller attribute from the root element of the FXML. This way the controller and root node are the same instance.
Since your FXML already explicitly ties itself to an AnchorPane by using the anchor pane settings on the child nodes, it might be clearer just to use the standard pattern for this. I.e.
<AnchorPane fx:id="root" fx:controller="application.LifeMandelbrot" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ImageView fx:id="view" onMouseClicked="#moveCenter" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<HBox alignment="CENTER" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<Button fx:id="zoomOut" mnemonicParsing="false" onAction="#zoomOut" text="Zoom-" />
<Button fx:id="zoomIn" mnemonicParsing="false" onAction="#zoomIn" text="Zoom+" />
<Button fx:id="defaultView" mnemonicParsing="false" onAction="#defaultView" text="Vue par défaut" />
</children>
</HBox>
</children>
</AnchorPane>
In the controller:
public class LifeMandelbrot implements Initializable {
#FXML
private AnchorPane root ;
// existing code...
#Override
public void initialize(URL location, ResourceBundle resources) {
repaint();
view.fitWidthProperty().bind(root.widthProperty());
view.fitHeightProperty().bind(root.heightProperty());
}
// existing code...
}
and then just
FXMLLoader loader = new FXMLLoader(getClass().getResource("../lifeMandelbrot.fxml"));
Scene scene = new Scene(loader.load());

JavaFX #FXML binding from within Java code

I have a custom JavaFX component extending the Tab class:
public class MyTab extends Tab implements Initializable {
#FXML private TextField myInput;
private final MyDTO dto;
public MyTab(MyDTO dto) {
super();
this.dto = dto;
final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/my-tab.xml"));
fxmlLoader.setResources(MSG.getResourceBundle());
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
}
catch (IOException exception) {
throw new RuntimeException(exception);
}
}
#Override
public void initialize(URL url, ResourceBundle res) {
setText("My Tab");
myInput.setText(dto.getValue()); // !!!
}
}
With the FXML:
<fx:root type="javafx.scene.control.Tab" xmlns:fx="http://javafx.com/fxml">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Label id="myLabel" layoutX="14.0" layoutY="14.0" text="Text:" />
<TextField id="myInput" layoutX="162.0" layoutY="10.0" prefHeight="25.0" prefWidth="300.0" />
</children>
</AnchorPane>
</content>
</fx:root>
I need to create this objects (custom tabs) dynamically from the java code:
final MyTab myTab = new MyTab(new MyDTO(...));
tabPane.getTabs().add(myTab);
When I use it like this, the #FXML binding doesn't work and the line
myInput.setText(dto.getValue());
throws NullPointerException. When the line with the setting of the text from the code is commented, the input is showned, so the problem is only in the binding.
I am using JavaFX 2 for Java 1.7
Thank you for any idea!
Solution is very easy, I just overlooked the mistake in the FXML code:
Should be
<TextField fx:id="myInput" ...
instead of
<TextField id="myInput" ...

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

Resources