javafx cannot load image resource - javafx

I am very new to javafx, and was getting java.lang.reflect.InvocationTargetException when testing with the code tutorial:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
public static final String IMAGE_NAME = "groceries.jpg";
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(setupScene(), 300, 300);
primaryStage.setScene(scene);
primaryStage.setTitle("Image Screen");
primaryStage.show();
}
StackPane setupScene() {
StackPane root = new StackPane();
ImageView imageView = new ImageView();
imageView.setPreserveRatio(true);
imageView.setSmooth(true);
Image image = new Image(getClass().getClassLoader().getResource(IMAGE_NAME).toString());
imageView.setImage(image);
root.setPrefSize(250, 250);
imageView.setFitHeight(root.getPrefHeight());
imageView.setFitWidth(root.getPrefWidth());
root.getChildren().add(imageView);
return root;
}
}
The exception was caused by java.lang.NullPointerException in line Image image = new Image(getClass().getClassLoader().getResource(IMAGE_NAME).toString());
The image file is in my project folder, but it doesn't seem to be loaded. I was able to get the image using Image image = new Image(new File(IMAGE_NAME).toURI().toURL().toString()), but when I switched back to Image image = new Image(getClass().getClassLoader().getResource(IMAGE_NAME).toString()), it just never worked.
Does anyone know why my program is behaving like this? Any ideas would be highly appreciated...
Edit: My image file is on the same level of the src folder:
- projectfolder
- groceries.jpg
- src
- Main.java
I'm using IntelliJ JavaFX Application to create the project, everything is in default state.

Image image = new Image(getClass().getClassLoader().getResource(IMAGE_NAME).toString()) and Image image = new Image(new File(IMAGE_NAME).toURI().toURL().toString()) do two different things.
The first will get a resource based off the class loader, which is most commonly used when extracting a resource directly from the jar file. The second is used to load the image from the file system, which is why that works in your case (that's where the file is!)

The getClass().getClassLoader().getResource() line, searchs for the file in the same location where your Main class is.
If you have this image in the src, you just need to add a '/' :
private String theme1Url = getClass().getResource("/groceries.jpg").toExternalForm();

Related

Can't get images to show up, trying to display 5 random cards from directory file

I'm not sure what I'm doing wrong. My pane opens, but it is blank. I have the file (card) as a directory (image) in the src folder. I have tried writing this so many different way but always get the same result. I just need to make the images actually show up. I don't know how to get the card images to show up. Any help is greatly appreciated.
package Assignment;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Collections;
public class Assignment extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Initialize card deck
ArrayList<Integer> cards = getCards();
// Create a FlowPane
FlowPane pane = new FlowPane();
pane.setVgap(10);
pane.setHgap(10);
pane.setPadding(new Insets(15, 15, 15, 15));
for (int i = 0; i < 5; i++) {
pane.getChildren().add(new ImageView(new Image("file:image/card/" + cards.get(i) + ".png")));
}
// Create scene and place it in the stage
Scene scene = new Scene(pane,500, 300);
primaryStage.setTitle("Poker 1");
primaryStage.setScene(scene);
primaryStage.show();
}
private ArrayList<Integer> getCards() {
ArrayList<Integer> cards = new ArrayList<>();
for (int i = 0; i < 52; i++) {
cards.add(i + 1);
}
Collections.shuffle(cards);
return cards;
}
public static void main(String[] args) {
launch(args);
}
}
What directory are your cards images in?
Click 'edit configuration' on the run button drop down menu, then look at the "Working directory" entry. Ex. Mine was C:\Users\NAME\IdeaProjects\Test
Placing the cards in C:\Users\NAME\IdeaProjects\Test\image\cards[1-52].png made your code work for me as written.

How to use modal dialog in this case?

I have a question. I need to make a GridPane with a directory choose that will then lead me to a modal dialog showing photos. I cannot figure how to do the modal dialog that also has to be a GridPane or a HBox...so the question is , how do I get to show a Modal Dialog after selecting the Folder and pressing the "Show" Button... Thanks a lot!
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class FotoView extends Application {
#Override
public void start(Stage primaryStage) {
TextField tf = new TextField();
Button b1 = new Button("Search");
Button b2 = new Button("Show");
DirectoryChooser dc = new DirectoryChooser();
GridPane gp = new GridPane();
gp.add(tf, 0 , 0);
gp.add(b1, 1, 0);
gp.add(b2, 0, 1);
b1.setOnAction(e-> dc.showDialog(primaryStage));
primaryStage.setScene(new Scene(gp)) ;
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
} ```
Below is a quick example where a first window has a button that opens up a DirectoryChooser. Once a directory has been selected a second smaller window opens up with the Modality set to APPLICATION_MODAL. In this second window you could add the image(s) that you load and add them to the GridPane.
import java.io.File;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage aStage) throws Exception {
final HBox root = new HBox();
final Button browseBtn = new Button("Click to open a Directory chooser");
root.getChildren().add(browseBtn);
browseBtn.setOnAction(e -> {
final DirectoryChooser chooser = new DirectoryChooser();
final File dir = chooser.showDialog(aStage);
openNewModalStage(aStage, dir);
});
final Scene scene = new Scene(root, 500, 500);
aStage.setScene(scene);
aStage.show();
}
private void openNewModalStage(final Stage aStage, final File aDirectory) {
final Stage stage = new Stage();
final GridPane grid = new GridPane();
final Scene scene = new Scene(grid);
grid.setStyle("-fx-background-color:black");
grid.setPrefWidth(400);
grid.setPrefHeight(400);
// get your images from 'aDirectory' and add them to your grid pane.
stage.setScene(scene);
// set the new windows Modality.
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
}
}
This way you would only need the one button and the dialog would show as soon as you've selected a directory. However, if you would still want a Search and Show button then just store the directory as a variable and add a listener on the 'show' button and move the openNewModalStage call to that one and remove the second argument.
Edit:
Also, depending on how many images and exactly what you want to display in the modal window, you might want to reconsider the GridPane and use a TilePane, or an hbox/vbox inside of a scroll pane. It's just a thought but I don't know what you will be doing with the GridPane.

How to pass file path from a FileChooser button to another button?

I'm trying to make a program with some filters of image by using JavaFx, so I need two button at least, one is a file chooser to open an image, and another one will be a choice box that allows to choose a filter.
My problem is how could a choice box get the path name or a file object from the file chooser.
here is my program unfinished :
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.layout.*;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Filter extends Application{
public void start(final Stage stage) {
stage.setTitle("FilterShop");
final FileChooser fileChooser = new FileChooser();
final Button openButton = new Button("Select a photo");
ChoiceBox<String> choiceBox = new ChoiceBox<>();
choiceBox.getItems().add("Choose a Filter");
choiceBox.getItems().addAll("Remove watermark", "Brightness", "Grey", "Mosaic");
choiceBox.getSelectionModel().selectFirst();
final Pane stac = new Pane();
openButton.setOnAction(e -> {
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
Image image = new Image(file.toURI().toString());
ImageView imageView = new ImageView(image);
imageView.setX(50);
imageView.setY(50);
imageView.setFitWidth(300);
imageView.setFitHeight(470);
imageView.setPreserveRatio(true);
stac.getChildren().add(imageView);
}
});
choiceBox.setOnAction(event1 -> {
if (choiceBox.getValue() == "Mosaic") {
try {
BufferedImage imagen = ImageIO.read(/* A file object is needed here. */ );
new Mosaic().mosaico(imagen, 80, 80);
} catch (IOException ie) {
System.err.println("I/O Error");
ie.printStackTrace(System.err);
}
}
});
openButton.setLayoutX(300);
openButton.setLayoutY(350);
choiceBox.setLayoutX(430);
choiceBox.setLayoutY(350);
stac.getChildren().addAll(openButton, choiceBox);
stage.setScene(new Scene(stac, 800, 400));
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
I am not sure what is the exact issue you are facing. Firstly FileChooser is not a Button. It is a helper class to interact with ToolKit to open the OS specific file chooser and return the results. And obvisously, it will no keep record of the returned results.
It is your duty to keep a reference of the retrieved file. This can be done in "N" number of ways. As you question focuses on get getting the value from the open button, I would suggest the below approach.
openButton.setOnAction(e -> {
File file = fileChooser.showOpenDialog(stage);
openButton.getProperties().put("FILE_LOCATION", file.getAbsolutePath());
...
});
choiceBox.setOnAction(event1 -> {
if (choiceBox.getValue() == "Mosaic") {
File file = new File(openButton.getProperties().get("FILE_LOCATION").toString());
}
});

Why can't I use the same Image twice?

I have been trying to learn more on using JavaFX and in this program I am trying to display a 3 by 3 game of tic tac toe that has already been played. I have created my ImageViews and set the images I want to use but once I started plugging them into columns and rows I noticed I cannot use the same one twice. I have an image for an empty space, an X, and an O. Once I use one more than once I get an "Exception while running application". Might be a rookie mistake, but an explanation would be greatly appreciated.
package Fresh;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Fresh extends Application {
#Override
public void start(Stage primaryStage) {
//Create a pane and set its properties
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
pane.setHgap(5.5);
pane.setVgap(5.5);
//imv0 = X image
final ImageView imv0 = new ImageView();
final Image image0 = new Image(Fresh.class.getResourceAsStream("images/x.gif"));
imv0.setImage(image0);
//imv1 = O image
final ImageView imv1 = new ImageView();
final Image image1 = new Image(Fresh.class.getResourceAsStream("images/o.gif"));
imv1.setImage(image1);
//imv2 = empty image
final ImageView imv2 = new ImageView();
final Image image2 = new Image(Fresh.class.getResourceAsStream("images/empty.gif"));
imv2.setImage(image2);
//Place nodes in the pane
pane.add((imv0),0,0);
pane.add((imv1), 1, 0);
//Once I try to use imv0 again "I get an exception while running".
pane.add((imv0),0,1);
//Create a scene and place it in the stage
Scene scene = new Scene(pane);
primaryStage.setTitle("ShowGridPane");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You can use the same Image as many times as you like; however, you can only place a given ImageView in one place in the scene graph. From the Javadocs:
A node may occur at most once anywhere in the scene graph.
To see why this must be true, what would you expect
GridPane.getColumnIndex(imv0)
to return, given the code you have?
So you can do:
final Image image0 = new Image(Fresh.class.getResourceAsStream("images/x.gif"));
ImageView imv00 = new ImageView(image0);
ImageView imv01 = new ImageView(image0);
pane.add(imv00, 0, 0);
pane.add(imv01, 0, 1);
// etc
The overhead here is not too bad; you use the same image data for each ImageView.

Set Graphic to label

I want to set Label to graphic. I tested this code:
private static final ImageView livePerformIcon;
static
{
livePerformIcon = new ImageView(MainApp.class.getResource("/images/Flex.jpg").toExternalForm());
}
final Label label = new Label();
label.setStyle("-fx-background-image: url(\"/images/Flex.jpg\");");
livePerformIcon.setFitHeight(20);
livePerformIcon.setFitWidth(20);
label.setGraphic(livePerformIcon);
But I don't see any image.
The only way that I found to make it work is this:
label.setStyle("-fx-background-image: url(\"/images/Flex.jpg\");");
Is there a way to solve this?
Not sure, but AFAIK controls should be created on the JavaFX Application thread, but you're creating ImageView in a static initializer, which I'm not sure if it's executed on the Application thread.
Besides: Do you really want livePerformIcon to be static???
This one made from the data used in the docs, works perfectly for me
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class LabelWithImages extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Label With Image Sample");
stage.setWidth(400);
stage.setHeight(180);
HBox hbox = new HBox();
//Replace the image you want to put up
Image image = new Image(getClass().getResourceAsStream("a.png"));
Label label = new Label("Demo Label");
label.setGraphic(new ImageView(image));
hbox.setSpacing(10);
hbox.getChildren().add((label));
((Group) scene.getRoot()).getChildren().add(hbox);
stage.setScene(scene);
stage.show();
}
}
Code snippets below will set the value of the property graphic of a label. You can use any of the two. I prefer using javafx css, just to implement the model-view-controller design.
// programmatically, provided with image input stream
label.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("path/to/image.png"))));
// javafx css, provided with image url
.label {
-fx-graphic: url("path/to/image.png");
}

Resources