controlsfx CustomTextField add ImageView click event is often not triggered - javafx

After adding ImageView, the imageview click event is often not triggered. Clicking ten times may trigger one or two times. I don't know why.
enter image description here
<CustomTextField prefHeight="45.0" prefWidth="300.0" promptText="搜索" fx:id="fieldSearch">
<right>
<ImageView fx:id="imageView">
<image>
<Image url="#../static/img/search.png"/>
</image>
</ImageView>
</right>
</CustomTextField>
#FXML
public ImageView imageView;
#Override
public void initialize(URL location, ResourceBundle resources) {
imageView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
onSearchClick();
}
});
}
public void onSearchClick(){
System.out.println("搜索");
}

You should set
imageView.setPickOnBounds(true);
in your initialize() method. This makes transparent parts of the image also clickable

Related

Using JavaFX to pass data to an already opened window

I'm new to JavaFX. This was easy to do without FXML, but the FXML controllers are stumping me.
What I'm trying to do: Set up a main window that has a button. When clicked, the button launches a second popup window in which the user submits a value. Upon closing the second window (done currently with a button click on the pop-up), I'd like the user's input to be passed back to the main controller-- the main window that is already open.
So far, I've got 2 .fxml files(one for a main window the other for a popup), and the corresponding controllers: MainWindowController:
public class MainController implements Initializable {
#FXML
public Label label;
#FXML
private Button button;
#FXML
private void popBtnClick(ActionEvent event) throws IOException {
//creates new pop-up window
Stage popupSave = new Stage();
popupSave.initModality(Modality.APPLICATION_MODAL);
popupSave.initOwner(ComWins.stage);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("PopUp.fxml"));
Parent root = loader.load();
PopUpController controller = loader.getController();
//calls a method in the PopUpController, and uses it to pass data to
//the Popup window.
controller.dataToPopUp(7);
Scene scene = new Scene(root);
popupSave.setScene(scene);
popupSave.showAndWait();
}
I also tried calling this method from the popup window with no success in
changing Main's label.
public void dataPass(String name){
label.setText(name);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
And PopUpController:
public class PopUpController implements Initializable {
#FXML
private Button ok_btn;
#FXML
public TextField input_tf;
#FXML
private String input;
#FXML
private void okBtnClick() throws IOException {
input = input_tf.getText();
/*my attempt to pass the variable-- using a loader to get the
controller and then referencing the public label. */
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Main.fxml"));
Parent root = loader.load();
FXMLDocumentController controller = loader.getController();
//this line works, and retrieves the label's text.
String temp = controller.label.getText();
//but this line does not work. Why?
controller.label.setText(input);
//closes this pop-up
Stage stage = (Stage)input_tf.getScene().getWindow();
stage.close();
}
//this method is called in the maincontroller and used to pass data to
//the popup's textfield.
public void dataToPopUp(int x){
input_tf.setText(Integer.toString(x));
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Using the above, Main passes ('7') into the PopUp's textfield. But if the user enters something else into the textfield, I cannot seem to get that data back to Main. This is like having a Settings Pop-up window, and then passing the user's selections from the Settings popup back to the main window. I just cannot figure out how to pass things back to the main window.
I am not using SpringBoot, but thanks for the suggestion.
Thank you in advance!
If you are using Spring Boot, MPV Java on YouTube has great examples of connecting your controllers together allowing you to pass information cleanly and easily between them.In my application I've been able to implement these examples. Each controller is registered as a bean using #Component which means you can #Autowire the controller into another controller. In your main controller I would recommend setting up some basic getters/setters to allow outside interaction with your fields so other controllers can "talk" to the main controller.
A really basic example would be:
#Component
public class MyMainController {
#FXML private TextField exampleTextField;
...
...
/* Get the text of a field from this controller: can be accessed from another controller */
public String getExampleTextField() {
exampleTextField.getText();
}
/* Set the text of a field on this controller: can be accessed from another controller */
public void setExampleTextField(String text) {
exampleTextField.setText(text);
}
}
#Component
public class AnotherController {
#Autowired private MyMainController myMainController;
...
...
public void someMethod(String newText) {
// Do some work here and set some text back to the main controller
myMainController.setExampleTextField(newText);
}
}
MPV Java does a much better job of explaining this concept.
https://www.youtube.com/watch?v=hjeSOxi3uPg
I reviewed the suggestions and was unable to get anything to work for me-- many of the concepts were over my head, as I'm new to Java. After several attempts, I was able to get a fairly simple solution to the problem. It is likely far from best practices, but it works:
In the main window's controller, use the popup's controller to call the Pop Up's string variable and set it as the label's text (label.setText(controller.test)). The string variable has to be public, and is set once the pop-up is closed by the button click. See the code below:
Main.fxml:
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="switchingpass.MainController">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" onAction="#popBtnClick" text="Click Me!" />
<Label fx:id="label2" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<Label fx:id="label" layoutX="143.0" layoutY="38.0" text="Label" />
</children>
</AnchorPane>
MainController:
public class MainController implements Initializable {
#FXML
public Label label;
#FXML
private Button button;
#FXML
private void popBtnClick(ActionEvent event) throws IOException {
//creates new pop-up window
Stage popupSave = new Stage();
popupSave.initModality(Modality.APPLICATION_MODAL);
popupSave.initOwner(SwitchingPass.stage);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("PopUp.fxml"));
Parent root = loader.load();
PopUpController controller = loader.getController();
Scene scene = new Scene(root);
popupSave.setScene(scene);
popupSave.showAndWait();
//after the popup closes, this will run, setting the label's text to the popup's test variable, which is public.
label.setText(controller.test);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
PopUp.fxml:
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="switchingpass.PopUpController">
<children>
<TextField fx:id="input_tf" layoutX="207.0" layoutY="65.0" />
<Button fx:id="close_btn" layoutX="268.0" layoutY="185.0" mnemonicParsing="false" onAction="#closeBtnClick" text="Close" />
</children>
</AnchorPane>
PopUpController:
public class PopUpController implements Initializable {
#FXML
public Button close_btn;
#FXML
public TextField input_tf;
#FXML
public String test;
#FXML
private void closeBtnClick() throws IOException {
//stores textfield input as a string
test = input_tf.getText();
Stage stage = (Stage)input_tf.getScene().getWindow();
stage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Please note that the code's main class that extends Application must declare the stage variable as a public static variable:
public class SwitchingPass extends Application {
//this is necessary to initialize the owner of the popup
public static Stage stage;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Again, probably not the best way to accomplish this, but it works, and perhaps it is helpful to someone else.
I did that this way.
First create an interface
public interface DataSender {
void send(String data);
}
and then implement that interface to your Main Window Controller
public class FXMLDocumentController implements Initializable,DataSender {
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
try {
Stage popupSave = new Stage();
popupSave.initModality(Modality.NONE);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("PopUp.fxml"));
Parent root = loader.load();
PopUpController controller = loader.getController();
controller.setX(7);
//this is the line use to get data from popup
controller.setSendDataSender(this);
Scene scene = new Scene(root);
popupSave.setScene(scene);
popupSave.show();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
//this method can call from popus controller
#Override
public void send(String data) {
label.setText(data);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
and then override implemented interface method and inside the method you can change Main window UI data I changed label text.
and then create variable in pupup controller with type DataSender(created interface befor) and create method to set that interface
public class PopUpController implements Initializable {
private int x;
//this is the variable
private DataSender dataSender;
#FXML
private Button btnOk;
#FXML
private TextField txtText;
#Override
public void initialize(URL url, ResourceBundle rb) {
btnOk.setOnAction(e->{
//When Click this button will call Main Window send method
dataSender.send(txtText.getText());
});
}
public void setX(int x){
this.x=x;
}
//this is the method to set variable value from Main Window
public void setSendDataSender(DataSender ds){
this.dataSender=ds;
}
}
and then when popup window button clicked then call send method with data and then will change main window label text.
This solution is work for me.hope this useful for you also .

JavaFX controller communication with dynamic content

Here is a general structure of a JavaFX android mobile application I am creating.
Using (AppBar or AppBarSearch these interchange dynamically) as nested controllers within Primary Application FXML.
ParentController
- AppBarController
- AppBarSearchController
primary.fxml
- appBar.fxml / appBarSearch.fxml
<AnchorPane fx:id="appBarPane" prefHeight="56.0" prefWidth="350.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<fx:include source="appbar.fxml" fx:id="appBar" />
<!-- initially shows AppBar but appBarSearch can also be here after clicking search button -->
</children>
</AnchorPane>
A button in each of the child fxml is responsible for changing between the fxml content from appBar/AppBarSearch.
The issue arises when I am dynamically change the content of the appBar to appBarSearch and back. I want the appBar menu button to communicate to the NavigationMenu to slide in and out.
I have been looking into whether I should somehow have an instance of the parentController inside the AppBarController.
I did use the following:
#FXML
private AppBarController appBarController; // injected via <fx:include fx:id="child" ... />
<fx:include source="appbar.fxml" fx:id="appBar" /> <- dynamically changes
//to dynamically change content in Panes
public static void setView(View view, Pane pane) {
try {
pane.getChildren().clear();
pane.getChildren().setAll((Node) FXMLLoader.load(Main.class.getResource(view.getTemplate()), resources));
} catch (IOException e) {
logger.error(e.getMessage());
}
}
#FXML
public void initialize() {
appBarController.setParentController(this);
}
#FXML
private void menuButtonClick (ActionEvent event) {
this.parentController.triggerMenu();
}
Initially the above works but after switching between appBarSearch and appBar it gives me a nullPointer to the parentController instance.
It may be that after switching between controllers dynamically it would not recognise the child controller.
I want the menuBtn in AppBar to open a navigationMenu so it would require to call triggerMenu() from within PrimaryController to start animations of it sliding in and out after the button in AppBar is clicked.
Thanks very much to the comments I was able to fix the issue and improve my understanding of how to use Controllers and included fxml.
Below is the general code I used to connect the child controllers with my primary controller and change views dynamically.
#FXML
private AppBarController appBarController; // injected via <fx:include fx:id="child" ... />
#FXML
private NavMenuController navMenuController; // injected via <fx:include fx:id="child" ... />
#FXML
private MainContentController mainContentController; // injected via <fx:include fx:id="child" ... />
#FXML
public void initialize() {
appBarController.setScreenParent(this);
navMenuController.setScreenParent(this);
mainContentController.setScreenParent(this);
}
/**
* Set View on a Pane Javafx component
*/
public <T extends Pane> boolean setView(View view, T pane) {
try {
FXMLLoader myLoader = new FXMLLoader(getClass().getResource(view.getTemplate()), resources);
pane.getChildren().clear();
pane.getChildren().setAll((Node) myLoader.load());
ControlledScreen childController = myLoader.getController();
childController.setScreenParent(this);
return true;
} catch (IOException e) {
logger.error(e.getMessage());
return false;
}
}
public void setMainContentView(View view) {
setView(view, mainContentPane);
}
public void setAppBarView(View view) {
setView(view, appBarPane);
}
public void setNavMenuView(View view) {
setView(view, navMenuPane);
}
public void triggerNavMenu() {
if (navMenuPane.getTranslateX() != 0) {
openNav.play();
appBarController.setMenuClosedImage();
} else {
closeNav.setToX(-(navMenuPane.getWidth()));
closeNav.play();
appBarController.setMenuClosedImage();
}
}

How to change the image of Imageview on MouseClick

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);
}
}

On Mouse Entered Method to swap Button position

I would like to develop a mouse entered method that swaps the locations of two buttons in real time using FXML and JavaFX which I am unfortunately very new to. Relocate(x,y), get/setLayoutX/Y and below get/setTranslateX/Y all throw IllegalArgumentEceptions with not much more understandable information in the stack trace. What is the preferred Button Property to use in order to get and then set a real-time location swap?
#FXML protected void neinHover (ActionEvent evt){
double jTmpX, jTmpY, nTmpX, nTmpY;
nTmpX = neinButton.getTranslateX();
nTmpY = neinButton.getTranslateY();
jTmpX = jaButton.getTranslateX();
jTmpY = jaButton.getTranslateY();
jaButton.setTranslateX(nTmpX);
jaButton.setTranslateY(nTmpY);
neinButton.setTranslateX(jTmpX);
neinButton.setTranslateY(jTmpY);
}
I supose you want something like this:
FXML:
<fx:root onMouseClicked="#swap" type="Pane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<Button fx:id="b1" mnemonicParsing="false" text="1" />
<Button fx:id="b2" layoutX="90.0" mnemonicParsing="false" text="2" />
</children>
</fx:root>
Controller:
public class MockPane extends Pane {
#FXML
private Button b1;
#FXML
private Button b2;
public MockPane() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"MockPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#FXML
private void swap() {
double b1x = b1.getLayoutX();
double b1y = b1.getLayoutY();
double b2x = b2.getLayoutX();
double b2y = b2.getLayoutY();
b1.setLayoutX(b2x);
b1.setLayoutY(b2y);
b2.setLayoutX(b1x);
b2.setLayoutY(b1y);
}
}
App:
public class MockApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
MockPane root = new MockPane();
Scene scene = new Scene(root, 200, 100);
stage.setScene(scene);
stage.show();
}
}

How can I create my own icon with propertise in JavaFX

Maybe somebody knows the answer and try help me.
I am creating own button.
<fx:root maxHeight="100.0" maxWidth="100.0" minHeight="50.0" minWidth="50.0" prefHeight="80.0" prefWidth="80.0" style="-fx-background-color: red;" type="StackPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" >
<children>
<ImageView fx:id="baseImage" fitHeight="66.0" fitWidth="72.0" pickOnBounds="true" preserveRatio="true" StackPane.alignment="TOP_CENTER" />
<Label fx:id="textBtn" alignment="BOTTOM_LEFT" prefHeight="17.0" prefWidth="75.0" textFill="WHITE" textOverrun="CLIP" StackPane.alignment="BOTTOM_LEFT" />
</children>
</fx:root>
So I need to change my button (Image and Label), when I am creating this in FXML file.
<MyButton layoutX="200.0" layoutY="162.0" />
e.g
<MyButton layoutX="200.0" layoutY="162.0" image="" text="" />
Can somebody help me ?
My Java Code
public class MyButton extends StackPane
{
#FXML
private ImageView baseImage;
#FXML
private Label textBtn;
public MyButton()
{
FXMLLoader fxmlLoader =new FXMLLoader(getClass().getResource("/pl/edu/wat/wcy/pz/icons/MyButtonView.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
init();
try {
fxmlLoader.load();
}
catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public Label getTextBtn() {
return textBtn;
}
public void setTextBtn(Label textBtn) {
this.textBtn = textBtn;
}
public ImageView getBaseImage() {
return baseImage;
}
public void setBaseImage(Image location) {
this.baseImage.setImage(location);
}
public void setButton(Label textBtn, Image location){
this.baseImage.setImage(location);
this.textBtn = textBtn;
}
But I care about icon are changed in FXML file, not JavaCode
}
If you want to set properties in FXML:
<MyButton layoutX="200.0" layoutY="162.0" image="" text="" />
you must define those properties in the corresponding class. In particular, MyButton must define setImage(...) and setText(...) methods (it already has setLayoutX(...) and setLayoutY(...) which are inherited from StackPane). It's hard to know exactly what functionality you want here, but you probably want to set these up as JavaFX Properties. If the intention is to map these into the Label and ImageView defined in the FXML file, you can just expose the relevant properties from the controls. You might need to work a bit to map the string from the image property into the correct thing.
public class MyButton extends StackPane
{
#FXML
private ImageView baseImage;
#FXML
private Label textBtn;
public MyButton()
{
FXMLLoader fxmlLoader =new FXMLLoader(getClass().getResource("/pl/edu/wat/wcy/pz/icons/MyButtonView.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
// not sure what this is:
// init();
// note that if you define
// public void initialize() {...}
// it will be called
// automatically during the FXMLLoader.load() method
try {
fxmlLoader.load();
}
catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public StringPropergty textProperty() {
return textBtn.textProperty();
}
public final String getText() {
return textProperty().get();
}
public final void setText(String text) {
textProperty().set(text);
}
// similarly expose a property for image, but you need to be able to coerce it from a String
}
(Incidentally, I assume this is just an example for the purposes of understanding how to do this. Everything you have in the example can be done using a regular button. Just wanted to make that clear for any others reading this post.)

Resources