I am trying to create a JavaFX app for multiple screen resolutions (also high resolutions).
I want to use variables/calculations in my FXML file (JavaFX project).
This works when I only do the calculations in prefWidth, prefHeight etc only. When trying to do a calculation in (for example) a AnchorPane.topAnchor it gives me the following error.
-- exec-maven-plugin:1.2.1:exec (default-cli) # SecureChat ---
dec 04, 2014 10:13:50 AM securechat.helpers.CustomStage initialize
SEVERE: null
javafx.fxml.LoadException: Cannot bind to static property.
file:/D:/private_java/SecureChat/target/SecureChat-1.0-SNAPSHOT.jar!/fxml/main.fxml:24
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2591)
at javafx.fxml.FXMLLoader.access$100(FXMLLoader.java:104)
at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:291)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:771)
at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2817)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2526)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
at securechat.helpers.CustomStage.initialize(CustomStage.java:111)
at securechat.helpers.CustomStage.<init>(CustomStage.java:104)
at securechat.MainApp.start(MainApp.java:40)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$51/967161415.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$45/584634336.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1040960283.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/501263526.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$37/96639997.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:363)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:303)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(LauncherImpl.java:157)
at com.sun.javafx.application.LauncherImpl$$Lambda$48/815033865.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Root cannot be null
at javafx.scene.Scene.<init>(Scene.java:313)
at javafx.scene.Scene.<init>(Scene.java:181)
at securechat.helpers.CustomStage.initialize(CustomStage.java:120)
at securechat.helpers.CustomStage.<init>(CustomStage.java:104)
at securechat.MainApp.start(MainApp.java:40)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$51/967161415.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$45/584634336.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1040960283.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/501263526.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$37/96639997.run(Unknown Source)
... 1 more
Exception running application securechat.MainApp
------------------------------------------------------------------------
BUILD FAILURE
------------------------------------------------------------------------
Total time: 9.363s
Finished at: Thu Dec 04 10:13:51 CET 2014
Final Memory: 19M/265M
------------------------------------------------------------------------
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:exec (default-cli) on project SecureChat: Command execution failed. Process exited with an error: 1 (Exit value: 1) -> [Help 1]
To see the full stack trace of the errors, re-run Maven with the -e switch.
Re-run Maven using the -X switch to enable full debug logging.
For more information about the errors and possible solutions, please read the following articles:
[Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
When I remove the AnchorPane.leftAnchor="${dpi.value*200}" (in the last AnchorPane) in Main.fxml it does work.
I am using the following code snippets.
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import securechat.helpers.Scaling?>
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="securechat.controllers.MainController">
<children>
<fx:define>
<Scaling fx:id="dpi"></Scaling>
</fx:define>
<AnchorPane fx:id="chatsAnchorPane" maxWidth="${dpi.value*200}" minWidth="${dpi.value*200}" prefWidth="${dpi.value*200}" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Button fx:id="openNewChatWindowButton" onAction="#openNewChatDialog" text="%button.openNewChatDialog" prefHeight="${dpi.value*40}" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<ListView fx:id="chatsListView" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="40.0" />
</children>
</AnchorPane>
<AnchorPane fx:id="chatAnchorPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="${dpi.value*200}" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ListView fx:id="chatMessagesListView" AnchorPane.bottomAnchor="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<TextField fx:id="chatMessageTextField" onAction="#sendChatMessage" promptText="%textfield.chatMessagePrompt" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" prefHeight="${dpi.value*40}" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
</children>
</AnchorPane>
</children>
</AnchorPane>
Scaling.java
package securechat.helpers;
import java.awt.GraphicsEnvironment;
/**
*
*/
public final class Scaling {
public double value;
public Scaling() {
value = getDefaultScaling();
}
private double getDefaultScaling() {
int width = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().width;
return width / 1920;
}
public double getValue() {
return value;
}
}
After some debugging, I've found that in the FXMLLoader class there are several LinkedList<Attribute> lists. One if for instance property attributes, like prefHeight="400.0", and one is for static property attributes, like AnchorPane.bottomAnchor="0.0".
If you use a regular value like prefHeight="400.0" or a binding expression, like prefWidth="${dpi.value*200}", these cases will be processed in this method processPropertyAttribute().
For bindings, there are three preliminary checks:
#SuppressWarnings("unchecked")
public void processPropertyAttribute(Attribute attribute) throws IOException {
String value = attribute.value;
if (isBindingExpression(value)) {
// Resolve the expression
Expression expression;
if (attribute.sourceType != null) {
throw constructLoadException("Cannot bind to static property.");
}
if (!isTyped()) {
throw constructLoadException("Cannot bind to untyped object.");
}
if (this.value instanceof Builder) {
throw constructLoadException("Cannot bind to builder property.");
}
// Evaluate the expression
...
} else {
processValue(attribute.sourceType, attribute.name, value);
}
While prefWidth="${dpi.value*200}" passes these checks, on the contrary, on AnchorPane.leftAnchor="${dpi.value*200}" you will find that it has a sourceType:
attribute.sourceType = (java.lang.Class) class javafx.scene.layout.AnchorPane
so by design this will happen:
if (attribute.sourceType != null) {
throw constructLoadException("Cannot bind to static property.");
}
Also it is not possible bidirectional binding:
if (isBidirectionalBindingExpression(value)) {
throw constructLoadException(new UnsupportedOperationException("This feature is not currently enabled."));
}
If you look at the docs:
Attributes representing static properties are handled similarly to static property elements and use a similar syntax.
In addition to being more concise, static property attributes, like instance property attributes, support location, resource, and variable resolution operators, the only limitation being that it is not possible to create an expression binding to a static property.
You will need to find another way...
EDIT
Based on the FXML provided, my suggestion for a way to avoid static properties will be using HBox and VBox, with the desired min/pref/max sizes via bindings, wrapping the controls.
Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import securechat.helpers.Scaling?>
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="securechat.controllers.MainController">
<children>
<fx:define>
<Scaling fx:id="dpi"></Scaling>
</fx:define>
<HBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<VBox fx:id="chatsVBox" maxWidth="${dpi.value*200}" minWidth="${dpi.value*200}" prefWidth="${dpi.value*200}" HBox.hgrow="NEVER">
<children>
<Button fx:id="openNewChatWindowButton" onAction="#openNewChatDialog" text="%button.openNewChatDialog" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" prefHeight="${dpi.value*40}" prefWidth="${dpi.value*200}" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" VBox.vgrow="NEVER" />
<ListView fx:id="chatsListView" VBox.vgrow="ALWAYS" />
</children>
</VBox>
<VBox fx:id="chatVBox" HBox.hgrow="ALWAYS">
<children>
<ListView fx:id="chatMessagesListView" VBox.vgrow="ALWAYS" />
<TextField fx:id="chatMessageTextField" onAction="#sendChatMessage" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" prefHeight="${dpi.value*40}" promptText="%textfield.chatMessagePrompt" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" VBox.vgrow="NEVER" />
</children>
</VBox>
</children>
</HBox>
</children>
</AnchorPane>
The main info as you point it is that it is not possible to use an expression in a static attribute and never will BUT you can use a variable.
An expression is written with ${} and must be bound to a property, a "variable" is written with only $var and is accessed through a getter.
I ended with this horrible workaround : AnchorPane.leftAnchor="$dpi.value200"
And implements as many methods as you need in Scaling class:
public final class Scaling {
public double value;
public Scaling() {
value = getDefaultScaling();
}
private double getDefaultScaling() {
int width = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().width;
return width / 1920;
}
public double getValue() {
return value;
}
public double getValue100() {
return value*100;
}
public double getValue200() {
return value*200;
}
public double getValue300() {
return value*300;
}
/* etc.*/
}
Additionnaly, there is a kind of bug in a variable analysis, don't call it "200Value" (or "200dp" as i did). it will stop evaluation if the variable begins with numeric characters.
Related
I want my table to change the color of a row depending on a column is checked or not or when a button is clicked.
I searched for solutions but it never worked the way I wanted to. I am happy for every keyword or help you have. Maybe I was just looking for the wrong thing?
My code looks like this:
public class Cellexample_presenter implements Initializable{
#FXML
TableColumn<ExampleData, Boolean> checkcol;
#FXML
TableView<ExampleData> testtable;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
checkcol.setText("Check");
ObservableList<ExampleData> exList = FXCollections.observableArrayList();
exList.add(new ExampleData(true));
exList.add(new ExampleData(false));
checkcol.setCellValueFactory(
new Callback<CellDataFeatures<ExampleData, Boolean>, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(CellDataFeatures<ExampleData, Boolean> param) {
return param.getValue().checkProperty();
}
});
testtable.setItems(exList);
testtable.setEditable(true);
checkcol.setCellFactory(CheckBoxTableCell.forTableColumn(checkcol));
}
#FXML
private void clicked() {
ObservableList<ExampleData> tabledata = testtable.getItems();
for (ExampleData e : tabledata) {
System.out.println(e.isCheck());
}
}
}
I found solutions with another setCellFactory, but I doesn't seem to work when I already have a setCellFactory and I was unable to combine then. Moreover there is still the connection missing to the
change of the Checkbox.
Another solution I came across was something with a PseudoClass but this also required another setCellFactory
The method private void clicked() I used to check if the data in my object was really changed.
Also I want as another Feature to click a Button and change the color of rows with wrong data.
I was hoping there was a way to iterate trough the table, check the data and if something doesn't equals something else. It changes color.
Like this in pseudo-code
for (tablerow row: table)
if (row.ischecked()) {
row.changecolor();
}
Here is the .FXML for putting everything together:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<AnchorPane prefHeight="254.0" prefWidth="700.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="pathToFXML/Cellexample_presenter">
<children>
<Pane layoutX="-269.0" prefHeight="315.0" prefWidth="700.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TableView fx:id="testtable" layoutX="142.0" layoutY="27.0" prefHeight="200.0"
prefWidth="340.0">
<columns>
<TableColumn fx:id="checkcol" prefWidth="75.0" text="C1" />
</columns>
</TableView>
<Button fx:id="checkbtn" layoutX="70.0" layoutY="36.0" mnemonicParsing="false"
onAction="#clicked" text="isChecked" />
</children>
</Pane>
</children>
</AnchorPane>
You can use a custom TableRow for this. I also prefer to use CSS and PseudoClasses to manage the color of rows.
What needs to happen here is that the row needs to know if the checked property in the ExampleData instance currently displayed by the row changes, and needs to change color if that happens.
Of course, for any given table row, the ExampleData instance displayed by that table row may also change (e.g. if the underlying data list changes, or if the user scrolls the table, etc.)
So the basic strategy here is:
Create a listener that observes the current item's checked property, and updates the pseudoclass state if it does (which in turn causes the style to change). In the code below I call this listener checkListener.
If the item displayed by the row changes, we need to stop observing the old item's checked property and start observing the new item's checked property instead. This can be achieved via a listener on the item property of the table row. That listener on the itemProperty can then remove the checkListener from the checkedProperty of the old item (if there was an old item), and add it to the checkedProperty of the new item (if there is one). It also needs to update the pseudoclass state according to the current state of the new item's checkedProperty.
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// Existing code....
testTable.setRowFactory(tv -> new TableRow<ExampleData>() {
private final PseudoClass checkedPC = PseudoClass.getPseudoClass("checked");
private final ChangeListener<Boolean> checkListener = (obs, wasChecked, isNowChecked) ->
pseudoClassStateChanged(checkedPC, isNowChecked);
{
itemProperty().addListener((obs, oldItem, newItem) -> {
if (oldItem != null) {
oldItem.checkedProperty().removeListener(checkListener);
}
if (newItem == null) {
pseudoClassStateChanged(checkedPC, false);
} else {
pseudoClassStateChanged(checkedPC, newItem.isChecked());
newItem.checkedProperty().addListener(checkListener);
}
});
}
});
}
And then in your external CSS file include
.table-row-cell:checked {
-fx-background-color: red ;
}
I am trying to load the FXML file and show it as an application window, but i get an exception. The FXML file was created by the FXML Scene Builder.
Here are the codes for the class
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(FXMLLoader.load(getClass().getResource("sample.fxml")));
primaryStage.show();
}
}
and FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<TitledPane animated="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
prefHeight="400.0" prefWidth="600.0" text="Pass4D" xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<Button layoutX="211.0" layoutY="134.0" mnemonicParsing="false" prefHeight="33.0" prefWidth="177.0"
text="Log in"/>
<Button layoutX="212.0" layoutY="170.0" mnemonicParsing="false" prefHeight="33.0" prefWidth="175.0"
text="Exit"/>
</children>
</AnchorPane>
</content>
</TitledPane>
And here is the exception i get
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(LauncherImpl.java:157)
at com.sun.javafx.application.LauncherImpl$$Lambda$1/2074407503.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Location is required.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3201)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3169)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3142)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3118)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3098)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3091)
at Pass4D.start(Pass4D.java:19)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$51/317090070.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1833150059.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$49/2115863517.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/1436737924.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
What am i doing wrong?
p.s. here is the project structure
The short answer is getClass().getResource("sample.fxml") returns null silently if the resource cannot be found on the runtime classpath, not the current directory etc.
So this depends on your IDE project setup, if you're using eclipse try adding the folder that sample.fxml resides in the run configuration.
Some ideas...
try getClass().getResource("/sample.fxml") instead...
try moving sample.fxml into the resources folder. I don't know much about your IDE, but I suspect that folder is only used for .java files... this is certainly true for gradle projects in eclipse - resources have to be in the src/main/resources tree as only that is added to the runtime classpath...
I already posted this today, so here's again, hope it helps you.
Here's a solution that works in the development environment, in Scene Builder and in a packaged JAR.
The folder structure:
Main.java:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("view/RootLayout.fxml"));
AnchorPane rootLayout = (AnchorPane) loader.load();
Scene scene = new Scene(rootLayout, 400, 400);
scene.getStylesheets().add(getClass().getResource("css/application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
RootLayout.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.view.RootLayoutController">
<children>
<Pane layoutX="0.0" layoutY="0.0" prefHeight="200.0" prefWidth="200.0">
<children>
<Button fx:id="sunButton" layoutX="74.0" layoutY="88.0" mnemonicParsing="false" onAction="#handleSunButtonClick" styleClass="sun-button" stylesheets="#../css/toolbar.css" text="Button" />
</children>
</Pane>
</children>
</AnchorPane>
RootLayoutController.java:
package application.view;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class RootLayoutController {
#FXML
Button sunButton;
#FXML
public void handleSunButtonClick() {
System.out.println( "Button clicked");
}
}
toolbar.css:
.sun-button {
-fx-graphic: url('./icons/sun.png');
}
application.css:
.root {
-fx-background-color:lightgray;
}
sun.png:
This works in both the development environment and when you package the JAR (choose "Extract required libraries into generated JAR" in Eclipse).
Screenshot (just a button with an icon loaded via css)
Try this example from oracle:
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("fxml_example.fxml"));
Scene scene = new Scene(root, 300, 275);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
}
Main.class.getResource worked for me. I was trying to get resource from subclass instead of Main class. I used there getClass().getResource() which was pointing to the current class. I didn't have my FXML files in resources directory.
Append MainApp.class to getClass().getResource("/fxml/Scene.fxml") . worked for me!
example:
Parent root = FXMLLoader.load(MainApp.class.getClass().getResource("/fxml/Scene.fxml"));
Delete the "build" folder in your javafx project and rebuild your project.
If you are using Maven you may need to move the fxml file to your resources directory.
refactor src/main/java/sample/sample.fxml to src/main/resources/sample/sample.fxml
Here's what to do when using an IntelliJ IDE.
When you are using getClass().getResource(), the resource must be located in the resources folder under a directory in that resource folder that corresponds to the package name of the class you are using:
src/main/java/com/foo/MyClass.java
src/main/java/resources/com/foo/MyResource.fxml
MyClass.class.getResource(MyResource.fxml) will worked
same rule applies for using FXMLLoader.
In the IntelliJ world, if you put that resource into the same folder that the class is located in, that resource won't be found. The irony of that is when look at jar produced, you'll find that the resource is actually placed into the same jar folder as the source is located in. That's because, when debugging only the compiled java classes are moved into the target folder, together with the resources from the resources directory. So what's really happening is just an artifact of how the debug build process works. I know that if you were using Android Studio for instance it works slightly different. You could place the resource in the same folder that the java source file is located, and it would find that resource. I don't know what IDE Roland above was using, but he was using an IDE that allowed him to place the resource the same directory as the java source was located in.
for me, after a lot of trial and error, the only way that worked was to add getClassLoader() like so:
MyClass.class.getClassLoader().getResource("views/myview.fxml")
For a layout of:
src
+main
+resources
+views
+myview.fxml
I can not figure out for the life of me the problem with this code. I have done research on many similar questions here, addressing whether the directories were correct, possible wrong function calls etc.
I am hoping someone can help me out. Everything is in a file called login in an app called loginapp.
Here is Login.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package login;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Login extends Application {
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Login.fxml"));
Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("Login.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Fracken");
stage.show();
}
}
Here is Login.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="317.0" prefWidth="326.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="login.Login">
<children>
<TextField fx:id="txtUsername" layoutX="110.0" layoutY="45.0" promptText="Username" />
<PasswordField fx:id="txtPassword" layoutX="110.0" layoutY="115.0" promptText="Password" />
<Button fx:id="btnLogin" layoutX="110.0" layoutY="184.0" mnemonicParsing="false" onAction="btnLoginAction" text="Login" />
<Button fx:id="btnReset" layoutX="232.0" layoutY="184.0" mnemonicParsing="false" onAction="btnResetAction" text="Reset" />
<Label fx:id="lblMessage" layoutX="110.0" layoutY="236.0" prefHeight="31.0" prefWidth="187.0" />
</children>
</AnchorPane>
I am sure the issue is with
Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("Login.fxml"));
I get this error.
Executing C:\Users\David\Desktop\Java Project\loginapp\dist\run122343396\loginapp.jar using platform C:\Program Files\Java\jdk1.8.0_111\jre/bin/java
Exception in Application start method
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Location is required.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3207)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at login.Login.start(Login.java:23)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
... 1 more
Java Result: 1
Please help me, I have looked at other's similar issues on here but no solutions worked.
getClass().getResource("Login.fxml") should return a non-null value, since using Class.getResource looks up the resouce relative to the class. Since you seem to have placed the resource in the login package, using a class in that package with resource name Login.fxml should work.
For some reason you do not use the FXMLLoader that you pass this resource URL to. Instead you use
getClass().getClassLoader().getResource("Login.fxml")
I.e. you use the classloader to load the file. The classloader however does not know about the class you retrieve it from and therefore tries to locate Login.fxml in the default package.
If you use a classloader, you should use the full path, i.e.
getClass().getClassLoader().getResource("login/Login.fxml")
My fxml file wasn't at the same folder that main (neither on the same package). The only way that I got is using: getClass().getResource("/fxml/inicial.fxml");
You schould delate: fx:controller="login.Login"
form Login.fxml
just add user libraries. javafx from java-jre-lib-javafx.
Before marking my question as DUPLICATE or REPEATED, PS that I have tried everything :
1. They said HERE, and HERE, and finally HERE. Nothing worked.
2. I self signed my application, and provided the link in exception list of Java Control Panel. Lowered the security level from Very High to High. Still the same results.
3. Later, I also generated a keytool store and entered the command for .csr and .jks file, provided their path as well as alias name in NetBeans, and failed again.
4. Provided "all-permissions" command in manifest file and got same results.
5. Tried Running JNLP file as a standalone webstart application, but got blocked due to Java Security Reasons.(don't know why ! )
I am pasting my code below :
This is my FXML File :
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxwillrunthistime.FXMLDocumentController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children> </AnchorPane>
Following is my Main File :
public class JavaFXWillRunThisTime extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
This is the exception:
Missing Application-Name manifest attribute for: file:/G:/WorkSpaces/NetBeans/JavaFXWillRunThisTime/dist/JavaFXWillRunThisTime.jar
java.lang.NullPointerException: Location is required. at
javafx.fxml.FXMLLoader.loadImpl(Unknown Source) at
javafx.fxml.FXMLLoader.loadImpl(Unknown Source) at
javafx.fxml.FXMLLoader.loadImpl(Unknown Source) at
javafx.fxml.FXMLLoader.loadImpl(Unknown Source) at
javafx.fxml.FXMLLoader.loadImpl(Unknown Source) at
javafx.fxml.FXMLLoader.load(Unknown Source) at
javafxwillrunthistime.JavaFXWillRunThisTime.start(JavaFXWillRunThisTime.java:22)
I have tried running this in all the browsers I have. Read the documentation by Oracle on JavaFX's web depolyment, and also had a look at the browser list it has provided on its site.
It would be a great help, if someone can tell me what to do next ?
(DUPLICATE & SOLVED - see answer below)
I'm doing my first steps in JavaFX and it seems quite hard to use the "SceneBuilder". I'm used to Android and the QtCreator. It looks to me that there is accessing the UI components much easier.
Something like findViewById(R.id.btnPushMe); <- Android Code
Actually I got an solution but it is quite uncomfortable to use. This looks as this:
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("../fmxl/main.fxml"));
AnchorPane pane = loader.load();
System.out.println("panechilds:" + pane.getChildren().size());
BorderPane border = (BorderPane) pane.getChildren().get(0);
System.out.println("borderchilds:" + border.getChildren().size());
the xml..
<AnchorPane fx:id="mAnchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.progui.MainController">
<children>
<BorderPane layoutX="-1.0" prefHeight="600.0" prefWidth="800.0">
<top>
...
Thanks in advance
Martin
Edit:
This is a duplicate question (but I will not delete it, because I took some time to find the answer - maybe because JavaFX wasn't asked as much as Android questions were..)
AnchorPane anchor = (AnchorPane) scene.lookup("#mAnchor");
found here: How to find an element with an ID in JavaFX?
You should use a controller class and access the UI elements there.
Basically you do:
<AnchorPane fx:id="mAnchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.progui.MainController">
<children>
<BorderPane fx:id="border" layoutX="-1.0" prefHeight="600.0" prefWidth="800.0">
<top>
...
And then you can access the fx:id-attributed elements in the controller with
package app.progui ;
// ...
public class MainController {
#FXML
private BorderPane border ;
public void initialize() {
border.setStyle("-fx-background-color: antiquewhite;");
// ...
}
// ...
}
The field names in the controller class must match the fx:id values in the FXML file.
It is possible to access the fx:id-attributed elements in the class that invoked the FXMLLoader, but if you need to do this it is usually a sign that your overall design is wrong. You can do:
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("../fmxl/main.fxml"));
AnchorPane pane = loader.load();
Map<String, Object> fxmlNamespace = loader.getNamespace();
BorderPane border = (BorderPane) fxmlNamespace.get("border");
assuming the fx:id defined in the FXML snipped above.
When you design for FXML, you typically design three things: the application logic, the GUI controller logic, and the FXML.
References to the UI controls you wish to access are injected by the FXML loader into your controller class during its loading and initialization so that you do not need to use a FindById() method.
A controller class looks similar to this:
class DCServRecEditor extends DialogController {
#FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;
#FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;
#FXML // fx:id="ancMatchSelector"
private AnchorPane ancMatchSelector; // Value injected by FXMLLoader
#FXML // fx:id="ancServEditor"
private AnchorPane ancServEditor; // Value injected by FXMLLoader
#FXML // fx:id="ancServRecEditor"
private AnchorPane ancServRecEditor; // Value injected by FXMLLoader
:
:
The FXML loading facility automatically injects references into instance fields that are annotated with the #FXML tag. To manipulate a UI control, just access its methods using the appropriate reference.
Separating the UI control logic from your application logic is highly desirable, and effects a "separation of concerns". When you get used to designing FXML UI's this way, you'll enjoy it.