I have a problem with nullPointer while i'm trying to modify any element from second Panel in my application.
How my application look like: I have 2 Panel, first to loggin and second one with Main Application.
Steps in my application:
Create and show 1 panel
Provide passwords and loggin to database
a/ Success - open new panel and hide this one
b/ show error message
Now i'm trying to modify any element from panel 2 but i cant
Caused by: java.lang.NullPointerException
at sample.ControllerLoginMenu.openScene(ControllerLoginMenu.java:114)
at sample.ControllerLoginMenu.login(ControllerLoginMenu.java:41)
... 58 more
Here is my code
public class ControllerLoginMenu {
#FXML private Label statusMessage; // second Panel
#FXML private Circle statusCircle; // second Panel
#FXML private Label errorMessageConnection; // First Panel
#FXML private Label errorMessagePassword; // First Panel
#FXML private TextField loginField; //First Panel
#FXML private PasswordField passwordField; //First panel
private String username ;
private String password ;
private final String url = "jdbc:oracle:thin:#google.com:6666:NotExist";
private Stage primaryStage = new Stage();
private Connection con;
private Statement statement;
#FXML private void login(ActionEvent event) throws IOException {
checkConnection();
openScene(event);
// From there is the problem'
errorMessageConnection.setVisible(true); -- no Error
statusCircle.setFill(Color.RED); -- Error
}
private void openScene(ActionEvent event) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("MainMenu.fxml"));
((Node) event.getSource()).getScene().getWindow().hide();
primaryStage.setTitle("Masterdata loading application");
primaryStage.setScene(new Scene(root, 640, 480));
primaryStage.show();
}
private boolean checkConnection() {
boolean result = false;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return result;
}
try {
con = DriverManager.getConnection(url, username, password);
statement = con.createStatement();
String sql = "SELECT SYSDATE FROM DUAL";
result = statement.execute(sql);
}
catch (SQLException e)
{
passwordField.setText("");
e.printStackTrace();
return result;
}
return result;
}
private boolean getPasswords()
{
username = loginField.getText();
password = passwordField.getText();
if(username.isEmpty() || password.isEmpty())
return false;
else
return true;
}
#Override // Main Class
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("LoginMenu.fxml"));
primaryStage.setTitle("Masterdata loading application");
primaryStage.setScene(new Scene(root, 540, 380));
primaryStage.show();
}
I other posts i have found that this should solve problem, but it didnt.
Platform.runLater(() ->{
statusCircle.setFill(Color.GREEN);});
You load two fxml files, so you have (at least) two controllers. The fields with matching fx:ids in the first fxml file will be initialized in the first controller, and the fields with matching fx:ids in the second fxml file will be initialized in the second controller. Since errorMessageConnection and statusCircle are defined in different FXML files, it is impossible for them both to be non-null in the same controller. Consequently, your login method is guaranteed to throw a null pointer exception.
(You actually appear to be getting a null pointer exception in openScene, but there isn't enough information in your question to diagnose that. It is likely related.)
If you use the same controller class for all your different fxml files, it becomes extremely difficult to keep track of what is initialized, and what remains null, in each controller. You should use a different controller class for each FXML file. If you need to pass data to a controller, use the techniques outlined in this answer.
Related
I'm currently working on a small project that requires a server and a small user interface, which I built with JavaFX. I have to start the user interface via the command prompt using mvn javafx:run (as you can see, I use maven to manage my dependencies). I start the server normally via Eclipse. This also works so far and both programs start up as desired. It just seems like they can't communicate with each other. The commands from the user interface do not arrive in the "actual" program. It seems like there are two separate versions running and not a unified one.
Here is my GUI main-class i start using mvn javafx:run:
public class FX extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("../main/Scene.fxml"));
Scene scene = new Scene(root);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
And heres the corresponding controller:
public class Controller {
#FXML
private TextField senderField;
#FXML
private TextField receiverField;
#FXML
private TextField amountField;
#FXML
private TextField tfbpField;
#FXML
private TextField tflField;
#FXML
private TextField nonceField;
#FXML
private Button submitButton;
#FXML
void submitPressed(ActionEvent event) {
System.out.println("Submit Pressed");
byte[] sender = SHA3Helper.hexToDigest(senderField.getText());
byte[] receiver = SHA3Helper.hexToDigest(receiverField.getText());
double amount = Double.parseDouble(amountField.getText());
double tfbp = Double.parseDouble(tfbpField.getText());
double tfl = Double.parseDouble(tflField.getText());
Transaction transaction = new Transaction(sender, receiver, amount, 0, tfbp, tfl);
System.out.println(transaction.getAmount());
DependencyManager.getPendingTransactions().addPendingTransaction(transaction);
for(int i = 0; i<100 ; i++) {
System.out.println("Receiving test");
}
}
}
As you can see i implemented a simple for-loop to check whether "Receiving test" will also be displayed on eclipse or not - with the rusult that i can see it only in my cmd, not in Eclipse.
And here is the Tomcat that starts the actual program. Of course I start this one first.
public class Start
{
public static void main( String args[] )
{
try
{
Tomcat tomcat = new Tomcat( );
String webappDirectory = new File( "src/main/webapp" ).getAbsolutePath( );
tomcat.setPort( 8080 );
Context context = tomcat.addWebapp( "", webappDirectory );
Tomcat.addServlet( context, "blockchain", new ServletContainer( new Application( ) ) );
context.addServletMappingDecoded( "/blockchain/api/*", "blockchain" );
tomcat.start( );
tomcat.getServer( ).await( );
}
catch ( Exception e )
{
e.printStackTrace( );
}
}
}
Through dubugging I quickly found out that the problem lies in the communication between the two programs. Commands from the UserInterface do not reach the actual program.
I'm trying to make a small "Login then Main Menu" form using JavaFX and Gluon's Scene Builder. I've made 2 scenes so far, the first one is a "Login" screen in which I've connected a SQLite Database, after putting the right Username and Password it loads perfectly fine and it changes to the second scene. For each scene I use a different class (FXML / FXML Controller). In the second scene I want 2 labels that I use to change according to the Database's data (More specifically First_Name and Role).
This is the code I use when I press the "OK" Button in the first scene and it loads the Database:
public class FXMLDocumentController implements Initializable {
public static Connection con;
public static ResultSet rs;
public static String Name;
public static String Role;
#FXML
private void OKButtonAction(ActionEvent event) throws SQLException, IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenuFXML.fxml"));
MainMenuFXMLController mainmenu = loader.getController();
try {
PreparedStatement pst ;
// db parameters
String DBlink = "jdbc:sqlite:"+System.getProperty("user.dir")+"//MedExpressDB.db";
// create a connection to the database
con = DriverManager.getConnection(DBlink);
String sql = "SELECT ID,UserName,Password,First_Name,Last_Name,Role,Address,Town,Phone,AFM,AMKA,Email FROM Users where (UserName = ? and Password = ?)";
pst = con.prepareStatement(sql);
pst.setString(1, user.getText());
pst.setString(2, pass.getText());
rs = pst.executeQuery();
if (rs.next() == false){
System.out.println("Λάθος κωδικός ή Username!");
}else{
Name = "WElcome, "+rs.getString("First_Name");
Role = rs.getString("Role");
mainmenu.setLabels(Name, Role);
Parent root = FXMLLoader.load(getClass().getResource("MainMenuFXML.fxml"));
Scene scene2 = new Scene(root);
Stage stage = (Stage) okbutton.getScene().getWindow();
stage.setScene(scene2);
System.out.println("\nConnection has been established!\nWelcome!");
}
}
catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
}
And in the second class where I use the second scene I have:
public class MainMenuFXMLController implements Initializable {
#FXML
private Label welcomelbl;
#FXML
private Label rolelbl;
public void setLabels(String name, String role){
welcomelbl.setText(name);
rolelbl.setText(role);
}
}
//I tried the:
public void setLabels(x,y){
welcomelbl.setText(x);
rolelbl.setText(y);
}
//and use setLabels in the 1st Class:
FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenuFXML.fxml"));
MainMenuFXMLController mainmenu = loader.getController();
Name = "Welcome, "+rs.getString("First_Name");
Role = rs.getString("Role");
mainmenu.setLabels(Name, Role);
like you can see as well but it throws a java.lang.reflect.InvocationTargetException error.
When you load the 2nd scene get a reference to the controller, and use it:
FXMLLoader loader = new FXMLLoader(getClass().getResource("MainMenuFXML.fxml")); //once only, not twice as posted !
Parent root = loader.load(); //this is essential
MainMenuFXMLController mainmenu = loader.getController();
mainmenu.setLabels(Name, Role);
I'm a beginner in JavaFX, and I am developing a simple app and need to create a confirm box for closing the stage. I have done it without a problem without FXML when I have in the same method the initializing and the closing of the stage. But when I do it with FXML, when I have opened the stage in another class it fails to close it from controller class, even if I create a global stage instance.
public class ConfirmBox {
private Stage confirmBoxStage = new Stage();
boolean confirmClose;
// Confirm box -----------------------------------------------------------------------------------------------------
public boolean confirmClose() {
Parent rootConfirmBox = null;
confirmBoxStage.initModality(Modality.APPLICATION_MODAL);
try {
rootConfirmBox = FXMLLoader.load(getClass().getResource("ConfirmBox.fxml"));;
} catch (IOException e) {
System.out.println("Exception ConfirmBox.java//confirmBoxScene");
e.printStackTrace();
}
Scene confirmBoxScene = new Scene(rootConfirmBox, 640, 480);
confirmBoxStage.setScene(confirmBoxScene);
confirmBoxStage.showAndWait();
return confirmClose;
}
// Closing the confirm box -----------------------------------------------------------------------------------------
public void closeConfirmBox() {
confirmBoxStage.close();
}
}
I was creating an application and wanted to change screens with one button depending on a number the user inputs. For example, if a user enters "1234", the program checks another class to see if that number is there. If it is, you go on to SceneOne. If the number the user enters is in reverse compared to the number in the other class, then you go to SceneTwo. However, when I try to set the location to a different scene, it just ignores it and automatically sends me to the first screen.
Storage.Java (contains a pre-defined number)
int pin = 1234;
public int getPin() {
return number;
}
My other class: (function executes when button it is assigned to is pushed)
public void switchScenes(ActionEvent e) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/application/ScreenOne.fxml"));
Parent changeScenes = loader.load();
Scene firstScene = new Scene(changeScenes);
Stage window = (Stage)((Node)e.getSource()).getScene().getWindow();
Storage a = new Storage();
int pin = a.getPin();
if(Integer.parseInt((screen.getText())) == pin) {
//screen is a field where user can enter a number
window.setScene(firstScene);
window.show();
}
else if(Integer.parseInt(screen.getText()) == reverseNumber(pin)) {
//if number entered is in reverse, change to ScreenTwo
loader.setLocation(getClass().getResource("/application/ScreenTwo.fxml"));
}
I can offer a format for changing the scene on a single stage:
On the sixth line is the desired .fxml object. You can simply make an if-then statement and load whatever .fxml object you want based on the input. This is a proven snippet of code I rely on when I want to change the scene in my projects.
{
#FXML
public void buttonclicked(ActionEvent event) throws IOException //This method loads a new scene in a current window
{
//note that on this line you can substitue "Screen2.fxml" for a string chosen prior to this line.
Parent loader = FXMLLoader.load(getClass().getResource("Screen2.fxml"));//Creates a Parent called loader and assign it as ScReen2.FXML
Scene scene = new Scene(loader); //This creates a new scene called scene and assigns it as the Sample.FXML document which was named "loader"
Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); //this accesses the window.
app_stage.setScene(scene); //This sets the scene as scene
app_stage.show(); // this shows the scene
}
}
I have two fxml files with two controller classes MainController and PlaylistController. Each class has a TableView, table and nTable respectively.
table is displayed as the default tab on a TabPane
nTable aplies to a new tab created with a button.
What I want is to be able to select items in the default table and add them to a new table on a new tab in a single action (I can do it using two buttons, one of them being clicked after the new tab is created).
I'm guessing I need to make sure the program waits for the new tab to be created before setting the items but I don't know how to do that.
This is the method I'm using:
#FXML
PlaylistController pc;
public static ObservableList<Track> newTracklist = FXCollections.observableArrayList();
public void addToNewPlaylist(){
newTracklist.clear();
newTracklist.addAll(table.getSelectionModel().getSelectedItems());
Tab nTab = new Tab();
FXMLLoader nLoader = new FXMLLoader(getClass().getResource("/fxml/fxPlaylist.fxml"));
try {
Parent nRoot = nLoader.load();
nTab.setContent(nRoot);
} catch (IOException e) {
e.printStackTrace();
}
tabPane.getTabs().add(nTab);
nTab.isClosable();
pc.nTable.setItems(newTracklist);
}
Unless you are defining a constant, or something similar, static fields have no place in a controller.
Define a method in your PlaylistController to take a list of Tracks for display in its table:
public class PlaylistController {
#FXML
private TableView<Track> nTable ;
// ...
public void setTracks(List<Track> tracks) {
nTable.getItems().setAll(tracks);
}
// ...
}
Then just call it when you load the FXML:
public void addToNewPlaylist(){
Tab nTab = new Tab();
FXMLLoader nLoader = new FXMLLoader(getClass().getResource("/fxml/fxPlaylist.fxml"));
try {
Parent nRoot = nLoader.load();
PlaylistController controller = nLoader.getController();
controller.setTracks(table.getSelectionModel().getSelectedItems());
nTab.setContent(nRoot);
} catch (IOException e) {
e.printStackTrace();
}
tabPane.getTabs().add(nTab);
}