Как сделать так, чтобы «текущий каталог» диалогов сохранялся при разных вызовах?
Вы можете изменить подход Singleton Pattern для этого
При этом вы будете использовать только один FileChooser
и отслеживать/контролировать исходный каталог там, но не подвергать экземпляр непосредственно изменениям вне класса.
Например:
public class RetentionFileChooser {
private static FileChooser instance = null;
private static SimpleObjectProperty<File> lastKnownDirectoryProperty = new SimpleObjectProperty<>();
private RetentionFileChooser(){ }
private static FileChooser getInstance(){
if(instance == null) {
instance = new FileChooser();
instance.initialDirectoryProperty().bindBidirectional(lastKnownDirectoryProperty);
//Set the FileExtensions you want to allow
instance.getExtensionFilters().setAll(new ExtensionFilter("png files (*.png)", "*.png"));
}
return instance;
}
public static File showOpenDialog(){
return showOpenDialog(null);
}
public static File showOpenDialog(Window ownerWindow){
File chosenFile = getInstance().showOpenDialog(ownerWindow);
if(chosenFile != null){
//Set the property to the directory of the chosenFile so the fileChooser will open here next
lastKnownDirectoryProperty.setValue(chosenFile.getParentFile());
}
return chosenFile;
}
public static File showSaveDialog(){
return showSaveDialog(null);
}
public static File showSaveDialog(Window ownerWindow){
File chosenFile = getInstance().showSaveDialog(ownerWindow);
if(chosenFile != null){
//Set the property to the directory of the chosenFile so the fileChooser will open here next
lastKnownDirectoryProperty.setValue(chosenFile.getParentFile());
}
return chosenFile;
}
}
Это установит начальный каталог FileChooser
в качестве каталога файла, который пользователь последний раз открывал/сохранял при повторном использовании.
Пример использования:
File chosenFile = RetentionFileChooser.showOpenDialog();
Однако здесь есть ограничение:
//Set the FileExtensions you want to allow
instance.getExtensionFilters().setAll(new ExtensionFilter("png files (*.png)", "*.png"));
Поскольку без предоставления каких-либо ExtensionFilter
, FileChooser
становится менее удобным для пользователя, требуя от пользователя добавления типа файла вручную, но предоставление фильтров при создании экземпляра без возможности их обновления ограничивает его теми же фильтрами.
Один из способов улучшить это — предоставить дополнительные фильтры в RetentionFileChooser
, которые могут быть предоставлены с помощью varargs, благодаря чему вы можете выбирать, когда изменять фильтры при отображении диалогов.
Например, опираясь на предыдущий:
public class RetentionFileChooser {
public enum FilterMode {
//Setup supported filters
PNG_FILES("png files (*.png)", "*.png"),
TXT_FILES("txt files (*.txt)", "*.txt");
private ExtensionFilter extensionFilter;
FilterMode(String extensionDisplayName, String... extensions){
extensionFilter = new ExtensionFilter(extensionDisplayName, extensions);
}
public ExtensionFilter getExtensionFilter(){
return extensionFilter;
}
}
private static FileChooser instance = null;
private static SimpleObjectProperty<File> lastKnownDirectoryProperty = new SimpleObjectProperty<>();
private RetentionFileChooser(){ }
private static FileChooser getInstance(FilterMode... filterModes){
if(instance == null) {
instance = new FileChooser();
instance.initialDirectoryProperty().bindBidirectional(lastKnownDirectoryProperty);
}
//Set the filters to those provided
//You could add check's to ensure that a default filter is included, adding it if need be
instance.getExtensionFilters().setAll(
Arrays.stream(filterModes)
.map(FilterMode::getExtensionFilter)
.collect(Collectors.toList()));
return instance;
}
public static File showOpenDialog(FilterMode... filterModes){
return showOpenDialog(null, filterModes);
}
public static File showOpenDialog(Window ownerWindow, FilterMode...filterModes){
File chosenFile = getInstance(filterModes).showOpenDialog(ownerWindow);
if(chosenFile != null){
lastKnownDirectoryProperty.setValue(chosenFile.getParentFile());
}
return chosenFile;
}
public static File showSaveDialog(FilterMode... filterModes){
return showSaveDialog(null, filterModes);
}
public static File showSaveDialog(Window ownerWindow, FilterMode... filterModes){
File chosenFile = getInstance(filterModes).showSaveDialog(ownerWindow);
if(chosenFile != null){
lastKnownDirectoryProperty.setValue(chosenFile.getParentFile());
}
return chosenFile;
}
}
Пример использования:
//Note the previous example still holds
File chosenFile = RetentionFileChooser.showOpenDialog();
File file = RetentionFileChooser.showSaveDialog(FilterMode.PNG_FILES);
но это не работает, если диалог закрыт или отменен.
К сожалению, FileChooser
не предоставляет информацию о том, какой каталог проверялся до его закрытия/прекращения. Если вы декомпилируете класс и проследите его, он в конечном итоге столкнется с вызовом native
. Таким образом, даже если FileChooser
не было final
разрешено создание подкласса, вряд ли он сможет получить эту информацию.
Единственная выгода, которую дает описанный выше подход, заключается в том, что он не меняет начальный каталог, если этот сценарий срабатывает.
Если вам интересно, есть несколько очень хороших ответов на ключевое слово native
в этом вопросе и связанных ссылках:
person
Peter
schedule
25.06.2016