How can I get a reference to the controller of an FXML? - java

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);

Related

Running 2 java classes simultaneously from command prompt and eclipse

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.

Closing the stage from JavaFX FXML controller class (ConfirmBox)

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();
}
}

NullPointerException while modyfing elements on second Pane JavaFX

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.

How to set items of a TableView in a different controller class in JavaFX?

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);
}

How to keep the users login id for all classes

I'm using netbeans and have created a bunch of forms text fields and buttons using the drag and drop gui.
I've created this nice login page where the user enters a user id and password from a local database, I want to store that entered user id to use on another form (a "my profile" page) to then query the database and fetch details about that user. To do this I'll need to store the userid as currentuser and use it in another class.
I've tried a lot of things but the problem is that where the user enters the data is in a private void method and I can't seem to get any variable out of that here's what it looks like.
private void jButton6MouseClicked(java.awt.event.MouseEvent evt) {
String sql = "select * from user where userid='" +userid.getText()
+ "' and password='" +password.getText()+"'";
try {
pst = conn.prepareStatement(sql);
rs = pst.executeQuery();
if (rs.next()) {
JOptionPane.showMessageDialog(null, "Welcome");
dispose();
currentuser = rs.getString("userid");
HomePageMember form5 = new HomePageMember();
form5.setVisible(true);
} else {
JOptionPane.showMessageDialog(null,
"Sorry, Invalid Login ID or Password");
}
} catch(Exception e) {
JOptionPane.showMessageDialog(null, e);
}
public class LoginPage extends javax.swing.JFrame {
Connection conn = null;
ResultSet rs = null;
PreparedStatement pst = null;
private String currentuser;
public String getText() {
return this.currentuser;
// something like this, but it doesn't work
}
//Then in another class have this
displayuserid.setText("currentuser")
Sorry but begin with your code is pretty wierd :
jButton6MouseClicked belongs to which class?
2 of your braces are never closing.
Now to give you an idea of how to proceed :
- Let say your method jButton6MouseClicked belongs to a class LogIn. This class just needs a class attribute currentUser and a getter for this attribute. Then you set this attribute inside jButton6MouseClicked (the fact that it is private doesn't change anything), and so you can get this currentUser from any other class :
public class LogIn {
private String currentUser;
public String getCurrentUser() {
return this.currentUser();
}
// ... Here code to get the user enter login and password
private void jButton6MouseClicked(java.awt.event.MouseEvent evt) {
// ... same code as yours
} // Close the brace
} // And the second one
Now if you are using the LogIn class from elsewhere, let's say the instance of your class is called login, you can get the currentUser by calling :
login.getCurrentUser();

Categories

Resources