I want to change scenes on my stage or close stage when I push the startgame button and exitgame button, but its just show me first scene, and when I'm trying to push one of this buttons compiler close in case of NullPointerException.
I also have main class and two fxml files, but I think it's don't necessary to put it here, it contains just two anchor panes, primitive labels and buttons.
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable{
private Stage stage = new Stage();
private FXMLLoader loader = new FXMLLoader();
private AnchorPane anchorPane = new AnchorPane();
private Scene scene = new Scene(new AnchorPane());
#FXML private Button startGameButton;
#FXML private Button endGameButton;
#FXML private Button buttonAnswer1;
#FXML private Button buttonAnswer2;
#FXML private Button buttonAnswer3;
#FXML private Button buttonAnswer4;
public void createScene(int typeOfScene) throws Exception
{
if (typeOfScene == 1)
{
loader = new FXMLLoader(getClass().getResource("/sample/sample.fxml"));
anchorPane = loader.load();
scene = new Scene(anchorPane);
stage.setScene(scene);
stage.show();
}
if (typeOfScene == 2)
{
scene = null;
loader = new FXMLLoader(getClass().getResource("/sample/episodesFXML.fxml"));
anchorPane = loader.load();
scene = new Scene(anchorPane);
stage.setScene(scene);
stage.show();
}
}
public void getPrimaryStage(Stage stage) throws Exception
{
this.stage = stage;
createScene(1);
}
#Override
public void initialize(URL location, ResourceBundle resources) {
startGameButton.setOnAction(event -> {
try {
createScene(2);
} catch (Exception e)
{
e.printStackTrace();
}
});
endGameButton.setOnAction(event -> {
stage.close();
});
}
}
I remember a problem like that, fxml file is linked to a controller file by the fx:controller attribute. You try to load a fxml in a controller that it's not handled/loaded. Create another form and showing/hiding forms seems simpler.
Related
I have multiple stages in my program, each with their own controller class. For simplicity I will focus on just two: the Main stage and the Add stage. My program is a projectile simulator program, so the Main stage will show the simulation, while the Add stage allows the user to add projectiles.
The problem I am experiencing is that when the user adds a projectile in the Add stage, it needs to then add the projectile to the Main stage so that it can be displayed. I am having troubles with communicating this new projectile between the two stages.
I have tried using the FXMLLoader.getController() method, to then run MainController.add( newSphere ), but there is a NullPointerException on the controller. The controller should not be null and the new sphere should have been passed to the add method, so that the Sphere can be displayed on the Main Stage.
Application Class
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class App extends Application
{
private FXMLLoader fxmlLoader = new FXMLLoader( getClass().getResource("/Main.fxml") );
public void start( Stage primaryStage ) throws Exception
{
Parent root = fxmlLoader.load();
Scene scene = new Scene( root, 900, 600 );
primaryStage.setTitle("Projectile Simulator");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main( String[] args )
{
launch(args);
}
}
Main Controller
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;
public class MainController
{
private Group group = new Group();
/**
* Creates the Add Stage when the user presses the Add button.
* #param event
*/
public void handleAddMenuAction( ActionEvent event )
{
Stage addStage = new Stage();
try
{
Parent root = FXMLLoader.load( getClass().getResource("/Add.fxml") );
Scene scene = new Scene(root, 300, 250);
addStage.setScene(scene);
addStage.setResizable(false);
addStage.setTitle("Add Simulation");
addStage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
// Adds the sphere to the group.
public void addSphere( Sphere newSphere )
{
group.getChildren().add( newSphere );
}
}
Add Controller
There are other features, such as setting the position and velocity of the projectile etc, but I have left them out for simplicity.
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.shape.Sphere;
public class AddController
{
#FXML private TextField txtRadius;
#FXML private void handleAddButtonAction()
{
FXMLLoader loader = new FXMLLoader( getClass().getResource("/Main.fxml") );
MainController mainController = loader.getController();
String szRadius = txtRadius.getText();
double dRadius;
dRadius = Double.parseDouble( szRadius );
Sphere sphere = new Sphere();
sphere.setRadius( dRadius );
mainController.addSphere( sphere);
}
}
I want to make a very simple program in JavaFX. It goes like this:
The user inputs something into a TextField
The program displays the input on a label but on a different Scene
Here is my code:
Controller.java
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import javax.xml.soap.Text;
import java.io.IOException;
public class Controller {
//textField in sample.fxml
#FXML
TextField textField;
//label in display.fxml
#FXML
Label label;
String text;
#FXML
public void enter() throws IOException {
text = textField.getText();
Stage stage = (Stage) (textField).getScene().getWindow();
Parent root = FXMLLoader.load(getClass().getResource("display.fxml"));
stage.setResizable(false);
stage.setTitle("Display");
stage.setScene(new Scene(root, 300, 275));
label.setText(text);
}
}
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
There are 2 other FXML files containing either a single textField or a single Label.
But whenever I run this code there is a NullPointerException signaling that label is null, because it hasn't been initialized. How do I fix this?
I believe you should make antoher controller for the display.fxml file (the other scene). Than in this new controller you can prepare a function to set label value:
DisplayController.java
public class DisplayController {
//label in display.fxml
#FXML
Label label;
public void setLabelText(String s){
label.setText(s);
}
}
and in Controller.java edit enter() function by calling a new DisplayController.java instance:
#FXML
public void enter() throws IOException {
text = textField.getText();
Stage stage = (Stage) (textField).getScene().getWindow();
FXMLLoader loader = new FXMLLoader.load(getClass().getResource("display.fxml"));
Parent root = loader.load();
DisplayController dc = loader.getController();
//here call function to set label text
dc.setLabelText(text);
stage.setResizable(false);
stage.setTitle("Display");
stage.setScene(new Scene(root, 300, 275));
}
I have 2 scenes. One of the scenes is Login and the other is Register. When I click the register button on the Log in screen it switches me to the register scene. The actions I have made in the controller for the button is not working. Do I need to do something in the main or controller to get the Register.fxml to work?
ModelController:
package application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.sql.*;
public class ModelController extends Main{
#FXML
private Label LblStatus;
#FXML
private TextField UserEmail;
#FXML
private TextField UserPassword;
#FXML
private TextField RegisterEmail;
#FXML
private TextField RegisterPassword;
#FXML
private TextField RegisterFirst;
#FXML
private TextField RegisterLast;
#FXML
private TextField RegisterSSN;
#FXML
private TextField RegisterAddress;
#FXML
private TextField RegisterCity;
#FXML
private TextField RegisterState;
#FXML
private TextField RegisterZip;
#FXML
private Button LoginRegister;
public void Login(ActionEvent event) throws Exception {
if(UserEmail.getText().equals("User") && UserPassword.getText().equals("pass")) {
LblStatus.setText("Login Success");
Stage primaryStage = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("/application/Main.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
else {
LblStatus.setText("Login Failed");
}
}
public void handleButtonAction(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Register.FXML"));
Parent root1 = (Parent) fxmlLoader.load();
Scene Register = new Scene(root1);
Stage window = (Stage)((Node)event.getSource()).getScene().getWindow();
window.setScene(Register);
window.show();
}
catch(Exception e) {
}
}
public void CompleteRegistration(ActionEvent event) {
}
Main:
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/application/Login.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
The 2nd scene was not pulling in the controller.
I want to customize a Slider and found a working example here on stackoverflow:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class SliderWithLabeledThumb extends Application {
#Override
public void start(Stage primaryStage) {
Slider slider = new Slider();
StackPane root = new StackPane(slider);
root.setPadding(new Insets(20));
Scene scene = new Scene(root);
slider.applyCss();
slider.layout();
Pane thumb = (Pane) slider.lookup(".thumb");
Label label = new Label();
label.textProperty().bind(slider.valueProperty().asString("%.1f"));
thumb.getChildren().add(label);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Unfortunately, if I look up the thumb of the slider in my controller class for an fxml view, I will always get a NullPointerException when trying to add the Label to the thumb's children… Thumb can obviously not be looked up. Then I found another answer here that says lookup() must be called after stage.show(), so here is my question again:
How can I look up a slider thumb in a controller class that manages fxml components (that does not have a stage.show())?
I tried creating a Slider in code only and also used one from fxml, both lookups return null when calling that in the controller's initialize(…) method.Is it somehow possible to customize a Slider's thumb in a controller class?
EDIT:
The code that produces the exception is in the controller class that gets automatically instantiated due to an entry in the corresponding xml file. No matter if I use a Slider loaded from fxml by annotation, having just a member and initialize that or create a new Slider object. As long as I do that in the controller class, I will keep getting NullPointerExceptions from the line commented in the code below:
public class MainViewController implements Initializable {
#FXML private VBox root;
private Slider timeSlider;
#Override
public void initialize(URL location, ResourceBundle resources) {
timeSlider = new Slider();
root.getChildren.add(timeSlider);
timeSlider.setMax(360);
timeSlider.setMin(0);
timeSlider.setCursor(Cursor.OPEN_HAND);
timeSlider.applyCss();
timeSlider.layout();
Pane thumb = (Pane) timeSlider.lookup(".thumb");
Label label = new Label();
label.textProperty().bind(timeSlider.valueProperty().asString("%.1f"));
// the following line points to thumb, which is null then… (debugger proof)
thumb.getChildren().add(label);
}
}
In the Main.java I just load the fxml file:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("MainView.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root,800,600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Finally, the fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="root" maxHeight="600" maxWidth="800" prefHeight="600"
prefWidth="800" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="application.MainViewController">
</VBox>
Put the lookup code in the slider listener like below:
volumeBar.valueProperty().addListener((observable, oldValue, newValue) -> {
Pane thumb = (Pane) volumeBar.lookup(".thumb");
if(thumb.getChildren().size() == 0){
Label label = new Label();
label.textProperty().bind(volumeBar.valueProperty().asString("%.0f"));
thumb.getChildren().add(label);
}
});
This is the java
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class mains extends Stage {
public static void main(String[] args) {
new JFXPanel();
Platform.runLater(new Runnable(){
#Override
public void run() {
new mains();
}
});
}
void go(){
new JFXPanel();
new mains().show();
}
public mains() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"LOL.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (Exception e) {
e.printStackTrace();
}
}
#FXML
private Button button;
#FXML
private Label label;
#FXML
void push(ActionEvent event) {
}
}
here is the fxml http://pastebin.com/uzBrMRDV
I get a load exception it says Root is already specified.
If i remove the setRoot(this); it doesnt load at all
I am getting really frustrated with JFX...
Is there anyway to load FXML files like a Stage from the controller itself
Remove the line
fxmlLoader.setRoot(this);
Your FXML defines the root to be an AnchorPane (and you can't set the root twice, which is why you are getting the error).
Since the current class is a Stage, and the FXMLLoader loads an AnchorPane, you need to put the loaded AnchorPane in a Scene and set the scene in the stage. Replace
fxmlLoader.load();
with
AnchorPane root = fxmlLoader.load();
Scene scene = new Scene(root); // optionally specify dimensions too
this.setScene(scene);