I want to change the Image in the Image View using FXML and to change the Image I open the fileChooser to pick an image that should replace the old one , I have 2 issues right now :
How to make the ImageView Clickable this is the code I'm using for this
public void imagePicker(){
Defaultview.setPickOnBounds(true); // allows click on transparent areas
Defaultview.setOnMouseClicked((MouseEvent e) -> {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open Resource File");
fileChooser.showOpenDialog(new Stage());
});
}
in my FXML file I have:
<ImageView fx:id="Defaultview" fitHeight="93" fitWidth="93"
pickOnBounds="true" preserveRatio="true" onAction='#imagePicker'>
and for the image change I'd like to change it from
Image url="#../images/default.png"
to the Image Chosen .
ImageView doesn't have an onAction property (so I think you should get a runtime error when you load your FXML file). If you want to respond to mouse clicks, then you should use onMouseClicked:
<ImageView fx:id="Defaultview" fitHeight="93" fitWidth="93"
pickOnBounds="true" preserveRatio="true" onMouseClicked='#imagePicker'>
Registering the event handler in FXML means that the imagePicker() method will be invoked when the event occurs (i.e. when the user clicks on the image view). There is no need (and it's incorrect) to set the onClicked handler from inside the method that is invoked when the onClick event occurs. All you need is
public void imagePicker(){
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open Resource File");
// use existing window here, don't create a new one:
File file = fileChooser.showOpenDialog(Defaultview.getScene().getWindow());
if (file != null) {
Defaultview.setImage(new Image(file.toURI().toString()));
}
}
In JavaFx ImageView has setOnMouseClicked property,so if you want to import an image from your PC using fileChooser ,you need to add an extension to your FileChooser to define only images and skip other files
public void imagePicker(){
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("JPG files (*.jpg)", "*.JPG");
FileChooser.ExtensionFilter extFilterPNG = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.PNG");
fileChooser.getExtensionFilters().addAll(extFilterJPG, extFilterPNG);
File ChooserFile = fileChooser.showOpenDialog(Defaultview.getScene().getWindow());//your owner
if (ChooserFile != null) {
Image image = new Image(ChooserFile.toURI().toString());
Defaultview.setImage(image);
}
}
and add MouseEvent (setOnMouseClicked) to your ImageView :
Defaultview.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
imagePicker();
}
});
Related
I cant convert this code into scene builder...
The problem is in event handler....
I am not getting how to use the confirmCloseEventHandler event handeler in java
fx scene builder...
thanks in advance.
mainly i cant use those event handlers... in fxml controllers...
public class Javafxpopupmessage extends Application {
private Stage mainStage;
#Override
public void start(Stage stage) throws Exception {
this.mainStage = stage;
stage.setOnCloseRequest(confirmCloseEventHandler);
Button closeButton = new Button("Close Application");
closeButton.setOnAction(event ->
stage.fireEvent(
new WindowEvent(
stage,
WindowEvent.WINDOW_CLOSE_REQUEST
)
)
);
StackPane layout = new StackPane(closeButton);
layout.setPadding(new Insets(100));
stage.setScene(new Scene(layout));
stage.show();
}
private EventHandler<WindowEvent> confirmCloseEventHandler = event -> {
Alert closeConfirmation = new Alert(
Alert.AlertType.CONFIRMATION,
"Are you sure you want to exit?"
);
Button exitButton = (Button)
closeConfirmation.getDialogPane().lookupButton(
ButtonType.OK
);
exitButton.setText("Exit");
closeConfirmation.setHeaderText("Confirm Exit");
closeConfirmation.initModality(Modality.APPLICATION_MODAL);
closeConfirmation.initOwner(mainStage);
// normally, you would just use the default alert positioning,
// but for this simple sample the main stage is small,
// so explicitly position the alert so that the main window can still be
seen.
// closeConfirmation.setX(mainStage.getX());
//closeConfirmation.setY(mainStage.getY() + mainStage.getHeight());
Optional<ButtonType> closeResponse = closeConfirmation.showAndWait();
if (!ButtonType.OK.equals(closeResponse.get())) {
event.consume();
}
};
public static void main(String[] args) {
launch(args);
}
}
Registering some handler for the primary stage via fxml could only be done with a bad hack, since FXMLLoader only has access to objects it creates itself.
You could add a listener to the Node.scene property of some node in your scene and add a listener to the window property of that scene as soon as it's set and access the window as soon as it's assigned, which is quite complex for something that could be done using much simpler code in the start method.
Other than that hack you won't get around registering that event handler in the start method (or passing the Stage to the controller resulting in more complex code than the one posted).
As for the close button onAction event: You can use a method of your controller as handler:
fxml
<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="mypackage.MyController">
<children>
<Button text="Close Application" onAction="#close"/>
</children>
<padding>
<Insets topRightBottomLeft="100"/>
</padding>
</StackPane>
controller
package mypackage;
...
public class MyController {
#FXML
private void close(ActionEvent event) {
Node source = (Node) event.getSource();
Window window = source.getScene().getWindow();
window.fireEvent(new WindowEvent(
window,
WindowEvent.WINDOW_CLOSE_REQUEST));
}
}
I have a pane with a label, a text field and a combo box inside a VBox in fxml file. Let´s call it tempPane.
In the same stage I have a button.
Once the button is pressed I need to add to the VBox a pane exactly the same as tempPane. This is, adding dynamically a pane to the VBOX.
I am able to add individual controls such as buttons or labels or text fields to the VBox, but I can´t obtain the same results when trying to add this new pane.
Part of the controller code:
#FXML
private Pane tempPane;
#FXML
private Button btnAddNewPane;;
#FXML
private VBox vBox;
#FXML
void addNewPane(ActionEvent event) {
...
Pane newPane = new Pane();
newPane = tempPane;
// New ID is set to the newPane, this String (NewID) should be
//different each time button is pressed
newPane.setId(newID);
vBox.getChildren().add(newPane);
...
}
And the error I´m getting is:
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = VBox[id=filterBox]
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:580)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at com.sener.dbgui.controller.SearchController$1.run(SearchController.java:53)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
at java.base/java.lang.Thread.run(Thread.java:844)
So, why am I getting this duplicate children error? I´m changing the newPane ID before adding it to the VBox.
Pane newPane = new Pane();
newPane = tempPane;
...
vBox.getChildren().add(newPane);
This code does create a new Pane (first line) but immediately drops the new instance by overwriting it with the old one (second line).
The error happens since the contract of Node does not allow it to be placed twice in a scene and you're adding the same Pane that is already a child of vBox again. Modifying the id property does not change that fact.
You need to create a new copy of the subscene rooted at tempPane if this is supposed to work.
You could create a custom Pane for this scene:
subFXML.fxml
<fx:root xmlns:fx="http://javafx.com/fxml" type="javafx.scene.layout.Pane">
<!-- content of tempPane from old fxml goes here -->
...
<Button fx:id="btnAddNewPane" />
...
</fx:root>
public class MyPane extends Pane {
public MyPane() {
FXMLLoader loader = getClass().getResource("subFXML.fxml");
loader.setRoot(this);
loader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
#FXML
private Button btnAddNewPane;
public void setOnAction(EventHandler<ActionEvent> handler) {
btnAddNewPane.setOnAction(handler);
}
public EventHandler<ActionEvent> getOnAction() {
return btnAddNewPane.getOnAction();
}
}
old fxml
Be sure to import MyPane.
...
<VBox fx:id="vBox">
<children>
<!-- replace tempPane with MyPane -->
<MyPane onAction="#addNewPane"/>
</children>
</VBox>
...
old controller
#FXML
private VBox vBox;
#FXML
void addNewPane(ActionEvent event) {
...
MyPane newPane = new MyPane();
newPane.setId(newID); // Don't know why setting the CSS id is necessary here
newPane.setOnAction(this::addNewPane); // set onAction property
vBox.getChildren().add(newPane);
...
}
It is written in your comments already why you are getting duplicate ID.
// New ID is set to the newPane, this String (NewID) should be
//different each time button is pressed
You are passing the same string as a parameter.
newPane.setId("NewID");
try using a dynamically generated and unique id for each pane.
String newId; //generate the id by user input or internally
newPane.setId(newId);
i have a project in which i have in my db images stored with their names only so i want to load those image with javafx
and i have no idea how to load thos images
public void initialize(URL url, ResourceBundle rb) {
// help me here to retreive my images names
}
and this is my button that allows me to change my cover picture
here is the code
changecover.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
try {
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("JPG files (*.jpg)", "*.JPG");
FileChooser.ExtensionFilter extFilterPNG = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.PNG");
fileChooser.getExtensionFilters().addAll(extFilterJPG, extFilterPNG);
//Show open file dialog
File file = fileChooser.showOpenDialog(null);
BufferedImage bufferedImage = ImageIO.read(file);
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
coverpic.setImage(image);
Groupe g = gs.getGroupe(5);
g.setPhoto_couverture(coverpic.toString());
gs.update(g);
//myImageView.setImage(image);
} catch (IOException ex) {
Logger.getLogger(Groupe_homeController.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
Why load the image data to a BufferedImage and then convert this BufferedImage to a JavaFX Image when you can avoid storing the image data in memory twice by directly loading the data to a Image:
Image image = new Image(file.toURI().toURL().toExternalForm());
I'm not sure how a database is involved here though, since FileChooser allows you to choose the image from storage devices available to the client only, which means you'd need to implement some way of retrieving the data from the server... (unless the database is for use on the local machine only)
I'm new in javafx and I was trying to create custom dialogs/alerts. The thing is that I'm using Scene Builder to design the GUI, and I want to modify the dialog each time I load the fxml file (i.e change the title, label text, etc.), so I wanted to know if there's a way to send parameters and modify the stage/scene, or any other way I can achieve this.
To be more specific, let's say there's an error I want to handle anywhere in my program, so I load a new fxml file that represents the error dialog I created, and I modify the components inside it, depending on the type of error I need to handle, similar to, for example, JOptionPane.showMessageDialog(...) in swing.
For the use case you describe, you can just use the Dialog API, or the specialized Alert class that is part of that.
For the more general question you ask:
I wanted to know if there's a way to send parameters and change the stage/scene
the way to do this is to use the custom component mechanism described in the documentation.
In short, make a subclass of the UI type you need that loads the FXML file, and defines the properties you need, e.g.
public class ExceptionPane extends BorderPane {
private final ObjectProperty<Exception> exception ;
public ObjectProperty<Exception> exceptionProperty() {
return exception ;
}
public final Exception getException() {
return exceptionProperty().get();
}
public final void setException(Exception exception) {
exceptionProperty().set(exception);
}
#FXML
private final TextArea stackTrace ;
#FXML
private final Label message ;
public ExceptionPane() throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
loader.setRoot(this);
loader.setController(this);
loader.load();
exception.addListener((obs, oldException, newException) -> {
if (newException == null) {
message.setText(null);
stackTrace.setText(null);
} else {
message.setText(newException.getMessage());
StringWriter sw = new StringWriter();
newException.printStackTrace(new PrintWriter(sw));
stackTrace.setText(sw.toString());
}
});
}
}
Then define the FXML using a "dynamic root":
<!-- imports etc -->
<fx:root type="BorderPane" ...>
<center>
<TextArea fx:id="stackTrace" editable="false" wrapText="false" />
</center>
<top>
<Label fx:id="message" />
</top>
</fx:root>
Now you can use this directly in either Java or in FXML:
try {
// some code...
} catch (Exception exc) {
ExceptionPane excPane = new ExceptionPane();
excPane.setException(exc);
Stage stage = new Stage();
stage.setScene(new Scene(excPane));
stage.show();
}
or
<fx:define fx:id="exc"><!-- define exception somehow --></fx:define>
<ExceptionPane exception="${exc}" />
I have a stage with these properties
stage = new Stage(StageStyle.DECORATED);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.setTitle("My App");
stage.getIcons().add(new Image(icon-address));
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("start.fxml"));
fxmlLoader.setController(this);
...
...//and other properties
It is in full screen in this stage. I have a button and each time I click on it , a method of another class is called and the reference of this stage is passed to it.
For example, if I have two classes Start and ButtonClicked
In Start, I have this :
Button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
buttonClicked a = new buttonClicked ();
try {
a.render(stage);
} catch (Exception ex) {
Logger.getLogger(menuController.class.getName())
.log(Level.SEVERE, null , ex);
}
}
});
Now, the render method is called and I have the following code inside render :
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("buttonclicked.fxml"));
fxmlLoader.setController(this);//set Controller for our fxml file
loader = fxmlLoader.load();//loader is a stackPane because buttonclick.fxml has stackPane
stage.setScene(new Scene(loader));
stage.setFullScreen(true);
...
The problem is, if user clicks on button, stage become a 1024x700(because i have pictures in start.fxml and buttonclicked.fxml. The size of both the picture is 1024x700
After a moment, it becomes full screen. How can i fix this ?
I want to kill the delay in full screen
Thanks
Try
stage.getScene().setRoot(loader);
in render method.
By doing this, the creation of a new scene is eliminated. Therefore I guess, some UI related updates and calculations that must be done after the scene has been shown, are also eliminated.