Switching scenes in JavaFX(FXML) error - javafx

So, I'm trying to switch scenes in JavaFX but I can't seem to get it to work when I hard coded it I was able to get it working by using lambda expressions.
public class Main extends Application {
Stage window;
Scene scene1;
Scene scene2;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
Label label = new Label("Welcome to the first scene");
Button bttn1 = new Button("Go to second scene");
bttn1.setOnAction(e -> window.setScene(scene2));
//Scene 1
VBox layout1 = new VBox(20);
layout1.getChildren().addAll(label, bttn1);
scene1 = new Scene(layout1, 400, 400);
//Scene 2
Button bttn2 = new Button("Go to first scene");
bttn2.setOnAction(e -> window.setScene(scene1));
StackPane layout2 = new StackPane();
layout2.getChildren().add(bttn2);
scene2 = new Scene(layout2, 400, 500);
window.setScene(scene1);
window.setTitle("Test");
window.show();
}
However the project involves a few different GUIs and I would prefer to design the GUI's in FXML Scene Builder than to hardcode them the FX way. However when I have tried to do the FXML way it hasn't worked an error is always appearing when I press the button.
Error message
This is the document controller code.
public class FXMLDocumentController implements Initializable {
#FXML
private Button button1;
#FXML
private Button button2;
#FXML
private void handleButtonAction(ActionEvent event) throws IOException {
Stage stage;
Parent root;
if(event.getSource() == button1){
stage=(Stage)button1.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXML2.fxml"));
}
else{
stage=(Stage)button2.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
}
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}

The error you posted says the code is trying to load a button as an anchor pane. Check too see if you have an anchorpane with the fx:I'd of button1.

Related

How to load image in ImageView dynamically in Java FX

I'm working with FXML and have two different Scene on a single Stage. btnStart is on scene1, and imgBtn is on scene2. When I click btnStart it sets scene2 to stage and loads an image to imageView (this is throwing NullPointerException). But when I click imgBtn on scene2 it is loading image.
My question is how to load image dynamically when I switch to scene2 ?
#FXML private Button imgBtn;
#FXML private Button btnStart;
#FXML public ImageView imageView;
#FXML
public void imgBtnClicked()throws Exception{
imageView.setImage(new Image(new FileInputStream("src/Assets/CardAssets/png-v2/3C.png")));
}
#FXML
public void btnStartClicked()throws Exception{
SetScene2();
imageView.setImage(new Image(new FileInputStream("src/Assets/CardAssets/png-v2/3C.png")));
}
public void SetScene2()throws Exception {
Parent root = FXMLLoader.load(getClass().getResource(fxmlFile2.fxml));
String css=getClass().getResource("myStyle.css").toExternalForm();
Scene scene;
try{
scene=new Scene(root,root.getScene().getWidth(),root.getScene().getHeight());
}
catch(NullPointerException e) {
scene=new Scene(root,stage.getWidth(),stage.getHeight());
}
scene.getStylesheets().add(css);
stage.setScene(scene);
}
The question is not exactly very clear, so I'm going to make some guesses here. The most likely problem is that you have confused which Nodes are on which scene which is on which controller.
The correct structure for this is that you have two sets of each of the following items:
FXML file
Controller class
Scene object.
This is how it should be done:
public class ControllerA {
#FXML private Button btnStart;
#FXML
public void btnStartClicked()throws Exception{
setScene2();
}
public void setScene2()throws Exception {
// You may need to set the controller to an instance of ControllerB,
// depending whether you have done so on the FXML.
Parent root = FXMLLoader.load(getClass().getResource(fxmlFile2.fxml));
String css=getClass().getResource("myStyle.css").toExternalForm();
Scene scene;
try{
scene=new Scene(root,root.getScene().getWidth(),root.getScene().getHeight());
}
catch(NullPointerException e) {
scene=new Scene(root,stage.getWidth(),stage.getHeight());
}
scene.getStylesheets().add(css);
stage.setScene(scene);
}
}
public class ControllerB {
#FXML private ImageView imageView;
#FXML private Button imgBtn;
#FXML public void initialize() {
imageView.setImage(new Image(new FileInputStream("src/Assets/CardAssets/png-v2/3C.png")));
}
#FXML
public void imgBtnClicked()throws Exception{
imageView.setImage(new Image(new FileInputStream("src/Assets/CardAssets/png-v2/3C.png")));
}
}

JavaFX change ComboBox items (outside of initialize() method)

I am playing around with SceneBuilder and come across a few questions about the intialize() method and how to change ComboBox items after it's already been initialized in said method. So basically, after I set the items in initialize, I am not able to change them anymore from another method in the controller.
Here is my code:
public class AppController implements Initializable {
private ObservableList<String> list = FXCollections.observableArrayList();
private MainModel model;
#FXML
private ComboBox<String> cobUsers = new ComboBox<String>();
#Override
public void initialize(URL url, ResourceBundle rb) {
list.add("name1");
list.add("name2");
cobUsers.setItems(list); // this works!
}
public void initModel(MainModel model) {
this.model = model;
}
public void addItems(){
list.add("name3");
list.add("name4");
cobUsers.setItems(list); // this does not work. ComboBox items remain "name1" and "name2"
}
}
public class App extends Application {
private Stage primaryStage;
private AnchorPane rootLayout;
private AppController appController = new AppController();
MainModel model = new MainModel();
#Override
public void start(Stage primaryStage) {
appController.initModel(model);
this.primaryStage = primaryStage;
this.primaryStage.setTitle("App");
initRootLayout();
appController.addItems();
}
/**
* Initializes the root layout.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXMLDocument.fxml"));
rootLayout = (AnchorPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
So guess my question is, how can I access/change my ComboBox later on, after it's been initialized in intialize()?
Thanks! :)
UPDATE 1:
I have changed the initRootLayout() in the App class (see below) and it WORKS now. list now contains 4 items and all of them show up in the ComboBox after calling addItems(). Thanks everyone!
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("FXMLDocument.fxml"));
rootLayout = (AnchorPane) loader.load();
AppController controller = loader.<AppController>getController();
controller.addItems();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}

Switching between Scene JavaFX

I created a scene in class1, then i created a scene2 in class2.
How to switch between them?
public class class1 extends Application{
Stage window1;
BorderPane layout1;
Scene scene1;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window1 = primaryStage;
window.setTitle("Stage 1");
// And here is a button which switchs between scenes or stages,
//i dont know what is better.So:
button.setOnAction(e -> ?????????)
scene1 = new Scene(layout1, 800,600);
window1.show();
}
}
And here is the second class in which i have another scene.
public class class2 extends Application{
Stage window2;
BorderPane layout2;
Scene scene2;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window2 = primaryStage;
window2.setTitle("Stage 2");
scene2 = new Scene(layout, 800,600);
window2.show();
}
}
I wrote this controller to keep track of the different scenegraphes and switch the content of my Stage with no hassle.
Maybe you want to take a look at FXML:
http://docs.oracle.com/javafx/2/fxml_get_started/why_use_fxml.htm#CHDCHIBE
public class ScreenController {
private HashMap<String, Pane> screenMap = new HashMap<>();
private Scene main;
public ScreenController(Scene main) {
this.main = main;
}
protected void addScreen(String name, Pane pane){
screenMap.put(name, pane);
}
protected void removeScreen(String name){
screenMap.remove(name);
}
protected void activate(String name){
main.setRoot( screenMap.get(name) );
}
}
So I can write:
ScreenController screenController = new ScreenController(scene);
screenController.add("layout1", layout1 );
screenController.add("layout2", layout2 );
screenController.add("testSwitch", FXMLLoader.load(getClass().getResource( "TestSwitch.fxml" )));
button.setOnAction(e -> screenController.activate("layout2"));
This was a workaround for a fullscreen application, where the MacOS fullscreen transition was shown every time a stage switches its scene.
put this in your Controller. You can use anything (like button,label etc.) to get access to your Stage (best inside an eventhandler from Button).
Stage stage = (Stage) AnyThingOnScene.getScene().getWindow();
Parent root = FXMLLoader.load(getClass().getResource("someFile.fxml"));
Scene scene = new Scene(root,420,360);
stage.setScene(scene);

Switching scenes in JavaFX dynamically

I want to switch between 2 different scenes:
Scene 1: ScrollPane where I load different images.
Scene 2: the stage is transparent and there's only 1 button to return to Scene 1.
I´ve been able to do it just having a different fxml for each scene and creating a new scene every time I switch them.
The problem is when I switch from scene 2 to scene 1, all the images loaded in scene 1 aren't there (It´s obvious as I´m creating a new scene rather than "loading" Scene1.
Is there any way to keep the images already loaded when I swith from Scene 2 to Scene 1?
Scene1
public class ControllerImpl implements Initializable, ControlledScreen {
ScreensController myController;
public void initialize(URL url, ResourceBundle rb) {
}
public void setScreenParent(ScreensController screenParent){
myController = screenParent;
}
#FXML
private void goToScreen2(ActionEvent event) throws Exception{
try {
Stage primaryStage = (Stage) hideStage.getScene().getWindow();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/arrow.fxml"));
Parent root1 = fxmlLoader.load();
primaryStage.setScene(new Scene(root));
}
catch (Exception e) {
e.printStackTrace();
}
}
#FXML
public javafx.scene.control.Button hideStage;
}
Scene2:
public class ControllerArrow implements Initializable{
ScreensController myController;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
public void setScreenParent(ScreensController screenParent){
myController = screenParent;
}
#FXML
public javafx.scene.control.Button showStage;
#FXML
private void goToScreen1(ActionEvent event) throws Exception{
try{
Stage stage = (Stage) showStage.getScene().getWindow();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/sample.fxml"));
Parent root = fxmlLoader.load();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
You can switch the scene of your stage like:
Stage stage = (Stage) scene.getWindow();
stage.setScene(yourScene);
So when you have an instance of your scene, you can apply it to your stage

JavaFX stage.setOnCloseRequest without function?

This is my Start-Methode. First i create a stage and set a title and a scene. And i wanna create a dialog if someone wants to close the window on the window-close-btn [X]. i thought i will catch this event with the setOnCloseRequest()-function. But i still can close all stages i open while runtime.
#Override
public void start(final Stage primaryStage) throws Exception {
primaryStage.setTitle("NetControl");
primaryStage.setScene(
createScene(loadMainPane())
);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(final WindowEvent event) {
//Stage init
final Stage dialog = new Stage();
dialog.initModality(Modality.APPLICATION_MODAL);
// Frage - Label
Label label = new Label("Do you really want to quit?");
// Antwort-Button JA
Button okBtn = new Button("Yes");
okBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
dialog.close();
}
});
// Antwort-Button NEIN
Button cancelBtn = new Button("No");
cancelBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.show();
dialog.close();
}
});
}
});
primaryStage.show();
}
private Pane loadMainPane() throws IOException {
FXMLLoader loader = new FXMLLoader();
Pane mainPane = (Pane) loader.load(
getClass().getResourceAsStream(ContentManager.DEFAULT_SCREEN_FXML)
);
MainController mainController = loader.getController();
ContentManager.setCurrentController(mainController);
ContentManager.loadContent(ContentManager.START_SCREEN_FXML);
return mainPane;
}
private Scene createScene(Pane mainPane) {
Scene scene = new Scene(mainPane);
setUserAgentStylesheet(STYLESHEET_MODENA);
return scene;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(args);
}
Are there any other functions to catch the window-events?
or isnt it logical to run the CloseRequest on the primaryStage, i read something with platforms (but i dont know if it necessary for my problem)?
In the onCloseRequest handler, call event.consume();.
That will prevent the primary stage from closing.
Remove the primaryStage.show(); call from the cancel button's handler and add a call to primaryStage.hide(); in the OK button's handler.

Resources