javaFX: как создать Live ListView и добавить к нему ChangeListener

Я написал пользовательский интерфейс JavaFX (fxml) и привязал к нему класс контроллера, все работало нормально, пока я не добавил ObservableList и ChangeListener для ListView в своем приложении. ListView выглядит нормально и показывает правильные значения при запуске приложения, но когда я нажимаю некоторые кнопки, возникают исключения, и кнопки не работают. Это кнопки, которые должны показывать другие макеты при нажатии. исключение говорит, что макет (например, AddUser.fxml) не найден, но он существует и работает правильно до сих пор!

некоторые строки класса контроллера:

public class FileSharingController implements Initializable {

private ObservableList<User> UsersListData=FXCollections.observableArrayList();
@FXML
private ListView<User> UsersList;

public FileSharingController(){
    DatabaseManager DB=new DatabaseManager();
    try {
        UsersListData.addAll(DB.returnUsers());
    } catch (SQLException e) {e.printStackTrace();}
}

@Override
public void initialize(URL location, ResourceBundle resources) {
        UsersList.setItems(UsersListData);
        UsersListData.addListener(new ListChangeListener<User>(){
            @Override
            public void onChanged(Change<? extends User> c) {
                System.out.println(c.getList());

            }
        });
}

@FXML
public void showAddUserLayout(){
    try {Stage stage=new Stage();
    AnchorPane  rootPane=FXMLLoader.load(getClass().getResource("AddUser.fxml"));
    Scene scene = new Scene(rootPane);
    stage.setScene(scene);
    stage.setTitle("Add User");
    stage.show();
} catch (IOException e) {e.printStackTrace();}
}
}

Пользовательский класс (Модель):

package Model;

public class User {
private String Username;
private String Password;

public User(String Username,String Password){
    this.Username=Username;
    this.Password=Password;
}
public void Set(String Username,String Password){
    this.Username=Username;
    this.Password=Password;
}
public String toString(){
    return Username+"   "+Password;
}
}

когда я нажимаю кнопку «Добавить», вызывается функция showAddUserLayout(), и я получаю следующие исключения:

java.lang.NullPointerException
/D:/workspace_FileSharing%20Serverside/FileSharing_ServerSide/bin/com/Shayan/FileSharing/Server/AddUser.fxml
  at com.Shayan.FileSharing.Server.FileSharingController.updateUsersList(FileSharingController.java:144)
at com.Shayan.FileSharing.Server.FileSharingController.initialize(FileSharingController.java:50)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2152)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2028)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2742)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2721)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2694)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2683)
at com.Shayan.FileSharing.Server.FileSharingController.showAddUserLayout(FileSharingController.java:100)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1437)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
at javafx.event.Event.fireEvent(Event.java:171)
at javafx.scene.Scene$ClickGenerator.postProcess(Scene.java:3113)
at javafx.scene.Scene$ClickGenerator.access$8600(Scene.java:3051)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3333)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3164)
at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3119)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1559)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2261)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:228)
at com.sun.glass.ui.View.handleMouseEvent(View.java:528)
at com.sun.glass.ui.View.notifyMouse(View.java:922)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
at java.lang.Thread.run(Thread.java:722)

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
      at     javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1440)
      at  com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
     at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
      at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
      at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)

Пожалуйста помоги! Я не знаю, что происходит... заранее спасибо!


person Shayan_Aryan    schedule 21.07.2013    source источник
comment
пожалуйста! кто-нибудь ответьте...   -  person Shayan_Aryan    schedule 21.07.2013


Ответы (1)


Ваш опубликованный код неполный. FXMLLoader загружает файл «AddUser.fxml». Он также вызывает метод инициализации контроллера. Но исключение nullpointerException появляется в строке номер 144 в методе updateUsersList(). Проверьте эту строку. И вы можете изменить класс контроллера «AddUser.fxml» на другой, чем FileSharingController.

Согласно комментарию
Does each Layout need a seperate controller?

Технически нет, но семантически да. Если вы установите один и тот же fx:controller в разных файлах FXML, вы получите несколько экземпляров этого контроллера для каждого загружаемого файла FXML. Если вы используете FXMLLoader.setController() вместе с FXMLLoader.setRoot(), где файлы FXML включают fx:root вместо fx:controller, тогда вы получите только один экземпляр контроллера, метод initialize() которого будет вызываться отдельно для каждого загружаемого файла FXML. В обоих случаях, однако, каждый файл FXML будет семантически иметь дело только с некоторой частью контроллера, т. е. инициализировать, вводить, устанавливать, манипулировать частями, которые его интересуют. IMO файлы FXML не должны иметь общего домена, а если имеют, то они должны использовать обычный механизм обмена сообщениями Java через свои собственные контроллеры. Таким образом, наличие другого класса AddUserController будет более модульным, удобным в сопровождении и с меньшим количеством головной боли.

person Uluk Biy    schedule 21.07.2013
comment
Нужен ли для каждого макета отдельный контроллер? Я использовал один контроллер для всех своих 5 макетов. - person Shayan_Aryan; 28.07.2013
comment
Ух ты! Спасибо! Я создал контроллер для каждого макета, я не получаю никаких ошибок. теперь, как я могу инициализировать основной макет из других макетов? потому что, когда я добавляю данные в свою базу данных, мне нужно, чтобы ListView обновлялся с помощью метода инициализации - person Shayan_Aryan; 28.07.2013
comment
@Шаян_Арьян. Когда отображается дочерний макет, основной макет уже был инициализирован. Итак, вы хотите обновить основной макет, я думаю. Во-первых, вы можете вызвать метод refreshListView основного контроллера макета при действии кнопки «Добавить данные», а в другом случае сделать то же самое, когда этап дочернего макета onClosed. Найдите на сайте похожие варианты использования, такие как обмен данными между контроллерами, передача данных между контроллерами и другие. Или, пожалуйста, начните новую запись вопросов и ответов с более подробной информацией и примером кода. - person Uluk Biy; 28.07.2013