2016-04-28 35 views
5

Mój kontroler widoku ma pojedynczą instancję FileChooser używaną do otwierania i zapisywania plików.Czy program JavaFX FileChooser może "zapamiętać" ostatnio otwierany katalog?

Za każdym razem, gdy wywołuję z tej instancji showOpenDialog() lub showSaveDialog(), oczekuję, że wynikowe okno dialogowe będzie znajdować się w tym samym katalogu, w którym go zostawiłem, gdy ostatnio zadzwoniłem do jednego z nich.

Zamiast tego za każdym razem, gdy wywołuję jedną z tych metod, okna dialogowe otwierają się w katalogu domowym użytkownika.

Jak ustawić "bieżący katalog" dialogów w różnych wywołaniach?


Przykład obecnego zachowania:

import java.io.File; 
import javafx.application.Application; 
import javafx.event.ActionEvent; 
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.layout.VBox; 
import javafx.stage.FileChooser; 
import javafx.stage.Stage; 

/** 
* Demonstrates the use of an open dialog. 
* 
* @author N99x 
*/ 
public class FileChooserTest extends Application { 

    private final FileChooser open = new FileChooser(); 
    private File lastOpened = null; 

    @Override 
    public void start(Stage primaryStage) { 
     Label lbl = new Label("File Opened: <null>"); 
     lbl.setPadding(new Insets(8)); 
     Button btn = new Button(); 
     btn.setPadding(new Insets(8)); 
     btn.setText("Open"); 
     btn.setOnAction((ActionEvent event) -> { 
      open.setInitialDirectory(lastOpened); 
      File selected = open.showOpenDialog(primaryStage); 
      if (selected == null) { 
       lbl.setText("File Opened: <null>"); 
       // lastOpened = ??; 
      } else { 
       lbl.setText("File Opened: " + selected.getAbsolutePath()); 
       lastOpened = selected.getParentFile(); 
      } 
     }); 

     VBox root = new VBox(lbl, btn); 
     root.setPadding(new Insets(8)); 
     root.setAlignment(Pos.TOP_CENTER); 
     Scene scene = new Scene(root, 300, 300); 

     primaryStage.setTitle("FileChooser Testing!"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 

} 

udało mi się obejść za część problemu przechowując otwartą wartość, ale to nie działa, gdy okno jest zamknięte lub anulowane.

Odpowiedz

4

Co zrobić, aby "bieżący katalog" dialogów nadal występował w różnych wywołaniach?

Można zmodyfikować podejście Singleton Pattern tego

Przy czym należy użyć tylko jednego FileChooser i monitor/kontrolować początkowy katalog istnieje, ale nie bezpośrednio narażając instancji do modyfikacji poza klasą


Na przykład:

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

Spowoduje to ustawienie początkowy katalog z FileChooser być katalog pliku użytkownik ostatni otwieranych/zapisywanych gdy jest ponownie wykorzystywane

Przykład użycia:

File chosenFile = RetentionFileChooser.showOpenDialog(); 

Jednak istnieje ograniczenie o:

//Set the FileExtensions you want to allow 
instance.getExtensionFilters().setAll(new ExtensionFilter("png files (*.png)", "*.png")); 

Jak bez podawania ExtensionFilter „s FileChooser jest mniej przyjazna dla użytkownika, wymaga od użytkownika ręcznie appe nd typ pliku, ale dostarczenie filtrów podczas tworzenia instancji bez możliwości ich aktualizacji ogranicza je do tych samych filtrów

Jednym ze sposobów ulepszenia tego jest odsłonięcie opcjonalnych filtrów w ramach RetentionFileChooser, które można uzyskać za pomocą varargs, przy czym można wybrać podczas modyfikowania filtrów podczas wyświetlania okien dialogowych

na przykład, w oparciu o poprzedni:

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

przykład użycia:

//Note the previous example still holds 
File chosenFile = RetentionFileChooser.showOpenDialog(); 
File file = RetentionFileChooser.showSaveDialog(FilterMode.PNG_FILES); 

ale to nie działa, jeśli okno dialogowe jest zamknięte lub anulowane.

Niestety nie ma informacji o tym, który katalog był badany przed jego zamknięciem/zakończeniem. Jeśli usuniesz kompilację klasy i prześledzisz ją, w końcu trafi ona na wywołanie native.Więc nawet jeśli FileChooser nie byłby final pozwalający na jego subklasę, to jest mało prawdopodobne, aby móc uzyskać te informacje. Jedyną korzyścią, jaką daje powyższe podejście, jest to, że nie zmienia katalogu początkowego, jeśli ten scenariusz jest trafiony


Jeśli jesteś zainteresowany, istnieje kilka bardzo dobrych odpowiedzi na słowa kluczowego native w tej kwestii i te powiązane:

+0

Prostym rozwiązaniem propozycji rozszerzeń plików jest resetowanie rozszerzeń plików za każdym razem, gdy je wywołasz. IE: 'fileChooser.getExtensionFilters(). Clear(); fileChooser.getExtensionFilters(). Add (nowy FileChooser.ExtensionFilter ("PNG", "* .png")); ' –

1
private static String lastVisitedDirectory=System.getProperty("user.home"); 

FileChooser fileChooser = new FileChooser(); 
fileChooser.setTitle("View Pictures"); 
fileChooser.setInitialDirectory(new File(lastVisitedDirectory)); 
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("--")); 

List<File> files = fileChooser.showOpenMultipleDialog(----); 


lastVisitedDir=(files!=null && files.size()>=1)?files.get(0).getParent():System.getProperty("user.home"); 
Powiązane problemy