I am familiarizing with JavaFX. I have created a loginStage and a mainStage. When pressing the 'Login' Button on the loginStage, I want to switch to the mainStage. The loginStage is a lot smaller than the mainStage. I want the mainStage to be located such that the former loginStage was positioned right in the middle of the mainStage (if we hadn't closed it).
I managed to switch from the loginStage to the mainStage. But for some reason the mainStage does not position itself correctly; it seems to me that its X- and Y-coordinate are not set at all!
Here is my code:
public void switchWindow() {
FXMLLoader loader = new FXMLLoader();
try {
Stage loginStage = (Stage) btnLogin.getScene().getWindow();
loginStage.setScene(null);
loginStage.hide();
Pane mainPane= (Pane) loader.load(getClass().getResource("/mainStage.fxml"));
Stage mainStage= new Stage();
mainStage.initStyle(StageStyle.TRANSPARENT);
Scene mainScene= new Scene(mainPane);
mainStage.setScene(mainScene);
mainStage.setX(loginStage.getX() + loginStage.getWidth()/2 - mainStage.getWidth()/2);
mainStage.setY(loginStage.getY() + loginStage.getHeight()/2 - mainStage.getHeight()/2);
mainStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Also: I will be creating more stages. Hence, I figured it might be a good idea to create a switchWindow() function inside a separate package. I might just call the function with parameters oldStage and newPane. I wanted to ask you: What is the best practice of switching between stages? So that I do not reproduce the same code over and over again?
I figured it out - and yes, I am sorry, this seems to have been answered before.
The problem is that .getWidth() or .getHeight() methods can only be invoked AFTER the .show() method. Therefore, either change the order of calling the functions. This works fine - the mainStage seems to be at the correct x,y-coordinates from begin on. But to be sure that it does not get moved there after showing the stage, we could also just look up the width and the height of the mainStage inside the .fxml file and then substract these values in .setX() and .setY() respectively.
Hey guys I have "bug" if you can call it so.
When starting the program, one element is always blue.
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("resource/Start.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Alc Calc V1.1");
stage.show();
}
=>
The reason that shows up as blue is it is the active element. JavaFX allows you to use CSS to style your program and if you do not put in your own it will use the default. In the default it has the fx-focus-color attribute set to adding that blue that you're referring to.
You can just get rid of the effect on all controls by changing the attribute itself in the code.
control.setStyle("-fx-focus-color: transparent;");
If you plan on changing more than just a thing or two I would recommend making your own CSS file and using that. You can attach it with this:
scene.getStylesheets().add("your_custom_css_file.css");
Then to set this attribute within your CSS file you would want to add this attribute:
.root { -fx-focus-color: transparent; }
I'm currently writing an HexEditor Application with JavaFX 8 for various reasons. (Important is, that I have to do this I can't just use another HexEditor)
My problem is that when I want to update my UI for example with
textarea.setText(line);
table.setItems(getListForTable());
I get a NullPointerException because textarea(TextArea) and table (TableView) are null, but if I have data before I intialize my stage and set that to the components it works.
In other questions I read that Platfrom.runLater() should solve that but somehow it doesn`t work for me, I still get the NullPointerException. Also I'm sure I'm in the applications main thread, because my application only uses one thread.
Here is the full code from the method:
public void openFile() //this is called when the user presses the "Open"-MenuItem
{
FileChooser fc = new FileChooser();
fc.getExtensionFilters().addAll(
new ExtensionFilter("Text Files", "*.txt"),
new ExtensionFilter("All Files", "*.*"));
file = fc.showOpenDialog(primaryStage);
if(file != null)
{
create();
Platform.runLater(() -> textarea.setText(line)); //NPE
}
}
Also I tried using a button to update the UI but that works only if the user presses the button and also not with the Button.fire() Method, but thats not a good workaround if you have to press that button everytime you did something to see the changes.
EDIT: here are the methods initializing the code in the start() Method. And as I said: I`m sure there getting assigned correctly, because I can use them for setting up listeners and such while starting the program.
private TextArea textarea;
private TableView<Row> table; //Row is my own class used to get the contents to the table
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
initRootLayout();
showContentScene();
}
private void initRootLayout() { //initializes root layout as frame for Content
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Editor.class.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
private void showContentScene() { //initializes Content View
try {
// Load Content (panel).
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Editor.class.getResource("Content.fxml"));
ContentPane = (AnchorPane) loader.load();
table = (TableView<Row>) loader.getNamespace().get("table");
textarea = (TextArea) loader.getNamespace().get("textarea");
// Set Content into the center of root layout.
rootLayout.setCenter(ContentPane);
} catch (IOException e) {
e.printStackTrace();
}
}
EDIT: I overworked the code structure but now I have another exception from the loader telling me "Root cannot be null".
EDIT: For everyone viewing this: It was mostly a structure problem, make sure that every .fxml-file you use has its own Controller.
Your structure is very unusual. Usually you either construct nodes in your code and don't use and FXMLLoader OR you let the FXMLLoader construct nodes for you. In your case you are doing both, which can work, but is tricky to get right (as you have discovered).
So, given you are using FXML, just use it for constructing all of your nodes and place references to the constructed nodes in a controller, with the references annotated with #FXML so that the FXMLLoader initializes them. Then, never assign the references to new nodes you create.
Ensure that the references and controller are in different classes from your Application class, because you never really want to make the main application class a controller, all the main application class should do is invoke the FXMLLoader, it does not need any node references.
You never need to use Platform.runLater unless you are running on a non-JavaFX application thread and you want to execute some code on the JavaFX application thread. For your example this is clearly not the case, because the comment for openFile is this is called when the user presses the "Open"-MenuItem. The JavaFX framework handles the input event for the user pressing the open menu item and ensures that an event handler for it is invoked on the JavaFX application thread, so trying to use Platform.runLater in such a situation is both confusing and redundant.
Even if you address some of the issues mentioned in this answer, your program may still not work as you expect as it may have other issues, which cannot be verified with the current code in your question. For instance, the question code includes neither FXML or controller code. Those would be required to truly find all the issues with code and address this.
I have two good working windows (main window, first window) in seperate .java files, at the same package.
The program handles, if I call the the First window (from the main), the Main stays in the background. The only problem is that I still can use the main window if I click there, and create infinity first windows.
One solution is to shut down the Main window, to avoid clicking there again, but I would like to keep there. In order to make the solution I need a code which makes the background window somehow disabled until I click something in the First Window.
But to do that I need to give the rights to the "handler.java" to operate with the main.
Anybody has any idea how to do that?
Let me show you the 2 java file's methods:
Main.java:
public class program extends Application {
#Override
public void start(Stage main) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("mainwindow.fxml"));
Scene scene = new Scene(root);
main.setScene(scene);
main.setTitle("Main);
main.setWidth(800);
main.setHeight(600);
main.setResizable(false);
main.show();
First.java
public void first() throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("first.fxml"));
Scene scene = new Scene(root);
Stage first = new Stage();
first.setScene (scene);
first.setTitle("Köszöntjük az Útiokosban!");
first.setWidth(400);
first.setHeight(200);
first.setResizable(false);
first.show();
}
Use Stage.initModality to make one of your Stages modal (blocking).
Note: You need to set the modality before displaying the Stage.
Try using the advisory in the chapter "Modality" in this link:
http://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html
Is it possible to change the application icon using JavaFX, or does it have to be done using Swing?
Assuming your stage is "stage" and the file is on the filesystem:
stage.getIcons().add(new Image("file:icon.png"));
As per the comment below, if it's wrapped in a containing jar you'll need to use the following approach instead:
stage.getIcons().add(new Image(<yourclassname>.class.getResourceAsStream("icon.png")));
Full program for starters :) This program sets icon for StackOverflowIcon.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class StackoverflowIcon extends Application {
#Override
public void start(Stage stage) {
StackPane root = new StackPane();
// set icon
stage.getIcons().add(new Image("/path/to/stackoverflow.jpg"));
stage.setTitle("Wow!! Stackoverflow Icon");
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Output Screnshot
Updated for JavaFX 8
No need to change the code. It still works fine. Tested and verified in Java 1.8(1.8.0_45). Path can be set to local or remote both are supported.
stage.getIcons().add(new Image("/path/to/javaicon.png"));
OR
stage.getIcons().add(new Image("https://example.com/javaicon.png"));
Hope it helps. Thanks!!
I tried this and it totally works. The code is:
stage.getIcons().add(
new Image(
<yourclassname>.class.getResourceAsStream( "icon.png" )));
icon.png is under the same folder as the source files.
If you have have a images folder and the icon is saved in that use this
stage.getIcons().add(new Image(<yourclassname>.class.getResourceAsStream("/images/comparison.png")));
and if you are directly using it from your package which is not a good practice use this
stage.getIcons().add(new Image(<yourclassname>.class.getResourceAsStream("comparison.png")));
and if you have a folder structure and you have your icon inside that use
stage.getIcons().add(new Image(<yourclassname>.class.getResourceAsStream("../images/comparison.png")));
you can add it in fxml. Stage level
<icons>
<Image url="#../../../my_icon.png"/>
</icons>
stage.getIcons().add(new Image(<yourclassname>.class.getResourceAsStream("/icon.png")));
If your icon.png is in resources dir and remember to put a '/' before otherwise it will not work
What do you think about creating new package i.e image.icons in your src directory and moving there you .png images? Than you just need to write:
Image image = new Image("/image/icons/nameOfImage.png");
primaryStage.getIcons().add(image);
This solution works for me perfectly, but still I'm not sure if it's correct (beginner here).
stage.getIcons().add(new Image(ClassLoader.getSystemResourceAsStream("images/icon.png")));
images folder need to be in Resource folder.
stage.getIcons().add(new Image(<yourclassname>.class.getResourceAsStream("/icon.png" )));
You can add more than one icon with different sizes using this method.The images should be different sizes of the same image and the best size will be chosen.
eg. 16x16, 32,32
You can easily put icon to your application using this code line
stage.getIcons().add(new Image("image path") );
stage.getIcons().add(new Image("/images/logo_only.png"));
It is good habit to make images folder in your src folder and get images from it.
I used this in my application
Image icon = new Image(getClass().getResourceAsStream("icon.png"));
window.getIcons().add(icon);
Here window is the stage.
If you run the jar file, the code specified by Michael Berry will change the icon in the title bar and in the taskbar. Shortcut icon cannot be changed.
If you run a native program compiled with com.zenjava, You must add a link to the program icon:
<plugin>
<groupId>com.zenjava</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>8.8.3</version>
<configuration>
...
<bundleArguments>
<icon>${project.basedir}/src/main/resources/images/filename.ico</icon>
</bundleArguments>
</configuration>
</plugin>
This will add an icon to the shortcut and taskbar.
Toggle icons in runtime:
In addition to the responses here, I found that once you have assigned an Icon to your application by the first time you cannot toggle it by just adding a new icon to your stage (this would be helpful if you need to toggle the icon of your app from on/off enabled/disabled).
To set a new icon during run time use the getIcons().remove(0) before trying to add a new icon, where 0 is the index of the icon you want to override like is shown here:
//Setting icon by first time (You can do this on your start method).
stage.getIcons().add(new Image(getClass().getResourceAsStream("enabled.png")));
//Overriding app icon with a new status (This can be in another method)
stage.getIcons().remove(0);
stage.getIcons().add(new Image(getClass().getResourceAsStream("disabled.png")));
To access the stage from other methods or classes you can create a new static field for stage in you main class so can access it from out of the start() method by encapsulating in on a static method that you can access from anywhere in your app.
public class MainApp extends Application {
private static Stage stage;
public static Stage getStage() { return stage; }
#Override public void start(Stage primaryStage) {
stage = primaryStage
stage.getIcons().add(new Image(getClass().getResourceAsStream("enabled.png")));
}
}
public class AnotherClass {
public void setStageTitle(String newTitle) {
MainApp.getStage().setTitle(newTitle);
MainApp.getStage().getIcons().remove(0);
MainApp.getStage().getIcons().add(new Image(getClass().getResourceAsStream("disabled.png")));
}
}
If you got Invalid URL or resource not found put your icon.png in the "bin" folder in your workspace.
Another easy way to insert your own icon on the title bar in JavaFX is to add the image to your primary stage using the following method:
Image ico = new Image("resources/images/iconLogo.png");
stage.getIcons().add(ico);
Make sure your import javafx.scene.image.Image (if using an ide like netbeans this should be automatically done for you).
I tried this and it works:
stage.getIcons().add(new Image(getClass().getResourceAsStream("../images/icon.png")));