28 文件选择器
本章介绍如何使用 FileChooser
类来使用户能够浏览文件系统。本章提供的示例说明了如何打开一个或多个文件,配置文件选择器对话框窗口以及保存应用程序内容。
与其他用户界面组件类不同,FileChooser
类不属于 javafx.scene.controls
包。然而,由于它支持典型的 GUI 应用程序功能之一:文件系统导航,因此在 JavaFX UI Controls 教程中值得一提。
FileChooser
类位于 javafx.stage
包中,与其他基本的根图形元素(如 Stage
、Window
和 Popup
)一起。在图28-1中的“查看图片”窗口是 Windows 中文件选择器对话框的一个示例。
打开文件
文件选择器可以用于调用打开对话框窗口,选择单个文件或多个文件,并启用文件保存对话框窗口。要显示文件选择器,通常使用FileChooser
类。在您的应用程序中启用文件选择器的最简单方法如示例28-1所示。
示例28-1 显示文件选择器
FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("打开资源文件"); fileChooser.showOpenDialog(stage);
将示例28-1中的代码添加到JavaFX应用程序后,文件选择器对话框窗口将在应用程序启动时立即显示,如图28-2所示。
尽管在前面的示例中,文件选择器在应用程序启动时自动出现,但更典型的方法是通过选择相应的菜单项或点击专用按钮来调用文件选择器。在本教程中,您将创建一个应用程序,使用户能够点击一个按钮并打开文件系统中的一个或多个图片。 示例28-2显示了实现此任务的FileChooserSample应用程序的代码。
示例28-2 打开文件选择器以进行单个和多个选择
import java.awt.Desktop; import java.io.File; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; public final class FileChooserSample extends Application { private final Desktop desktop = Desktop.getDesktop(); @Override public void start(final Stage stage) { stage.setTitle("文件选择器示例"); final FileChooser fileChooser = new FileChooser(); final Button openButton = new Button("打开图片..."); final Button openMultipleButton = new Button("打开图片..."); openButton.setOnAction( (final ActionEvent e) -> { File file = fileChooser.showOpenDialog(stage); if (file != null) { openFile(file); } }); openMultipleButton.setOnAction( (final ActionEvent e) -> { List<File> list = fileChooser.showOpenMultipleDialog(stage); if (list != null) { list.stream().forEach((file) -> { openFile(file); }); } }); final GridPane inputGridPane = new GridPane(); GridPane.setConstraints(openButton, 0, 0); GridPane.setConstraints(openMultipleButton, 1, 0); inputGridPane.setHgap(6); inputGridPane.setVgap(6); inputGridPane.getChildren().addAll(openButton, openMultipleButton); final Pane rootGroup = new VBox(12); rootGroup.getChildren().addAll(inputGridPane); rootGroup.setPadding(new Insets(12, 12, 12, 12)); stage.setScene(new Scene(rootGroup)); stage.show(); } public static void main(String[] args) { Application.launch(args); } private void openFile(File file) { EventQueue.invokeLater(() -> { try { desktop.open(file); } catch (IOException ex) { Logger.getLogger(FileChooserSample. class.getName()). log(Level.SEVERE, null, ex); } }); } }
在示例28-2中,"打开图片"按钮允许用户打开一个文件选择器进行单个选择,而"打开图片"按钮允许用户打开一个文件选择器进行多个选择。这两个按钮的setOnAction
方法几乎相同,唯一的区别在于用于调用FileChooser
的方法。
-
showOpenDialog
方法显示一个新的文件打开对话框,用户可以选择一个文件。该方法返回指定用户选择的文件或null
(如果未进行选择)的值。 -
showOpenMultipleDialog
方法显示一个新的文件打开对话框,用户可以选择多个文件。该方法返回指定用户选择的文件列表或null
(如果未进行选择)的值。返回的列表不能被修改,并在每次修改尝试时抛出UnsupportedOperationException
。
这两个方法在显示的打开对话框窗口被关闭之前不会返回结果(换句话说,直到用户提交或取消选择)。
当您编译和运行FileChooserSample应用程序时,会产生如图28-5所示的窗口。
当您单击任一按钮时,将显示如图28-6所示的对话框窗口。打开的文件选择对话框窗口显示的位置是您操作系统的默认位置。
FileChooserSample应用程序的用户可以导航到包含图片的目录并选择一张图片。选择文件后,它将使用java.awt.Desktop
类的open
方法打开关联的应用程序。示例代码通过使用desktop.open(file);
来实现这一点。
注意:
Desktop
类的可用性取决于平台。请参考API 文档了解有关 Desktop
类的更多信息。您还可以使用 isDesktopSupported()
方法来检查系统是否支持它。
您可以通过将文件选择器目录设置为包含图片的特定目录来改善此应用程序的用户体验。
配置文件选择器
您可以通过设置FileChooser
对象的initialDirectory
和title
属性来配置文件选择对话框窗口。示例28-3展示了如何指定初始目录和合适的标题来预览和打开图片。
示例28-3 设置初始目录和窗口标题
import java.awt.Desktop; import java.io.File; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; public final class FileChooserSample extends Application { private final Desktop desktop = Desktop.getDesktop(); @Override public void start(final Stage stage) { stage.setTitle("文件选择器示例"); final FileChooser fileChooser = new FileChooser(); final Button openButton = new Button("打开图片..."); final Button openMultipleButton = new Button("打开多张图片..."); openButton.setOnAction( (final ActionEvent e) -> { configureFileChooser(fileChooser); File file = fileChooser.showOpenDialog(stage); if (file != null) { openFile(file); } }); openMultipleButton.setOnAction( (final ActionEvent e) -> { configureFileChooser(fileChooser); List<File> list = fileChooser.showOpenMultipleDialog(stage); if (list != null) { list.stream().forEach((file) -> { openFile(file); }); } }); final GridPane inputGridPane = new GridPane(); GridPane.setConstraints(openButton, 0, 0); GridPane.setConstraints(openMultipleButton, 1, 0); inputGridPane.setHgap(6); inputGridPane.setVgap(6); inputGridPane.getChildren().addAll(openButton, openMultipleButton); final Pane rootGroup = new VBox(12); rootGroup.getChildren().addAll(inputGridPane); rootGroup.setPadding(new Insets(12, 12, 12, 12)); stage.setScene(new Scene(rootGroup)); stage.show(); } public static void main(String[] args) { Application.launch(args); } private static void configureFileChooser(final FileChooser fileChooser){ fileChooser.setTitle("查看图片"); fileChooser.setInitialDirectory( new File(System.getProperty("user.home")) ); } private void openFile(File file) { EventQueue.invokeLater(() -> { try { desktop.open(file); } catch (IOException ex) { Logger.getLogger(FileChooserSample. class.getName()). log(Level.SEVERE, null, ex); } }); } }
configureFileChooser
方法设置了“查看图片”标题和用户主目录下的“我的图片”子目录的路径。当你编译并运行FileChooserSample,并点击其中一个按钮时,会出现如图28-7所示的文件选择器。
你也可以让用户通过使用DirectoryChooser
类来指定目标目录。在示例28-4中所示的代码片段中,点击browseButton
会调用directoryChooser.showDialog
方法。
示例28-4 使用DirectoryChooser类
final Button browseButton = new Button("..."); browseButton.setOnAction( (final ActionEvent e) -> { final DirectoryChooser directoryChooser new DirectoryChooser(); final File selectedDirectory = directoryChooser.showDialog(stage); if (selectedDirectory != null) { selectedDirectory.getAbsolutePath(); } });
选择完成后,你可以将相应的值分配给文件选择器,如下所示:fileChooser.setInitialDirectory(selectedDirectory);
。
设置扩展过滤器
作为下一个配置选项,您可以设置扩展过滤器来确定在文件选择器中打开哪些文件,如示例28-5所示。
示例28-5 设置图像类型过滤器
import java.awt.Desktop; import java.io.File; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; public final class FileChooserSample extends Application { private final Desktop desktop = Desktop.getDesktop(); @Override public void start(final Stage stage) { stage.setTitle("文件选择器示例"); final FileChooser fileChooser = new FileChooser(); final Button openButton = new Button("打开图片..."); final Button openMultipleButton = new Button("打开多张图片..."); openButton.setOnAction( (final ActionEvent e) -> { configureFileChooser(fileChooser); File file = fileChooser.showOpenDialog(stage); if (file != null) { openFile(file); } }); openMultipleButton.setOnAction( (final ActionEvent e) -> { configureFileChooser(fileChooser); List<File> list = fileChooser.showOpenMultipleDialog(stage); if (list != null) { list.stream().forEach((file) -> { openFile(file); }); } }); final GridPane inputGridPane = new GridPane(); GridPane.setConstraints(openButton, 0, 1); GridPane.setConstraints(openMultipleButton, 1, 1); inputGridPane.setHgap(6); inputGridPane.setVgap(6); inputGridPane.getChildren().addAll(openButton, openMultipleButton); final Pane rootGroup = new VBox(12); rootGroup.getChildren().addAll(inputGridPane); rootGroup.setPadding(new Insets(12, 12, 12, 12)); stage.setScene(new Scene(rootGroup)); stage.show(); } public static void main(String[] args) { Application.launch(args); } private static void configureFileChooser( final FileChooser fileChooser) { fileChooser.setTitle("查看图片"); fileChooser.setInitialDirectory( new File(System.getProperty("user.home")) ); fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("所有图片", "*.*"), new FileChooser.ExtensionFilter("JPG", "*.jpg"), new FileChooser.ExtensionFilter("PNG", "*.png") ); } private void openFile(File file) { EventQueue.invokeLater(() -> { try { desktop.open(file); } catch (IOException ex) { Logger.getLogger(FileChooserSample. class.getName()). log(Level.SEVERE, null, ex); } }); } }
在示例28-5中,您使用FileChooser.ExtensionFilter
设置了一个扩展过滤器,用于定义文件选择的以下选项:所有图片、JPG和PNG。
当您编译并运行来自示例28-5的FileChooserSample代码,并点击其中一个按钮时,扩展过滤器将出现在文件选择器窗口中。如果用户选择了JPG,则文件选择器只显示JPG类型的图片。在我的图片目录中选择JPG图片的瞬间被捕获在图28-8中。
保存文件
除了打开和过滤文件外,FileChooser
API还提供了让用户为应用程序保存文件指定文件名(以及文件在文件系统中的位置)的功能。 FileChooser
类的showSaveDialog
方法打开一个保存对话框窗口。与其他显示对话框方法一样,showSaveDialog
方法返回用户选择的文件,如果没有进行选择,则返回null
。
在菜单示例中,代码片段显示了一个上下文菜单的另一个项目,该项目将显示的图像保存在文件系统中。
示例28-6 使用FileChooser类保存图像
MenuItem cmItem2 = new MenuItem("保存图像"); cmItem2.setOnAction((ActionEvent e) -> { FileChooser fileChooser1 = new FileChooser(); fileChooser1.setTitle("保存图像"); System.out.println(pic.getId()); File file = fileChooser1.showSaveDialog(stage); if (file != null) { try { ImageIO.write(SwingFXUtils.fromFXImage(pic.getImage(), null), "png", file); } catch (IOException ex) { System.out.println(ex.getMessage()); } } });
将示例28-6添加到MenuSample应用程序中(在应用程序文件中找到源代码),编译并运行它,您将启用保存图像菜单项,如图28-9所示。
用户选择保存图像项目后,将显示如图28-10所示的保存图像窗口。
保存图像窗口对应于保存对话框窗口的典型用户体验:用户需要选择目标目录,输入保存文件的名称,然后点击保存。
相关API文档