0

I'm trying to update TableView, which is in one FXML, by pressing a button, which is in another FXML.

Here is the controller for the FXML which has the button:

public class GUIAddMemberPanelController 
{
   private GUIMainController mainController = new GUIMainController();

   @FXML private TextField tfEnterMemberName,tfEnterMemberEmail;

   @FXML private Button btnAddMember,btnClearAddMemberTextFields,btnCancelAddMemberPanel;

   public void addMember(ActionEvent event) throws ParseException, IOException, CloneNotSupportedException 
   {
      String memberName = tfEnterMemberName.getText();
      String memberEmail = tfEnterMemberEmail.getText();
      member = new Member(memberName,memberEmail);
      memberList.addMemberToList(member);
      memberFile.writeMemberTextFile(memberList);

      clearAddMemberTextFields(event);

      mainController.refreshMemberTable();
}

And here is the main controller which has the TableView:

public class GUIMainController 
{
    @FXML private TableView<Member> tableMembers;
    @FXML private TableColumn<Member, String> tcMemberName;
    @FXML private TableColumn<Member, String> tcMemberEmail;

public void initialize() throws FileNotFoundException, ParseException
{       
    refreshMemberTable();
}   

public void refreshMemberTable() throws ParseException, FileNotFoundException
{
    tcMemberName.setCellValueFactory(new PropertyValueFactory<Member, String>("name"));
    tcMemberEmail.setCellValueFactory(new PropertyValueFactory<Member, String>("email"));

    tableMembers.setItems(getList());
    tableMembers.setEditable(true); 
}   

public ObservableList<Member> getList() throws FileNotFoundException, ParseException
{
    ObservableList<Member> members = FXCollections.observableArrayList();

    MemberList memberList = memberFile.readMemberTextFile();

    for (int i = 0; i < memberList.size(); i++)
    {
        members.add(new Member(memberList.getMember(i).getName(), memberList.getMember(i).getEmail()));
    }       

    return members;     
}
}

After I click the button, it gives me a bunch of errors:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8413)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769)
... 48 more
Caused by: java.lang.NullPointerException
at GUIMainController.refreshMemberTable(GUIMainController.java:275)
at GUIAddMemberPanelController.addMember(GUIAddMemberPanelController.java:36)
... 58 more

Any help will be much appreciated, thanks.

Update:

I've tried to go trought the suggested question by fabian, but encountered more confusion. Can anyone please point out what am I doing wrong here? Thanks

public void addMember(ActionEvent event) throws ParseException, CloneNotSupportedException, IOException 
{
    String memberName = tfEnterMemberName.getText();
    String memberEmail = tfEnterMemberEmail.getText();
    member = new Member(memberName,memberEmail);
    memberList.addMemberToList(member);
    memberFile.writeMemberTextFile(memberList);

    refreshMemberList();
}  

public void refreshMemberList() throws FileNotFoundException, ParseException
{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("FXML/viaGUI.fxml"));
    GUIMainController controller = loader.<GUIMainController>getController();
    loader.setController(controller);       
    controller.refreshMemberTable();
}

Here i load the main FXML:

public class MainClass extends Application
{

public static void main(String[] args)
{
    launch(args);
}   

public void start(Stage stage) throws Exception
{
    FXMLLoader loader = new FXMLLoader();
    loader.setController(new GUIMainController());

    loader.setLocation(getClass().getResource("FXML/viaGUI.fxml"));
    Parent root = loader.load();

    Scene scene = new Scene(root);

    stage.setTitle("VIA - Event Management System");    

    stage.setScene(scene);
    stage.show();
}
}
RollerMobster
  • 864
  • 1
  • 10
  • 28
  • 2
    Simply creating a new instance of `GUIMainController` won't result in the controller used with the fxml you load.Assuming the fxml is loaded using a `` element you could simply use`FXMLLoader`to inject the controller by adding the `fx:id` attribute instead of creating it using the controller's initializer:``.Otherwise refer to this question: http://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml to pass the controller instance that is created when you load the main fxml to the controller created when loading the other fxml. – fabian Dec 06 '17 at 15:43
  • Hi fabian, tried to follow your suggested question, but got more confused. I've updated my code, can you please have a look and let me know if Im going in a right direction? – RollerMobster Dec 06 '17 at 17:21
  • You need to call the `load()` method to create the controller from a `fx:controller` attribute. Retrieving the value before calling load yields `null`. You could also specify a controller instance before calling `load()` using `setController` (`fx:controller` must not be present in the fxml in this case). Both approaches require you to use the `FXMLLoader` you use to create the fxml that you display on screen. Simply loading a scene to create a controller instance will result in a scene+controller that are never displayed. – fabian Dec 06 '17 at 18:03
  • In your updated version you create another FXML Loader that knows how to load the FMXL that defines the table, but you never actually load that FXML. Even if you did, you would simply have a second copy of the UI defined in the FXML. Somewhere in code you haven't posted, you actually load *and display* the FXML that contains the table. You need to get the controller associated with *that UI instance*, and update the table via it. Create (probably from scratch) a [MCVE] that has the same structure and essential features that are causing you problems. – James_D Dec 06 '17 at 22:07
  • Hi James, thanks for your suggestion, but I have a question. What if I am loading and displaying the FXML that contains the table from the main class (see update) ? How do I access that specific controller then? Thanks – RollerMobster Dec 06 '17 at 23:21
  • @GiedriusElectrum Then you would get the controller from the main class - the only time you can get the controller is when you load the FXML. You need to pass that reference to the other controller. – James_D Dec 07 '17 at 02:07
  • I think I understand what needs to be done, yet Im still stuck with how to translate that to code. Sorry to ask, but maybe you have some code snippets ? – RollerMobster Dec 07 '17 at 03:14

0 Answers0