Trouble setting application icon with JavaFX - java

I am having trouble changing the application icon with JavaFX (code is below with my attempts commented out). I tried implementing several solutions from previous stack overflow answers but I'm not sure if those methods are now deprecated. I am using NetBeans 8.2 (and the icon is in a folder called images under the source package).
1st Attempt: Illegal start of expression. identifier expected: JavaFX Application Icon
2nd Attempt: No suitable method found for add(java.awt.Image): Changing the icon of my java application
3rd Attempt: Cannot find symbol. Cannot instantiate the type Image java?
5th Attempt: Image is abstract it cannot be instantiated. http://docs.oracle.com/javafx/2/deployment/self-contained-packaging.htm
package javafxapplication1;
import java.awt.Image;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javax.imageio.ImageIO;
public class JavaFXApplication1 extends Application {
private double xOffset = 0;
private double yOffset = 0;
#Override
public void start(Stage stage) throws Exception {
//stage.getIcons().add(Image(<JavaFXApplication1>.class.getResourceAsStream( "/images/fiji.png" ));
Image i = ImageIO.read(getClass().getResource("/images/fiji.png"));
//setIconImage(i);
//stage.getIcons().add(i);
//stage.getIcons().add(Image("/images/fiji.png"));
// stage.getIcons().add(ImageIO.read(getClass().getResource("/images/fiji.png")));
//stage.getIcons().add(new Image(this.getClass().getResourceAsStream("/images/fiji.png")));
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
//stage.initStyle(StageStyle.UNDECORATED);
// makes it moveble
// LOOK INTO!!!!!!!!!!!
root.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
xOffset = event.getSceneX();
yOffset = event.getSceneY();
}
});
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stage.setX(event.getScreenX() - xOffset);
stage.setY(event.getScreenY() - yOffset);
}
});
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

You need to load an Image and add it to the stage's icons.
import javafx.scene.image.Image;
Image icon = new Image(Controller.class.getResource("/game.png").toExternalForm(), false);
primaryStage.getIcons().add(icon);
However, on Ubuntu these icons do not get displayed. This JavaFX defect hasn't been solved for a long time.
It seems that your first attempt is missing the new keyword for the Image instantiation, and make sure it is a javafx.scene.image.Image, not a java.awt.Image image, which has a different constructor. Try this:
stage.getIcons().add(new Image(JavaFXApplication1.class.getResource( "/images/fiji.png" ).toExternalForm());

First, load an image and then add to the stage object. Please make sure to give path starting from the inside of the resource folder, not from the resource folder, or else use the whole project path.
Image favicon = new Image('URL_OF_THE_IMAGE');
stage.getIcons.add(favicon);

Related

Understanding getSystemResource() in Java

How can I access the icon.png file without specifing the whole path "main/res/images/icon.png" in ClassLoader.getSystemResource()? I wanted something like images/icon.png.
This is the project explorer
Main.java:
package main.java.OOP20.alt.sim.View;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import java.awt.*;
public class Main extends Application {
public static final double PROPORTION = 1.5;
#Override
public void start(final Stage primaryStage) throws Exception {
final Dimension dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
final double width = dimension.getWidth() / PROPORTION;
final double height = dimension.getHeight() / PROPORTION;
final Parent root=FXMLLoader.load(
ClassLoader.getSystemResource("main/res/layouts/sample.fxml")
);
primaryStage.setTitle("Title");
primaryStage.setScene(new Scene(root, width, height));
primaryStage.getIcons().add(
new Image(ClassLoader.getSystemResource("main/res/images/icon.png").toString())
);
primaryStage.show();
}
public static void main(final String[] args) {
launch(args);
}
}
You can get url of both fxml or png files with using Class<T>#getResource(). You should use following solutions:
For fxml file:
Parent root = FXMLLoader.load(getClass().getResource("/layouts/sample.fxml"));
For png file:
primaryStage.getIcons().add(new Image(getClass().getResource("/images/icon.png").toString()));
Note: If you want to load any external resources (fxml, png etc) from resource folder within static methods, you must use Main.class.getClass() instead of getClass(). It guarantees the resource will be loaded relative to that class, and never relative to a subclass.

JavaFX: Remove percentage from ProgressIndicator

I have been trying to remove the percentage text below the ProgressIndicator, but is unsuccessful. I have found several mentions of this and tried the accepted answer, but it does not work
Using Java 8 Update 121
package com.company.mytest;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ProgressApp extends Application {
public static void main(String[] args) {
launch(args);
}
/* (non-Javadoc)
* #see javafx.application.Application#start(javafx.stage.Stage)
*/
#Override
public void start(Stage stage) throws Exception {
ProgressIndicator progress = new ProgressIndicator();
progress.setProgress(0.5f);
StackPane root = new StackPane();
root.getChildren().add(progress);
Scene scene = new Scene(root);
scene.getStylesheets()
.add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(scene);
stage.setWidth(300);
stage.setHeight(300);
stage.setTitle("JavaFX 8 app");
stage.show();
}
}
I know the CSS is loaded, because I am able to change the percentage font size. This is the CSS content of the progress.css file.
.progress-indicator .percentage {
visibility: hidden;
}
Setting the -fx-fill attribute to null seems solving the problem:
.progress-indicator .percentage {
-fx-fill:null;
}
Update:
Setting only this attribute hides the percentage text, but still takes up the space.
A possible workaround is to set the -fx-padding attribute of the ProgressIndicator:
.progress-indicator .percentage {
-fx-fill:null;
}
.progress-indicator {
-fx-padding: 0 0 -16 0;
}
The only problem is the hardcoded value: if the CSS for .progress-indicator .percentage is changed (e.g. bigger font size) then this also has to be adapted.
Alternatively a programatic solution in this answer: How can I avoid the display of percentage values, when using the ProgressIndicator of JavaFX UI Controls

Detect URL change in JavaFX WebView

In JavaFX's WebView I am struggling to detect change in URL.
I have this method in a class:
public Object urlchange() {
engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
#Override
public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
return engine.getLocation());
}
}
});
}
and I am trying to use it for an object called loginbrowser like:
System.out.print(loginbrowser.urlchange());
Can you see what I've done wrong?
(Part of) what you are doing wrong
The code you provided in your question doesn't even compile. The changed method of a ChangeListener is a void function, it can't return any value.
Anyway, loading of stuff in a web view is an asynchronous process. If you want the value of the location of the web view after the web view has loaded, you need to either wait for the load to complete (inadvisable on the JavaFX application thread, as that would hang your application until the load is complete), or be notified in a callback that the load is complete (which is what the listener you have is doing).
(Probably) what you want to do
Bind some property to the location property of the web engine. For example:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.web.*;
import javafx.stage.Stage;
public class LocationViewer extends Application {
#Override
public void start(Stage stage) throws Exception {
Label location = new Label();
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.load("http://www.fxexperience.com");
location.textProperty().bind(engine.locationProperty());
Scene scene = new Scene(new VBox(10, location, webView));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The above code will update the location label whenever the location of the web view changes (try it by running the code then clicking on some links). If you wish to only update the label once a page has successfully loaded, then you need a listener based upon the WebView state, for example:
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.web.*;
import javafx.stage.Stage;
public class LocationAfterLoadViewer extends Application {
#Override
public void start(Stage stage) throws Exception {
Label location = new Label();
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.load("http://www.fxexperience.com");
engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
if (Worker.State.SUCCEEDED.equals(newValue)) {
location.setText(engine.getLocation());
}
});
Scene scene = new Scene(new VBox(10, location, webView));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you run the last program and click on some links, you will notice it delays the updating of the location label until after the pages you click on completely finish loading, as opposed to the first program which updates the label as soon as the location changes, regardless of whether the load takes a while or indeed works at all.
Answers to additional questions
How can I use the url value in the label in a conditional statement? I want an action to be preformed if it changed from the original one.
location.textProperty().addListener((observable, oldValue, newValue) -> {
// perform required action.
});

Create a native bundle for a JavaFX application that has a preloader

I have a JavaFX application that uses a preloader. What I'd like to do is package it up as a native bundle (Mac app or Windows exe file that contains a copy of the Java JDK) so users who don't have the right version of Java on their computers can still run the app. I've followed Oracles instructions for creating native bundles and for adding preloaders. What I get is exactly what you'd expect—a native bundle that runs my program.
The problem is that the bundle completely ignores my preloader. It just runs the main program (after a long load time). I know the preloader is included because, when I run the jar file alone, it shows up.
Has anyone successfully bundled a JavaFX app with a preloader? Can you guide me through how to do so? I'm using Netbeans.
EDIT:
Here is the Preloader:
import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Splash extends Preloader {
ProgressIndicator bar;
ImageView Background;
Stage stage;
private Scene createPreloaderScene() {
bar = new ProgressIndicator();
bar.setLayoutX(380);
bar.setLayoutY(250);
bar.setPrefSize(60, 60);
Background = new ImageView("Images/Splash.png");
Background.setEffect(null);
Pane p = new Pane();
p.setStyle("-fx-background-color: transparent;");
p.getChildren().addAll(Background, bar);
Scene scene = new Scene(p, 794, 587);
scene.setFill(null);
scene.getStylesheets().add(Scrap2.class.getResource("CSS/Progress.css").toExternalForm());
bar.setId("myprogress");
return scene;
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setScene(createPreloaderScene());
stage.initStyle(StageStyle.TRANSPARENT);
stage.show();
}
#Override
public void handleStateChangeNotification(StateChangeNotification scn) {
if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
stage.hide();
}
}
#Override
public void handleProgressNotification(ProgressNotification pn) {
bar.setProgress(pn.getProgress());
}
#Override
public void handleApplicationNotification(PreloaderNotification arg0) {
if (arg0 instanceof ProgressNotification) {
ProgressNotification pn= (ProgressNotification) arg0;
bar.setProgress(pn.getProgress());
}
}
}
And here is the first part of my main program:
#Override
public void init(){
/*Root*/
root = new Pane();
root.setStyle("-fx-background-color: transparent;");
root.setLayoutX(150);
notifyPreloader(new Preloader.ProgressNotification(0.1));
/*Create Background*/
createBinding(stage);
createContents();
createSaveMessages();
createFlipBook();
notifyPreloader(new Preloader.ProgressNotification(0.2));
/*Add Pages*/
createOverview();
createAccounts();
notifyPreloader(new Preloader.ProgressNotification(0.3));
createCounselors();
createInsurance();
notifyPreloader(new Preloader.ProgressNotification(0.4));
createAssets();
createPapers();
notifyPreloader(new Preloader.ProgressNotification(0.5));
createLoans();
createFuneral();
notifyPreloader(new Preloader.ProgressNotification(0.6));
createWills();
addAllPages();
notifyPreloader(new Preloader.ProgressNotification(0.7));
/*Add Toolbar on top*/
createToolBar();
notifyPreloader(new Preloader.ProgressNotification(0.9));
/*Create Opening Instructions*/
opening();
/*Load Saved Data*/
load();
notifyPreloader(new Preloader.ProgressNotification(1.0));
}
#Override
public void start(Stage stage) {
/*Scene*/
scene = new Scene(root, 1200, 700);
stage.setScene(scene);
scene.setFill(null);
/*Stage*/
this.stage = stage;
stage.initStyle(StageStyle.TRANSPARENT);
stage.centerOnScreen();
stage.show();
}
This example will work with installers exe/msi/image only (have no Mac to test dmg). This step by step assumes, that you already installed the needed tools like InnoSetup, Wix Toolset, etc. It also assumes, that you have configured the tools to run with netbeans (setting paths, edit config files, etc.).
Prerequirements:
Inno Setup for .exe package, download the unicode version: http://www.jrsoftware.org/isdl.php
Wix Toolset for .msi package: http://wixtoolset.org/
Set Windows Paths for Inno Setup and Wix Toolset
Step 1:
I've made a new JavaFX Application Project in Netbeans like this:
Step 2:
Then I gave the project a name and said, that the wizard should create a preloader project with the given name too. Additionally it should create an application class in given package name.
Step 3:
After that I right clicked on the application project and select under deployment "Enable Native Packaging".
Step 4:
In step 4 I've created the code for the application. The preloader will be updated in the init() method and only there. All your work for initialization the application should go here.
JavaFXPreloaderApp.java
import javafx.application.Application;
import javafx.application.Preloader;
import javafx.event.ActionEvent;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class JavaFXPreloaderApp extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(createContent(), 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public Parent createContent() {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
System.out.println("Hello World!");
});
StackPane root = new StackPane();
root.getChildren().add(btn);
return root;
}
#Override
public void init() throws Exception {
// A time consuming task simulation
final int max = 10;
for (int i = 1; i <= max; i++) {
notifyPreloader(new Preloader.ProgressNotification(((double) i) / max));
Thread.sleep(500);
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Step 5:
The only missing part was the preloader code. Look for the only needed method handleApplicationNotification, all the other methods, like handleProgressNotification or handleStateChangeNotification, you can safely delete, or make them empty stubs.
JavaFXPreloader.java
import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
/**
* Simple Preloader Using the ProgressBar Control
*/
public class JavaFXPreloader extends Preloader {
ProgressBar bar;
Stage stage;
private Scene createPreloaderScene() {
bar = new ProgressBar();
BorderPane p = new BorderPane();
p.setCenter(bar);
return new Scene(p, 300, 150);
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setScene(createPreloaderScene());
stage.show();
}
#Override
public void handleApplicationNotification(PreloaderNotification info) {
// Check if info is ProgressNotification
if (info instanceof ProgressNotification) {
// if yes, get the info and cast it
ProgressNotification pn = (ProgressNotification) info;
// update progress
bar.setProgress(pn.getProgress());
// if this was the last progress (progress reached 1), hide preloader
// this is really important, if preloader isn't hide until app loader
// reaches the start method of application and tries to open the stage of
// the main app with the show() method, it will not work.
if (pn.getProgress() == 1.0) {
stage.hide();
}
}
}
}
Step 6:
Now it was time to bundle the application to native packages (image only/exe/msi). I right clicked on the applicaton project and selected the packages to create one by one.
Step 7:
After choosen to package as image only your directory should look like this:
Step 8:
After digging deeper in your directory you should find the image:
Step 9:
A double click on the .exe file should start your application:
Remarks:
The biggest mistake you could do is, to call things in your application start methods. Normaly all have to be done in the application init method, there you load the huge files, there you will connect to the db, or there you load a huge custom layout with a lot of css or fxml files. And there is the place to say good bye to the preloader (progress = 1). Try not to do things at the preloader in your application start method. Don't think in Thread's, the preloader is there to do things before the main stage is shown, so load all in sequence.

registering mouse handler but handler not inline, in javafx

I have an app in JavaFX that is getting a bit large, and I want to keep the code readable.
I have a LineChart that I want to have zoom functionality built in, that occurs on a mouseclick. I know I need to register a mouse listener to the chart. What I cannot figure out from Oracle examples, ie as written here:
http://docs.oracle.com/javafx/2/events/handlers.htm
is how to NOT have my handler defined inline to the registering. In other words, I want the body of the handler (which is many lines of code) to be in another class. Can I do that? And if so, how do I register the handler to my chart in my main Javafx controller code?
Place your handler in a new class which implements the the Mouse EventHandler and register an instance of your class with your target node via the node's setOnClicked method.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
* JavaFX sample for registering a click handler defined in a separate class.
* http://stackoverflow.com/questions/12326180/registering-mouse-handler-but-handler-not-inline-in-javafx
*/
public class ClickHandlerSample extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(final Stage stage) throws Exception {
stage.setTitle("Left click to zoom in, right click to zoom out");
ImageView imageView = new ImageView("http://upload.wikimedia.org/wikipedia/commons/b/b7/Idylls_of_the_King_3.jpg");
imageView.setPreserveRatio(true);
imageView.setFitWidth(150);
imageView.setOnMouseClicked(new ClickToZoomHandler());
final StackPane layout = new StackPane();
layout.getChildren().addAll(imageView);
layout.setStyle("-fx-background-color: cornsilk;");
stage.setScene(new Scene(layout, 400, 500));
stage.show();
}
private static class ClickToZoomHandler implements EventHandler<MouseEvent> {
#Override public void handle(final MouseEvent event) {
if (event.getSource() instanceof Node) {
final Node n = (Node) event.getSource();
switch (event.getButton()) {
case PRIMARY:
n.setScaleX(n.getScaleX()*1.1);
n.setScaleY(n.getScaleY()*1.1);
break;
case SECONDARY:
n.setScaleX(n.getScaleX()/1.1);
n.setScaleY(n.getScaleY()/1.1);
break;
}
}
}
}
}

Categories

Resources