1

I have an application which opens absolutely fine, but am having trouble setting an icon for it. The icon I give the path to is there, and changing to another imagine in that directory shows the icon 9/10 times, but this image never shows. There is always a question mark in it's place. So even on another file, which I know will work (ie. isn't corrupted), how come it only shows so rarely?

Below is the code of MyApplication.java

package MyApp;

import MyApp.Variables.Constants;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Forms/FormMain.fxml"));

        primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("/img/appicon.png")));
        primaryStage.setTitle("MyApp " + Constants.VERSION_NAME + " (" + Constants.RELEASE_ID + ")"); 
        primaryStage.setScene(new Scene(root, 1000, 800));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Below is the project directory structure relating /img/ to Main.java:

Directory structure

I have tried all the solutions here but nothing fixed my issue.

Running on Ubuntu 16.04, intelliJ IDEA for the IDE, though the problem persists with an exported JAR file.

Community
  • 1
  • 1
  • Use [new Image("File:/img/appicon.png")] if it works. also check this http://download.java.net/jdk8/jfxdocs/javafx/scene/image/Image.html as for the jar you have to use [new Image(getClass().getResourceAsStream("/img/appicon.png");] – GOXR3PLUS Jul 03 '16 at 17:50
  • I'm afraid that didn't work. I've had a look on the docs but I'm not really sure what to gain from it, I have tried using various constructors, passing in a stream instead of a string, background loading, nothing worked. – Mike Croall Jul 03 '16 at 17:52
  • when you export it as a jar you have to get it as a Stream using new Image(getClass().getResourceAsStream("/img/appicon.png"); can you provide an image of how your project is constructed? – GOXR3PLUS Jul 03 '16 at 17:53
  • Image has been added to main post. I have changed my code to use getClass().getResourceAsStream(...) but still to no avail. – Mike Croall Jul 03 '16 at 18:02
  • Use a constructor `Main()` and there load the icon with `new Image(MainApp.class.getResource(filename with extension).toExternalForm())` in a variable. In your `start()` method add the variable to your icons. – aw-think Jul 03 '16 at 18:02
  • There is a Main(String[] args) constructor present which is the one that automatically gets called. If I initialise the variable before it runs launch(args), it says Internal Graphics not intialised yet. If I initialise the variable after, it is null when used, because launch involves running start. Can I initialise internal graphics manually somehow? – Mike Croall Jul 03 '16 at 18:07
  • And you should be aware of the thing with the dash, explained [here](http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getResource-java.lang.String-) – aw-think Jul 03 '16 at 18:07
  • main(string[] args) is not a constructor! It's a method. But I think you should remvoe the first dash or add a dot in front of it. – aw-think Jul 03 '16 at 18:09
  • That's good to know, thank you. – Mike Croall Jul 03 '16 at 18:09
  • Oh yes, my bad! I'll try that now. – Mike Croall Jul 03 '16 at 18:09
  • Removing the dash causes Unable to construct Application instance: class MyApp.Main. – Mike Croall Jul 03 '16 at 18:11
  • @Mike Croall when you export the jar run it with cmd or terminal what error you get there? java -jar myjar.jar – GOXR3PLUS Jul 03 '16 at 18:33
  • Absolutely no errors. It simply shows the default question mark, and doesn't throw any errors in terminal. – Mike Croall Jul 03 '16 at 18:37
  • Class Image doesn't throw errors on creation, this is for convenience. It stores errors in a property. – aw-think Jul 03 '16 at 18:39

1 Answers1

3

Loading Data from your disk is time consuming, so you be able to start loading the icon while the object is constructed. Place it in a constructor and save it in a instance member. Normally you need to add more than one icon, because each platform needs it own sizes (for links and so on).

package MyApp;

import MyApp.Variables.Constants;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class Main extends Application {

    private Image icon;

    public Main() {
      icon = new Image(Main.class.getResource("/img/appicon.png").toExternalForm());
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Forms/FormMain.fxml"));

        primaryStage.getIcons().add(icon);
        primaryStage.setTitle("MyApp " + Constants.VERSION_NAME + " (" + Constants.RELEASE_ID + ")"); 
        primaryStage.setScene(new Scene(root, 1000, 800));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

My icon was this: enter image description here and the app structure in Netbeans looks like that:

enter image description here

and the running app look like that:

enter image description here

aw-think
  • 4,723
  • 2
  • 21
  • 42
  • getResource only accepts a string, it refuses to take no parameters. – Mike Croall Jul 03 '16 at 18:16
  • I did try that while you were making the edit - it still Cannot construct Application instance etc, due to InvocationTargetException in native code, due to NullPointerException from getResource being null. Removing the full stop at the beginning causes getResource to no longer be null, application launches, but icon still doesn't show. – Mike Croall Jul 03 '16 at 18:21
  • Hm, I've done some points, and on my machine this is running and showing the app icon. Maybe you need to load more icons in different resolutions like 16, 22, 24, 32, 48 and so on. This is needed for other platforms like Mac or Windows where you have different Icon sizes on different places. – aw-think Jul 03 '16 at 18:30
  • Okay, I'll look into it. Many thanks for your efforts! – Mike Croall Jul 03 '16 at 18:31
  • So adding in the sizes I want the icon to be make it work more, but still only sometimes. For example, I make it 16x16, run it, icon shows. Close it, run it again with no changes, default icon shows instead of mine. – Mike Croall Jul 03 '16 at 18:42
  • Well you need to add a lot of icon sizes to `primaryStage.getIcons()`, because it is a ObservableList you can add multiple sizes of the same icon. – aw-think Jul 03 '16 at 18:45
  • I am now adding multiple different sizes of icon, and it's still being inconsistent, no matter the combination of icon sizes. It may just be ubuntu causing problems as I don't know why else this could happen now. – Mike Croall Jul 03 '16 at 18:47
  • That sounds strange. I don't have any problems with my app on Ubuntu 16.04, it loads all icons as aspected. – aw-think Jul 03 '16 at 18:49
  • Interesting. I currently have sizes 16,22,24, and 32 all being added to the icons list. I run it once: shows my icon, stop it and run it again (no changes to anything): fails to show my icon. Thanks for the help anyway! – Mike Croall Jul 03 '16 at 18:50
  • default app launcher icon size is 48px. – aw-think Jul 03 '16 at 18:51
  • But why would it show it the first time and not the second? – Mike Croall Jul 03 '16 at 18:52
  • How long you are waiting between these two calls? – aw-think Jul 03 '16 at 18:53
  • Whether it's a couple seconds or a whole minute, it behaves the same. – Mike Croall Jul 03 '16 at 18:55