如何使用编辑窗格和文本窗格
原文:
docs.oracle.com/javase/tutorial/uiswing/components/editorpane.html
两个 Swing 类支持样式文本:JEditorPane及其子类JTextPane。JEditorPane类是 Swing 样式文本组件的基础,并提供了一种机制,通过该机制您可以为自定义文本格式添加支持。如果您需要无样式文本,请改用文本区域。
运行 TextSamplerDemo 可以看到编辑窗格和文本窗格的使用。以下是TextSamplerDemo示例的图片。
单击“启动”按钮以使用Java™ Web Start运行 TextSamplerDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
TextSamplerDemo示例仅仅是展示编辑窗格和文本窗格功能的开始。然而,右上角的编辑窗格展示了一个方便易用的功能:它显示从 URL 加载的不可编辑的帮助信息。右下角的文本窗格演示了您可以轻松地将图像甚至组件直接嵌入文本窗格中。
注意:
如果您需要一个完整的帮助系统,请查看javahelp项目。
Swing 文本 API 功能强大且庞大,我们可以专门撰写一本书来介绍如何使用编辑窗格和文本窗格。本节介绍它们的功能,提供使用建议,并指向其他信息来源。
- 使用编辑窗格显示来自 URL 的文本
- 编辑窗格 vs. 文本窗格
- 使用文本窗格的示例
- 编辑窗格和文本窗格 API
- 使用编辑窗格和文本窗格的示例
使用编辑窗格显示来自 URL 的文本
在不了解 Swing 文本系统的情况下,您可以完成的任务之一是显示来自 URL 的文本。以下是TextSamplerDemo.java中创建的一个不可编辑的编辑窗格,用于显示使用 HTML 标记格式化的文本的代码。
JEditorPane editorPane = new JEditorPane(); editorPane.setEditable(false); java.net.URL helpURL = TextSamplerDemo.class.getResource( "TextSamplerDemoHelp.html"); if (helpURL != null) { try { editorPane.setPage(helpURL); } catch (IOException e) { System.err.println("Attempted to read a bad URL: " + helpURL); } } else { System.err.println("Couldn't find file: TextSamplerDemoHelp.html"); } //Put the editor pane in a scroll pane. JScrollPane editorScrollPane = new JScrollPane(editorPane); editorScrollPane.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); editorScrollPane.setPreferredSize(new Dimension(250, 145)); editorScrollPane.setMinimumSize(new Dimension(10, 10));
代码使用默认构造函数创建编辑窗格,然后调用setEditable(false)以防止用户编辑文本。接下来,代码创建URL对象,并使用它调用setPage方法。
setPage方法打开 URL 指向的资源,并确定文本的格式(在示例中为 HTML)。如果已知文本格式,编辑窗格将使用在 URL 找到的文本进行初始化。标准编辑窗格可以理解纯文本、HTML 和 RTF。请注意,页面可能会异步加载,这会使 GUI 保持响应性,但意味着您不应该指望在调用setPage返回后数据已完全加载。
编辑窗格与文本窗格
要使用编辑窗格和文本窗格,您需要了解文本系统,该系统在文本组件功能中有描述。关于编辑窗格和文本窗格的几个事实分散在该部分中。在这里,我们再次列出这些事实并提供更多细节。这里的信息应该帮助您了解编辑窗格和文本窗格之间的区别,以及何时使用哪种。
- 通过
setPage方法,可以轻松地从 URL 加载文本到编辑窗格或文本窗格中。JEditorPane类还提供了构造函数,让您可以从 URL 初始化编辑窗格。JTextPane类没有这样的构造函数。参见使用编辑窗格显示来自 URL 的文本的示例,该示例使用此功能加载一个不可编辑的编辑窗格,其中包含 HTML 格式的文本。
使用setPage方法时要注意文档和编辑器工具包可能会发生变化。例如,如果编辑窗格包含纯文本(默认情况下),而您将其加载为 HTML,则文档将更改为HTMLDocument实例,编辑器工具包将更改为HTMLEditorKit实例。如果您的程序使用setPage方法,请确保调整代码以适应窗格文档和编辑器工具包实例的可能更改(在新文档上重新注册文档监听器等)。 - 默认情况下,编辑窗格知道如何读取、写入和编辑纯文本、HTML 和 RTF 文本。文本窗格继承了这种能力,但施加了一定的限制。文本窗格要求其文档实现
StyledDocument接口。HTMLDocument和RTFDocument都是StyledDocuments,因此在文本窗格中 HTML 和 RTF 可以正常工作。但是,如果您将文本窗格加载为纯文本,则文本窗格的文档不是您可能期望的PlainDocument,而是DefaultStyledDocument。 - 要支持自定义文本格式,需要实现一个可以读取、写入和编辑该格式文本的编辑器工具包。然后调用
registerEditorKitForContentType方法将您的工具包注册到JEditorPane类中。通过这种方式注册编辑器工具包,程序中的所有编辑窗格和文本窗格都能够读取、写入和编辑新格式。但是,如果新的编辑器工具包不是StyledEditorKit,文本窗格将不支持新格式。 - 如前所述,文本窗格需要其文档实现
StyledDocument接口。Swing 文本包提供了这个接口的默认实现,DefaultStyledDocument,这是文本窗格默认使用的文档。文本窗格还需要其编辑器工具包是StyledEditorKit的一个实例(或子类)。请注意,StyleEditorKit的read和write方法适用于纯文本。 - 通过它们的样式文档和样式编辑器工具包,文本窗格提供对命名样式和逻辑样式的支持。
JTextPane类本身包含许多用于处理样式的方法,这些方法只是调用其文档或编辑器工具包中的方法。 - 通过
JTextPane类提供的 API,您可以在文本窗格中嵌入图像和组件。您也可以在编辑窗格中嵌入图像,但只能通过在 HTML 或 RTF 文件中包含图像来实现。
使用文本窗格的示例
这是TextSamplerDemo示例中创建和初始化文本窗格的代码。
String[] initString = { /* ... * fill array with initial text * ... */ }; String[] initStyles = { /* ... * fill array with names of styles * ... */ }; JTextPane textPane = new JTextPane(); StyledDocument doc = textPane.getStyledDocument(); addStylesToDocument(doc); //Load the text pane with styled text. try { for (int i=0; i < initString.length; i++) { doc.insertString(doc.getLength(), initString[i], doc.getStyle(initStyles[i])); } } catch (BadLocationException ble) { System.err.println("Couldn't insert initial text into text pane."); }
简而言之,这段代码将初始文本硬编码到一个数组中,并创建并将几个样式 — 表示不同段落和字符格式的对象 — 硬编码到另一个数组中。接下来,代码循环遍历这些数组,将文本插入文本窗格,并指定要用于插入文本的样式。
虽然这是一个有趣的例子,简洁地展示了JTextPane的几个特性,但“现实世界”中的程序不太可能以这种方式初始化文本窗格。相反,程序会使用编辑窗格保存文档,然后再用它来初始化文本窗格。
编辑窗格和文本窗格 API
本节列出了与文本和编辑窗格相关的一些 API。许多JEditorPane及其子类JTextPane最有用的方法都是从JTextComponent类继承的。您可以在文本组件 API 中找到JTextComponent的 API 表。还请参阅 The JComponent Class,其中描述了从JComponent继承的 API。
JEditorPane 用于显示来自 URL 的文本的 API
| 方法或构造函数 | 描述 |
| JEditorPane(URL) JEditorPane(String) | 创建一个加载指定 URL 文本的编辑窗格。 |
| setPage(URL) setPage(String) | 使用指定 URL 加载编辑窗格(或文本窗格)中的文本。 |
| URL getPage() | 获取编辑窗格(或文本窗格)当前页面的 URL。 |
JTextPane API
| 方法或构造函数 | 描述 |
| JTextPane() JTextPane(StyledDocument) | 创建一个文本窗格。可选参数指定文本窗格的模型。 |
| StyledDocument getStyledDocument setStyledDocument(StyledDocument) | 获取或设置文本窗格的模型。 |
使用文本窗格和编辑窗格的示例
要开始使用文本,您可能希望运行这些程序并检查它们的代码,找到与您想要做的类似的内容。
| 示例 | 描述位置 | 备注 |
TextSamplerDemo |
使用文本组件 | 使用每个 Swing 文本组件。 |
TextComponentDemo |
文本组件特性 | 提供一个定制的文本窗格。展示了许多文本组件特性,如撤销和重做,文档过滤器,文档监听器,插入符位置变化监听器,以及如何将编辑操作与菜单和快捷键关联起来。 |
TreeDemo |
如何使用树形结构 | 使用编辑窗格显示从 HTML 文件加载的帮助信息。 |
学习如何在 JavaFX 中编辑 HTML 文本,参考使用 JavaFX UI 控件:HTML 编辑器 教程。
如何使用文件选择器
原文:
docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html
文件选择器提供了一个用于浏览文件系统的 GUI,然后从列表中选择文件或目录,或输入文件或目录的名称。要显示文件选择器,通常使用JFileChooser API 显示包含文件选择器的模态对话框。另一种呈现文件选择器的方法是将JFileChooser的实例添加到容器中。
注意:
如果您打算将程序作为沙箱 Java Web Start 应用程序进行分发,则应使用 JNLP API 提供的文件服务,而不是使用JFileChooser API。这些服务 — FileOpenService 和 FileSaveService — 不仅提供了在受限环境中选择文件的支持,还负责实际打开和保存文件。使用这些服务的示例在 JWSFileChooserDemo 中。有关使用 JNLP API 的文档可以在 Java Web Start 课程中找到。
单击“启动”按钮以使用Java™ Web Start运行 JWSFileChooserDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
在使用JWSFileChooserDemo示例时,请注意不要丢失所需的文件。每当单击保存按钮并选择现有文件时,此演示会弹出“文件已存在”对话框,并要求替换文件。接受请求会覆盖文件。
本节的其余部分讨论如何使用JFileChooser API。JFileChooser对象仅呈现用于选择文件的 GUI。您的程序负责处理所选文件,例如打开或保存文件。请参考基本 I/O 获取有关如何读取和写入文件的信息。
JFileChooser API 使打开和保存对话框变得简单。外观和感觉的类型决定了这些标准对话框的外观以及它们的区别。在 Java 外观和感觉中,保存对话框看起来与打开对话框相同,除了对话框窗口上的标题和批准操作的按钮上的文本不同。这是 Java 外观和感觉中标准打开对话框的图片:
这是一个名为FileChooserDemo的应用程序的图片,它会弹出一个打开对话框和一个保存对话框。
试一试:
- 编译并运行示例,参考示例索引。
- 点击“打开文件”按钮。在文件选择器中浏览,选择一个文件,然后点击对话框的“打开”按钮。
- 使用“保存文件”按钮来弹出保存对话框。尝试使用文件选择器上的所有控件。
- 在源文件
FileChooserDemo.java中,将文件选择模式更改为仅目录模式。(搜索DIRECTORIES_ONLY并取消注释包含它的行。)然后重新编译并运行示例。您只能看到并选择目录,而不能选择普通文件。
弹出标准打开对话框只需要两行代码:
//Create a file chooser final JFileChooser fc = new JFileChooser(); ... *//In response to a button click:* int returnVal = fc.showOpenDialog(*aComponent*);
showOpenDialog方法的参数指定对话框的父组件。父组件影响对话框的位置以及对话框所依赖的框架。例如,Java 外观将对话框直接放在父组件上。如果父组件在一个框架中,则对话框依赖于该框架。当框架最小化时,此对话框消失,当框架最大化时重新出现。
默认情况下,之前未显示过的文件选择器会显示用户主目录中的所有文件。您可以使用JFileChooser的其他构造函数之一指定文件选择器的初始目录,或者可以使用setCurrentDirectory方法设置目录。
调用showOpenDialog出现在“打开文件”按钮的动作监听器的actionPerformed方法中:
public void actionPerformed(ActionEvent e) { //Handle open button action. if (e.getSource() == openButton) { int returnVal = fc.showOpenDialog(FileChooserDemo.this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); //This is where a real application would open the file. log.append("Opening: " + file.getName() + "." + newline); } else { log.append("Open command cancelled by user." + newline); } } ... }
show*Xxx*Dialog方法返回一个整数,指示用户是否选择了文件。根据文件选择器的使用方式,通常只需检查返回值是否为APPROVE_OPTION,然后不更改任何其他值。要获取所选文件(或目录,如果设置文件选择器以允许选择目录),请在文件选择器上调用getSelectedFile方法。此方法返回一个File的实例。
该示例获取文件的名称并在日志消息中使用。你可以在File对象上调用其他方法,比如getPath、isDirectory或exists来获取有关文件的信息。你也可以调用其他方法,比如delete和rename来以某种方式更改文件。当然,你可能还想通过使用 Java 平台提供的读取器或写入器类之一来打开或保存文件。有关使用读取器和写入器将数据读取和写入文件系统的信息,请参阅基本 I/O。
示例程序使用相同的JFileChooser类实例来显示标准保存对话框。这次程序调用showSaveDialog:
int returnVal = fc.showSaveDialog(FileChooserDemo.this);
通过使用相同的文件选择器实例来显示其打开和保存对话框,程序获得以下好处:
- 选择器在使用之间记住当前目录,因此打开和保存版本会自动共享相同的当前目录。
- 你只需自定义一个文件选择器,自定义将应用于打开和保存版本。
最后,示例程序中有被注释掉的代码行,让你可以更改文件选择模式。例如,以下代码行使文件选择器只能选择目录,而不能选择文件:
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
另一种可能的选择模式是FILES_AND_DIRECTORIES。默认值是FILES_ONLY。以下图片显示了一个打开对话框,文件选择模式设置为DIRECTORIES_ONLY。请注意,至少在 Java 外观中,只有目录可见,而不是文件。
如果你想为除了打开或保存之外的任务创建一个文件选择器,或者想要自定义文件选择器,请继续阅读。我们将讨论以下主题:
- 另一个示例:FileChooserDemo2
- 为自定义任务使用文件选择器
- 过滤文件列表
- 自定义文件视图
- 提供附件组件
- 文件选择器 API
- 使用文件选择器的示例
另一个示例:FileChooserDemo2
让我们看看FileChooserDemo2示例,这是前一个演示程序的修改版本,使用了更多的JFileChooserAPI。该示例使用了多种方式自定义的文件选择器。与原始示例一样,用户通过按下按钮调用文件选择器。这是文件选择器的图片:
如图所示,此文件选择器已经为一个特殊任务(附件)进行了定制,提供了一个用户可选择的文件过滤器(仅图像),对图像文件使用了特殊的文件视图,并具有一个附件组件,显示当前选定图像文件的缩略图。
本节的其余部分向您展示了创建和自定义此文件选择器的代码。请参阅示例索引以获取此示例所需的所有文件的链接。
使用文件选择器执行自定义任务
正如您所见,JFileChooser类提供了showOpenDialog方法用于显示打开对话框,以及showSaveDialog方法用于显示保存对话框。
该类还有另一个方法showDialog,用于在对话框中显示用于自定义任务的文件选择器。在 Java 外观中,此对话框与其他文件选择器对话框之间唯一的区别是对话框窗口上的标题和批准按钮上的标签。以下是从FileChooserDemo2中调用的代码,用于打开附件任务的文件选择器对话框:
JFileChooser fc = new JFileChooser(); int returnVal = fc.showDialog(FileChooserDemo2.this, "Attach");
showDialog方法的第一个参数是对话框的父组件。第二个参数是一个String对象,提供对话框窗口的标题和批准按钮的标签。
再次强调,文件选择器不会对所选文件执行任何操作。程序负责实现文件选择器创建的自定义任务。
过滤文件列表
默认情况下,文件选择器显示它检测到的所有文件和目录,除了隐藏文件。程序可以向文件选择器应用一个或多个文件过滤器,以便选择器仅显示一些文件。文件选择器调用过滤器的accept方法来确定是否应显示该文件。文件过滤器根据文件类型、大小、所有权等标准接受或拒绝文件。过滤器影响文件选择器显示的文件列表。用户可以输入任何文件的名称,即使它没有显示。
JFileChooser支持三种不同类型的过滤。这些过滤器按照列出的顺序进行检查。例如,应用程序控制的过滤器只能看到内置过滤器接受的文件。
内置过滤
通过文件选择器上的特定方法调用来设置过滤。目前,唯一可用的内置过滤器是用于隐藏文件的,例如在 UNIX 系统上以句点(.)开头的文件。默认情况下,不显示隐藏文件。调用setFileHidingEnabled(false)以显示隐藏文件。
应用程序控制的过滤
应用程序确定显示哪些文件。创建FileFilter的自定义子类,实例化它,并将实例用作setFileFilter方法的参数。安装的过滤器显示在用户可选择的过滤器列表中。文件选择器仅显示过滤器接受的文件。
用户可选择的过滤
文件选择器 GUI 提供了用户可以选择的过滤器列表。当用户选择一个过滤器时,文件选择器只显示被该过滤器接受的文件。FileChooserDemo2 将一个自定义文件过滤器添加到用户可选择的过滤器列表中:
fc.addChoosableFileFilter(new ImageFilter());
默认情况下,用户可选择的过滤器列表包括“接受所有”过滤器,该过滤器使用户可以查看所有非隐藏文件。以下示例使用以下代码禁用“接受所有”过滤器:
fc.setAcceptAllFileFilterUsed(false);
我们的自定义文件过滤器在 ImageFilter.java 中实现,是 FileFilter 的子类。ImageFilter 类实现了 getDescription 方法,返回“Just Images”——一个要放在用户可选择过滤器列表中的字符串。ImageFilter 还实现了 accept 方法,以便接受所有目录和具有 .png、.jpg、.jpeg、.gif、.tif 或 .tiff 文件扩展名的文件。
public boolean accept(File f) { if (f.isDirectory()) { return true; } String extension = Utils.getExtension(f); if (extension != null) { if (extension.equals(Utils.tiff) || extension.equals(Utils.tif) || extension.equals(Utils.gif) || extension.equals(Utils.jpeg) || extension.equals(Utils.jpg) || extension.equals(Utils.png)) { return true; } else { return false; } } return false; }
通过接受所有目录,此过滤器允许用户在文件系统中导航。如果从此方法中省略了粗体行,则用户将受限于选择器初始化的目录。
前面的代码示例使用了 getExtension 方法和几个字符串常量,来自 Utils.java,如下所示:
public class Utils { public final static String jpeg = "jpeg"; public final static String jpg = "jpg"; public final static String gif = "gif"; public final static String tiff = "tiff"; public final static String tif = "tif"; public final static String png = "png"; /* * Get the extension of a file. */ public static String getExtension(File f) { String ext = null; String s = f.getName(); int i = s.lastIndexOf('.'); if (i > 0 && i < s.length() - 1) { ext = s.substring(i+1).toLowerCase(); } return ext; } }
自定义文件视图
在 Java 外观中,选择器的列表显示每个文件的名称,并显示一个小图标,表示文件是真实文件还是目录。您可以通过创建 FileView 的自定义子类并将该类的实例用作 setFileView 方法的参数来自定义此文件视图。该示例使用一个自定义类的实例,实现在 ImageFileView.java 中,作为文件选择器的文件视图。
fc.setFileView(new ImageFileView());
ImageFileView 类为先前描述的图像过滤器接受的每种类型的图像显示不同的图标。
ImageFileView 类重写了 FileView 中定义的五个抽象方法,如下所示。
String getTypeDescription(File f)
返回文件类型的描述。这是 ImageFileView 对此方法的实现:
public String getTypeDescription(File f) { String extension = Utils.getExtension(f); String type = null; if (extension != null) { if (extension.equals(Utils.jpeg) || extension.equals(Utils.jpg)) { type = "JPEG Image"; } else if (extension.equals(Utils.gif)){ type = "GIF Image"; } else if (extension.equals(Utils.tiff) || extension.equals(Utils.tif)) { type = "TIFF Image"; } else if (extension.equals(Utils.png)){ type = "PNG Image"; } } return type; }
Icon getIcon(File f)
返回表示文件或其类型的图标。这是 ImageFileView 对此方法的实现:
public Icon getIcon(File f) { String extension = Utils.getExtension(f); Icon icon = null; if (extension != null) { if (extension.equals(Utils.jpeg) || extension.equals(Utils.jpg)) { icon = jpgIcon; } else if (extension.equals(Utils.gif)) { icon = gifIcon; } else if (extension.equals(Utils.tiff) || extension.equals(Utils.tif)) { icon = tiffIcon; } else if (extension.equals(Utils.png)) { icon = pngIcon; } } return icon; }
String getName(File f)
返回文件的名称。大多数此方法的实现应返回 null,表示外观和感觉应该自行解决。另一个常见的实现返回 f.getName()。
String getDescription(File f)
返回文件的描述。意图是更具体地描述单个文件。此方法的常见实现返回 null,表示外观和感觉应该自行解决。
Boolean isTraversable(File f)
返回目录是否可遍历。大多数此方法的实现应返回null以指示外观和感觉应该解决这个问题。一些应用程序可能希望阻止用户进入某种类型的目录,因为它代表一个复合文档。isTraversable方法永远不应为非目录返回true。
提供一个附件组件
FileChooserDemo2中的自定义文件选择器具有一个附件组件。如果当前选择的项目是 PNG、JPEG、TIFF 或 GIF 图像,则附件组件显示图像的缩略图草图。否则,附件组件为空。除了预览器,附件组件最常见的用途可能是一个面板,上面有更多控件,如切换功能的复选框。
示例调用setAccessory方法来建立ImagePreview类的一个实例,实现在ImagePreview.java中,作为选择器的附件组件:
fc.setAccessory(new ImagePreview(fc));
任何继承自JComponent类的对象都可以是附件组件。组件应具有在文件选择器中看起来不错的首选大小。
当用户在列表中选择项目时,文件选择器会触发属性更改事件。具有附件组件的程序必须注册以接收这些事件,以便在选择更改时更新附件组件。在示例中,ImagePreview对象本身注册了这些事件。这样可以将所有与附件组件相关的代码放在一个类中。
这是示例中propertyChange方法的实现,当触发属性更改事件时调用该方法:
//*where member variables are declared* File file = null; ... public void propertyChange(PropertyChangeEvent e) { boolean update = false; String prop = e.getPropertyName(); //If the directory changed, don't show an image. if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) { file = null; update = true; //If a file became selected, find out which one. } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) { file = (File) e.getNewValue(); update = true; } //Update the preview accordingly. if (update) { thumbnail = null; if (isShowing()) { loadImage(); repaint(); } } }
如果SELECTED_FILE_CHANGED_PROPERTY是更改的属性,则此方法从文件选择器获取一个File对象。loadImage和repaint方法使用File对象加载图像并重绘附件组件。
Java 中文官方教程 2022 版(十六)(2)https://developer.aliyun.com/article/1486471