3

Контекст:
Я новичок в JavaFX, но я пытаюсь создать приложение, которое один из его основной особенностью является, чтобы показать пользователю все папки в определенной директории и автоматически обновлять представление, когда в этой папке удаляются новые папки или папки. Эти папки можно рассматривать как объекты (например, в ListView), и пользователь должен иметь возможность взаимодействовать с ними. Я хочу создать это приложение с использованием архитектуры MVC.MVC: Лучший способ просмотра каталога для изменения

Что я сделал до сих пор:
Так у меня есть мнение (FXML), класс контроллера и мою модель, которая обрабатывает мое приложение логики. Я использую WatchDir example from Oracle как вспомогательный класс в моей модели и запуска WatchService в контроллере, как это:

@Override 
public void initialize(URL location, ResourceBundle resources) { 
    this.config = loadConfig(configFile); 
    this.facade = new facade(config); 
    Path rootPath = Paths.get(config.getDlRootPath()); 
    try { 
     // register WatchService 
     new WatchDir(rootPath, false).processEvents(); 
     statusText(rootPath + "is now being watched for changes"); 
    } catch (IOException e) { 
     statusError("Directory " + e.getLocalizedMessage() + " does not exist."); 
    } 
} 

В методе processEvents WatchDir() Я могу сделать что-то вроде:

if (!recursive && (kind == ENTRY_CREATE)) { 
    // new folder was created 
} 

Мой вопрос :
Что является лучшим/самым элегантным способом сообщить моему контроллеру, что что-то изменилось и обновить ListView? Я хочу сохранить его в стиле MVC.

Различный подход также приветствуется :)

ответ

4

Подход, который я хотел бы использовать бы обеспечить методы WatchDir для регистрации обратных вызовов. Самый простой способ сделать это просто использовать Consumer свойства для обратных вызовов:

public class WatchDir { 

    private Consumer<Path> onCreate ; 

    public void setOnCreate(Consumer<Path> onCreate) { 
     this.onCreate = onCreate ; 
    } 

    // other callbacks as needed... 

    // ... 

    void processEvents() { 

     // ... 

     Path child = ... ; // file/folder that was created 

     if (! recursive && kind == ENTRY_CREATE) { 
      if (onCreate != null) { 
       onCreate.accept(child); 
      } 
     } 

     // ... 
    } 

    // ... 
} 

Обратите внимание, что WatchDir.processEvents() является (не нагрузочным) блокировкой вызова, так что вам нужно, чтобы запустить его в фоновом потоке. Так что с вашего контроллера вы делаете:

WatchDir watchDir = new WatchDir(rootPath, false) ; 
watchDir.setOnCreate(path -> 
    Platform.runLater(() -> listView.getItems().add(path))); 
Thread watchThread = new Thread(watchDir::processEvents); 
watchThread.setDaemon(true); 
watchThread.start(); 

Обратите внимание, что, так как обратный вызов будет вызван на фоне потока, обновления пользовательского интерфейса должны быть завернуты в Platform.runLater(...). Если вы хотите, вы можете оборудовать WatchDir с Executor для выполнения обратного вызова, который позволит вам сказать это только один раз, чтобы всегда выполнять их с помощью Platform.runLater(...):

public class WatchDir { 

    // Executor for notifications: by default just run on the current thread 
    private Executor notificationExecutor = Runnable::run ; 
    public void setNotificationExecutor(Executor notificationExecutor) { 
     this.notificationExecutor = notificationExecutor ; 
    } 

    private Consumer<Path> onCreate ; 
    // etc... 

    void processEvents() { 

     // ... 

     if (! recursive && kind == ENTRY_CREATE) { 
      if (onCreate != null) { 
       notificationExecutor.execute(() -> onCreate.accept(child)); 
      } 
     } 

     // ... 
    } 

} 

и затем

WatchDir watchDir = new WatchDir(rootPath, false) ; 
watchDir.setNotificationExecutor(Platform::runLater); 
watchDir.setOnCreate(listView.getItems()::add); /* or path -> listView.getItems().add(path) */ 
Thread watchThread = new Thread(watchDir::processEvents); 
watchThread.setDaemon(true); 
watchThread.start(); 
+0

работает как шарм , это очень помогло мне! – lenny