Issue
I try to set the size of a pane with a value that is inside a variable of the controller but i always get a: java.lang.IllegalAccessException: class javafx.fxml.FXMLLoader$ValueElement (in module javafx.fxml) cannot access a member of class blub.Blub with modifiers "private"
EDIT:
I tried to make a minimal reproducible example and made some changes according to your comments. still the same IllegalAccessException
startFXMain.java
public class startFXMain extends Application {
private static MRE myApp;
public static void main(String[] args) {
try {
myApp = MRE.getInstance(args);
Application.launch(args);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void start(Stage primaryStage) throws Exception {
myApp.start(primaryStage);
}
}
MRE.java
public class MRE extends Application {
private static MRE instance = null;
@Override
public void start(Stage startStage) throws Exception {
try {
new MREGUI(startStage);
} catch (Exception e) {
e.printStackTrace();
}
}
public static MRE getInstance(String[] args) {
if (Objects.nonNull(instance))
return instance;
else synchronized (MRE.class) {
if (Objects.isNull(instance))
instance = new MRE();
return instance;
}
}
public static MRE getInstance() { return instance; }
private MRE() {
}
}
MREGUI.java
public class MREGUI extends Application {
private GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice();
public int iScreenWidth = gd.getDisplayMode().getWidth();
public int iScreenHeight = gd.getDisplayMode().getHeight();
private Scene scMainScene;
private Pane pMainPane;
@Override
public void start(Stage stgMainStage) throws Exception {
this.initStage(stgMainStage);
this.initStartPane();
this.initStartScene(this.pMainPane);
stgMainStage.setScene(this.scMainScene);
stgMainStage.show();
}
private void initStage(Stage s) {
s.setX(0);
s.setY(0);
s.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent e) {
Platform.exit();
System.exit(0);
}
});
}
private void initStartPane() {
FXMLLoader loader = new FXMLLoader();
try {
URL xmlUrl = new File(System.getProperty("user.dir") + "\\src\\startwindow.fxml").toURI().toURL();
loader.setLocation(xmlUrl);
pMainPane = loader.load();
loader.setController(this);
} catch (MalformedURLException err) {
err.printStackTrace();
} catch (IOException err) {
err.printStackTrace();
}
}
private void initStartScene(Pane rootPane) {
scMainScene = new Scene(rootPane, iScreenHeight, iScreenWidth);
}
public MREGUI(Stage stgMainStage) {
try {
this.start(stgMainStage);
} catch (Exception err) {
err.printStackTrace();
}
}
private MREGUI() {
}
@FXML
public int getIScreenWidth() { return this.iScreenWidth; }
@FXML
public int getIScreenHeight() { return this.iScreenHeight; }
}
startwindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<Pane layoutX="0" layoutY="0" minHeight="640" minWidth="480" prefHeight="${iScreenHeight}" prefWidth="${iScreenWidth}"
xmlns:fx="http://javafx.com/fxml" fx:controller="MREGUI">
<style>
-fx-background-color: blue;
</style>
</Pane>
Solution
The problem is that your no-arg constructor in MREGUI
is private, so the FXMLLoader
cannot construct an instance of the controller class.
Here is a working version with the code considerably cleaned up, and not relying on AWT classes, etc. This is still probably completely the wrong approach (why not just look up the screen size when you create the scene, and set the scene size as required?).
public class StartFXMain {
public static void main(String[] args) {
Application.launch(MRE.class, args);
}
}
public class MRE extends Application {
@Override
public void start(Stage startStage) throws Exception {
try {
new MREGUI(startStage);
} catch (Exception e) {
e.printStackTrace();
}
}
public MRE() {
}
}
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Screen;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
public class MREGUI {
private Screen screen = Screen.getPrimary();
private double screenWidth = screen.getVisualBounds().getWidth();
private double screenHeight = screen.getVisualBounds().getHeight();
private Scene mainScene;
private Pane mainPane;
public void start(Stage stgMainStage) throws Exception {
this.initStage(stgMainStage);
this.initStartPane();
this.initStartScene(this.mainPane);
stgMainStage.setScene(this.mainScene);
stgMainStage.show();
}
private void initStage(Stage s) {
s.setX(0);
s.setY(0);
}
private void initStartPane() {
FXMLLoader loader = new FXMLLoader();
try {
URL xmlUrl = getClass().getResource("startwindow.fxml");
loader.setLocation(xmlUrl);
mainPane = loader.load();
// this has no effect after loading the FMXL:
// loader.setController(this);
} catch (IOException err) {
err.printStackTrace();
}
}
private void initStartScene(Pane rootPane) {
mainScene = new Scene(rootPane, screenHeight, screenWidth);
}
public MREGUI(Stage stgMainStage) {
try {
this.start(stgMainStage);
} catch (Exception err) {
err.printStackTrace();
}
}
public MREGUI() {
}
public double getScreenWidth() { return this.screenWidth; }
public double getScreenHeight() { return this.screenHeight; }
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<Pane layoutX="0" layoutY="0" minHeight="640" minWidth="480" prefHeight="${screenHeight}" prefWidth="${screenWidth}"
xmlns:fx="http://javafx.com/fxml" fx:controller="org.jamesd.examples.sizing.MREGUI">
<style>
-fx-background-color: blue;
</style>
</Pane>
If you need the controller to be the previously-constructed instance of the class, you have to set the controller prior to loading the FXML:
public class MREGUI {
// ...
private void initStartPane() {
FXMLLoader loader = new FXMLLoader();
try {
URL xmlUrl = getClass().getResource("startwindow.fxml");
loader.setLocation(xmlUrl);
loader.setController(this);
mainPane = loader.load();
} catch (IOException err) {
err.printStackTrace();
}
}
// ...
public MREGUI(Stage stgMainStage) {
try {
this.start(stgMainStage);
} catch (Exception err) {
err.printStackTrace();
}
}
// public MREGUI () {
//
// }
// ...
}
In order for this to work, you must remove the fx:controller
attribute from the root element of the FXML. This attribute instructs the FXMLLoader
to create an instance of the controller class by calling the no-argument constructor, which is incompatible with setting the controller in code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<Pane layoutX="0" layoutY="0" minHeight="640" minWidth="480" prefHeight="${screenHeight}" prefWidth="${screenWidth}"
xmlns:fx="http://javafx.com/fxml" >
<style>
-fx-background-color: blue;
</style>
</Pane>
Answered By - James_D
Answer Checked By - Gilberto Lyons (JavaFixing Admin)