Java 中文官方教程 2022 版(十六)
如何使用编辑窗格和文本窗格
原文:
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对象加载图像并重绘附件组件。
文件选择器 API
使用文件选择器的 API 分为以下几类:
- 
创建和显示文件选择器 
- 
选择文件和目录 
- 
导航文件选择器的列表 
- 
自定义文件选择器 
创建和显示文件选择器
| 方法或构造函数 | 目的 | 
|---|
| JFileChooser() JFileChooser(File)
JFileChooser(String) | 创建一个文件选择器实例。当存在File和String参数时,提供初始目录。 |
| int showOpenDialog(Component) int showSaveDialog(Component)
int showDialog(Component, String) | 显示包含文件选择器的模态对话框。如果用户批准操作,则这些方法返回APPROVE_OPTION,如果用户取消操作,则返回CANCEL_OPTION。另一个可能的返回值是ERROR_OPTION,表示发生了意外错误。
选择文件和目录
| 方法 | 目的 | 
|---|---|
| void setSelectedFile(File) File getSelectedFile() | 设置或获取当前选定的文件或(如果启用了目录选择)目录。 | 
| void setSelectedFiles(File[]) File[] getSelectedFiles() | 设置或获取当前选定的文件(如果文件选择器设置为允许多选)。 | 
| void setFileSelectionMode(int) void getFileSelectionMode()
boolean isDirectorySelectionEnabled() | 检查目录选择是否已启用。
boolean isFileSelectionEnabled() | 设置或获取文件选择模式。可接受的值为FILES_ONLY(默认值)、DIRECTORIES_ONLY和FILES_AND_DIRECTORIES。根据当前选择模式解释目录或文件是否可选择。
| void setMultiSelectionEnabled(boolean) boolean isMultiSelectionEnabled() | 设置或解释是否可以一次选择多个文件。默认情况下,用户只能选择一个文件。 | 
|---|---|
| void setAcceptAllFileFilterUsed(boolean) boolean isAcceptAllFileFilterUsed() | 设置或获取是否在可选择的过滤器列表中使用 AcceptAll文件过滤器作为可接受的选择;默认值为true。 | 
| Dialog createDialog(Component) | 给定一个父组件,创建并返回一个包含此文件选择器的新对话框,依赖于父窗口的框架,并居中于父窗口。 | 
导航文件选择器的列表
| 方法 | 目的 | 
|---|---|
| void ensureFileIsVisible(File) | 滚动文件选择器的列表,使指定的文件可见。 | 
| void setCurrentDirectory(File) File getCurrentDirectory() | 设置或获取在文件选择器的列表中显示的目录。 | 
| void changeToParentDirectory() | 将列表更改为显示当前目录的父目录。 | 
| void rescanCurrentDirectory() | 检查文件系统并更新选择器的列表。 | 
| void setDragEnabled(boolean) boolean getDragEnabled() | 设置或获取确定是否启用自动拖放处理的属性。有关更多详细信息,请参阅拖放和数据传输。 | 
自定义文件选择器
| 方法 | 目的 | 
|---|---|
| void setAccessory(javax.swing.JComponent) JComponent getAccessory() | 设置或获取文件选择器的附件组件。 | 
| void setFileFilter(FileFilter) FileFilter getFileFilter() | 设置或获取文件选择器的主要文件过滤器。 | 
| void setFileView(FileView) FileView getFileView() | 设置或获取选择器的文件视图。 | 
| FileFilter[] getChoosableFileFilters() void addChoosableFileFilter(FileFilter) | 设置、获取或修改可供用户选择的文件过滤器列表。 |
boolean removeChoosableFileFilter(FileFilter)
void resetChoosableFileFilters()
FileFilter getAcceptAllFileFilter() | 设置、获取或修改用户可选择的文件过滤器列表。 |
| void setFileHidingEnabled(boolean) boolean isFileHidingEnabled() | 设置或获取是否显示隐藏文件。 | 
|---|---|
| void setControlButtonsAreShown(boolean) boolean getControlButtonsAreShown() | 设置或获取指示文件选择器中是否显示“批准”和“取消”按钮的属性。默认情况下,此属性为 true。 | 
使用文件选择器的示例
这个表格展示了使用文件选择器的示例,并指向这些示例所描述的位置。
| 示例 | 描述位置 | 注释 | 
|---|---|---|
| FileChooserDemo | 这一部分 | 显示一个打开对话框和一个保存对话框。 | 
| FileChooserDemo2 | 这一部分 | 使用具有自定义过滤、自定义文件视图和附件组件的文件选择器。 | 
| JWSFileChooserDemo | 这一部分 | 使用 JNLP API 来打开和保存文件。 | 
如何使用格式化文本字段
原文:
docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html
格式化文本字段为开发人员提供了一种指定可以在文本字段中键入的有效字符集的方法。具体而言,JFormattedTextField类添加了一个格式化器和一个对象值到从JTextField类继承的特性中。格式化器将字段的值转换为其显示的文本,将文本转换为字段的值。
使用 Swing 提供的格式化器,您可以设置格式化文本字段以在本地化格式中输入日期和数字。另一种格式化器使您可以使用字符掩码来指定可以在字段中的每个位置键入的字符集。例如,您可以指定一个用于以特定格式输入电话号码的掩码,如(XX)X-XX-XX-XX-XX。
如果格式化文本字段的可能值具有明显的顺序,请改用微调器。微调器默认使用格式化文本字段,但添加了两个按钮,使用户可以在序列中选择一个值。
使用格式化文本字段的另一种选择或辅助方法是在字段上安装输入验证器。组件的输入验证器在组件几乎失去键盘焦点时被调用。输入验证器使您能够检查组件的值是否有效,并可选择更改它或阻止焦点转移。
此 GUI 使用格式化文本字段以四种不同格式显示数字。

试试这个:
- 
单击“启动”按钮以使用Java™ Web Start运行 FormattedTextFieldDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。 
- 
尝试不同的贷款金额、年利率(APR)和贷款期限。 请注意,只要您输入的文本有效,当您按 Enter 键或将焦点移出您正在编辑的字段时,月付款字段将更新。 
- 
在贷款金额字段中键入无效文本,如“abcd”,然后按 Enter 键。 月付款字段保持不变。当您从贷款金额字段移动焦点时,文本将恢复到字段的最后一个有效值。 
- 
在贷款金额字段中输入类似"2000abcd"这样边缘有效的文本,然后按 Enter 键。 尽管贷款金额字段仍显示 2000abcd,但月付款字段已更新。当您从贷款金额字段移开焦点时,它显示的文本会更新为其值的整洁格式,例如"2,000"。
您可以在FormattedTextFieldDemo.java中找到此程序的完整代码。此代码创建了第一个字段。
amountField = new JFormattedTextField(amountFormat);
amountField.setValue(new Double(amount));
amountField.setColumns(10);
amountField.addPropertyChangeListener("value", this);
...
amountFormat = NumberFormat.getNumberInstance();
用于创建amountField对象的构造函数接受一个java.text.Format参数。Format对象由字段的格式化程序用于将字段的值转换为文本,以及将文本转换为字段的值。
其余代码设置了amountField对象。setValue方法将字段的值属性设置为表示为Double对象的浮点数。setColumns方法,从JTextField类继承而来,提示字段的首选大小。调用addPropertyChangeListener方法为字段的值属性注册了一个侦听器,因此当用户更改贷款金额时,程序可以更新月付款字段。
本节的其余部分涵盖以下主题:
- 
创建和初始化格式化文本字段 
- 
设置和获取字段的值 
- 
指定格式 
- 
使用 MaskFormatter 
- 
指定格式化程序并使用格式化程序工厂 
本节不解释从JTextField类继承的 API。该 API 在如何使用文本字段中有描述。
创建和初始化格式化文本字段
以下代码创建并初始化了示例中的其余三个字段。
rateField = new JFormattedTextField(percentFormat);
rateField.setValue(new Double(rate));
rateField.setColumns(10);
rateField.addPropertyChangeListener("value", this);
numPeriodsField = new JFormattedTextField();
numPeriodsField.setValue(new Integer(numPeriods));
numPeriodsField.setColumns(10);
numPeriodsField.addPropertyChangeListener("value", this);
paymentField = new JFormattedTextField(paymentFormat);
paymentField.setValue(new Double(payment));
paymentField.setColumns(10);
paymentField.setEditable(false);
paymentField.setForeground(Color.red);
...
percentFormat = NumberFormat.getNumberInstance();
percentFormat.setMinimumFractionDigits(2);
paymentFormat = NumberFormat.getCurrencyInstance();
用于设置rateField对象的代码几乎与之前列出的其他字段的代码相同。唯一的区别在于格式略有不同,这要归功于代码percentFormat.setMinimumFractionDigits(2)。
用于创建numPeriodsField对象的代码没有显式设置格式或格式化程序。相反,它将值设置为Integer并启用字段使用Integer对象的默认格式化程序。之前两个字段的代码没有这样做,因为默认格式化程序不适用于Double对象。结果不是所需的。如何指定格式和格式化程序将在本节后面介绍。
付款字段与其他字段不同,因为它是不可编辑的,使用不同颜色的文本,并且没有属性更改侦听器。否则,它与其他字段相同。我们本可以选择使用文本字段或标签。无论使用哪种组件,我们仍然可以使用paymentFormat方法将付款金额解析为要显示的文本。
设置和获取字段的值
使用格式化文本字段时请记住以下内容:
格式化文本字段的文本和数值是两个不同的属性,而数值通常落后于文本。
文本属性由JTextField类定义。该属性始终反映字段显示的内容。数值属性由JFormattedTextField类定义,可能不会反映字段中显示的最新文本。当用户输入时,文本属性会更改,但数值属性直到更改被提交之前不会改变。
要更加精确,格式化文本字段的数值可以通过使用setValue方法或commitEdit方法来设置。setValue方法将数值设置为指定的参数。技术上,参数可以是任何Object,但格式化器需要能够将其转换为字符串。否则,文本字段不会显示任何实质性信息。
commitEdit方法将数值设置为格式化器确定由字段文本表示的任何对象。当发生以下情况之一时,commitEdit方法会自动调用:
- 
当用户在字段具有焦点时按 Enter 键。 
- 
默认情况下,当字段失去焦点时,例如,当用户按 Tab 键将焦点切换到另一个组件时。您可以使用 setFocusLostBehavior方法来指定字段失去焦点时的不同结果。
注意:
一些格式化器可能会不断更新数值,使失去焦点变得毫无意义,因为数值始终与文本指定的内容相同。
当您设置格式化文本字段的数值时,字段的文本会更新以反映数值。数值如何表示为文本取决于字段的格式化器。
请注意,虽然JFormattedTextField类从JTextField类继承了setText方法,但通常不会在格式化文本字段上调用setText方法。如果这样做,字段的显示会相应更改,但数值不会更新(除非字段的格式化器不断更新它)。
要获取格式化文本字段的当前数值,请使用getValue方法。如果需要,您可以在调用getValue之前调用commitEdit方法来确保数值反映文本内容。因为getValue方法返回一个Object,您需要将其转换为字段数值所使用的类型。例如:
Date enteredDate = (Date)dateField.getValue();
要检测格式化文本字段数值的更改,您可以在格式化文本字段上注册一个属性更改监听器,以监听“value”属性的更改。属性更改监听器取自FormattedTextFieldDemo示例:
*//The property change listener is registered on each
//field using code like this:
//    someField.addPropertyChangeListener("value", this);*
/** Called when a field's "value" property changes. */
public void propertyChange(PropertyChangeEvent e) {
    Object source = e.getSource();
    if (source == amountField) {
        amount = ((Number)amountField.getValue()).doubleValue();
    } else if (source == rateField) {
        rate = ((Number)rateField.getValue()).doubleValue();
    } else if (source == numPeriodsField) {
        numPeriods = ((Number)numPeriodsField.getValue()).intValue();
    }
    double payment = computePayment(amount, rate, numPeriods);
    paymentField.setValue(new Double(payment));
}
指定格式
Format类提供了一种格式化区域敏感信息(如日期和数字)的方法。从InternationalFormatter类继承的格式化程序,如DateFormatter和NumberFormatter类,使用Format对象在字段文本和值之间进行转换。您可以通过调用DateFormat或NumberFormat类中的工厂方法之一,或者使用SimpleDateFormat构造函数之一来获取Format对象。
注意:
第三个常用的格式化类MaskFormatter,不是从InternationalFormatter类继承的,也不使用格式。关于MaskFormatter的讨论请参见使用 MaskFormatter。
在创建Format对象时,您可以自定义某些格式方面,而通过特定于格式的 API 可以自定义其他方面。例如,继承自NumberFormat并经常由其工厂方法返回的DecimalFormat对象可以通过使用setMaximumFractionDigits和setNegativePrefix方法进行自定义。有关使用Format对象的信息,请参阅国际化教程的格式化部分。
将自定义格式与格式化文本字段关联的最简单方法是使用以Format作为参数的JFormattedTextField构造函数创建字段。您可以在前面创建amountField和rateField对象的代码示例中看到这种关联。
使用 MaskFormatter
MaskFormatter类实现了一个指定每个字段文本位置中哪些字符有效的格式化程序。例如,以下代码创建了一个允许用户输入五位邮政编码的MaskFormatter:
zipField = new JFormattedTextField(
                    createFormatter("#####"));
...
protected MaskFormatter createFormatter(String s) {
    MaskFormatter formatter = null;
    try {
        formatter = new MaskFormatter(s);
    } catch (java.text.ParseException exc) {
        System.err.println("formatter is bad: " + exc.getMessage());
        System.exit(-1);
    }
    return formatter;
}
你可以通过运行TextInputDemo来尝试上述代码的结果。点击启动按钮以使用Java™ Web Start运行 TextInputDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
程序的 GUI 被显示。

以下表格显示了您可以在格式化掩码中使用的字符:
| Character | 描述 | 
|---|---|
| # | 任何有效数字( Character.isDigit)。 | 
| ' (单引号) | 转义字符,用于转义任何特殊格式化字符。 | 
| U | 任何字符( Character.isLetter)。所有小写字母都映射为大写字母。 | 
| L | 任何字符( Character.isLetter)。所有大写字母都映射为小写字母。 | 
| A | 任何字符或数字( Character.isLetter或Character.isDigit)。 | 
| ? | 任何字符( Character.isLetter)。 | 
| * | 任何内容。 | 
| H | 任何十六进制字符(0-9,a-f 或 A-F)。 | 
指定格式化程序并使用格式化程序工厂
在指定格式化程序时,请记住每个格式化程序对象一次只能由一个格式化文本字段使用。每个字段应至少关联一个格式化程序,其中恰好有一个在任何时候被使用。
您可以通过几种方式指定要由格式化文本字段使用的格式化程序:
- 
使用带有 Format参数的JFormattedTextField构造函数。为字段自动创建一个使用指定格式的格式化程序。 
- 
使用带有 JFormattedTextField.AbstractFormatter参数的JFormattedTextField构造函数。指定的格式化程序用于字段。 
- 
设置没有指定格式、格式化程序或格式化程序工厂的格式化文本字段的值。 通过默认格式化程序工厂将格式化程序分配给字段,使用字段值的类型作为指南。如果值是 Date,则格式化程序是DateFormatter。如果值是Number,则格式化程序是NumberFormatter。其他类型会导致DefaultFormatter的实例。
- 
使格式化文本字段使用返回定制格式化程序对象的格式化程序工厂。 这是最灵活的方法。当您想要将多个格式化程序与字段关联或添加新类型的格式化程序以用于多个字段时,这是非常有用的。前一种用法的示例是解释用户以某种方式输入但以另一种方式显示值(当用户不输入时)的字段。后一种用法的示例是具有自定义类值的多个字段,例如, PhoneNumber。您可以设置字段使用返回电话号码的专门格式化程序的格式化程序工厂。
您可以通过使用接受格式化工厂参数的构造函数创建字段,或者通过在字段上调用setFormatterFactory方法来设置字段的格式化工厂。要创建格式化工厂,通常可以使用DefaultFormatterFactory类的实例。DefaultFormatterFactory对象使您能够指定在正在编辑值、未在编辑值或具有空值时返回的格式化程序。
以下图示显示了基于FormattedTextFieldDemo示例的应用程序,该应用程序使用格式化工厂为贷款金额和年利率字段设置多个编辑器。在用户编辑贷款金额时,不使用$字符,以便用户不必输入它。类似地,在用户编辑年利率字段时,不需要%字符。
点击“启动”按钮以使用Java™ Web Start运行 FormatterFactoryDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
 
 
以下代码创建了格式化程序,并通过使用DefaultFormatterFactory类的实例设置它们:
private double rate = .075;  //7.5 %
...
amountField = new JFormattedTextField(
                    new DefaultFormatterFactory(
                        new NumberFormatter(amountDisplayFormat),
                        new NumberFormatter(amountDisplayFormat),
                        new NumberFormatter(amountEditFormat)));
...
NumberFormatter percentEditFormatter =
        new NumberFormatter(percentEditFormat) {
    public String valueToString(Object o)
          throws ParseException {
        Number number = (Number)o;
        if (number != null) {
            double d = number.doubleValue() * 100.0;
            number = new Double(d);
        }
        return super.valueToString(number);
    }
    public Object stringToValue(String s)
           throws ParseException {
        Number number = (Number)super.stringToValue(s);
        if (number != null) {
            double d = number.doubleValue() / 100.0;
            number = new Double(d);
        }
        return number;
    }
};
rateField = new JFormattedTextField(
                     new DefaultFormatterFactory(
                        new NumberFormatter(percentDisplayFormat),
                        new NumberFormatter(percentDisplayFormat),
                        percentEditFormatter));
...
amountDisplayFormat = NumberFormat.getCurrencyInstance();
amountDisplayFormat.setMinimumFractionDigits(0);
amountEditFormat = NumberFormat.getNumberInstance();
percentDisplayFormat = NumberFormat.getPercentInstance();
percentDisplayFormat.setMinimumFractionDigits(2);
percentEditFormat = NumberFormat.getNumberInstance();
percentEditFormat.setMinimumFractionDigits(2);
粗体代码突出显示了对DefaultFormatterFactory构造函数的调用。构造函数的第一个参数指定用于格式化文本字段的默认格式化程序。第二个参数指定显示格式化程序,在字段没有焦点时使用。第三个参数指定编辑格式化程序,在字段具有焦点时使用。代码没有使用第四个参数,但如果使用了,第四个参数将指定空格式化程序,在字段的值为 null 时使用。因为没有指定空格式化程序,所以在值为 null 时使用默认格式化程序。
该代码通过创建NumberFormatter类的子类来自定义使用percentEditFormat的格式化器。该子类重写了NumberFormatter的valueToString和stringToValue方法,以便将显示的数字转换为实际用于计算的值,并将值转换为数字。具体来说,显示的数字是实际值的 100 倍。原因是显示格式器使用的百分比格式会自动将文本显示为值的 100 倍,因此相应的编辑格式器必须以相同的值显示文本。FormattedTextFieldDemo示例不需要处理此转换,因为此演示仅对显示和编辑使用一种格式。
您可以在FormatterFactoryDemo.java中找到整个程序的代码。
格式化文本字段 API
以下表格列出了一些常用的用于使用格式化文本字段的 API。
- 
与格式化文本字段相关的类 
- 
JFormattedTextField 方法 
- 
默认格式化器选项 
与格式化文本字段相关的类
| 类或接口 | 目的 | 
|---|---|
| JFormattedTextField | JTextField的子类,支持格式化任意值。 | 
| JFormattedTextField.AbstractFormatter | JFormattedTextField的所有格式化器的超类。格式化器实施编辑策略和导航策略,处理字符串到对象的转换,并根据需要操作JFormattedTextField以实施所需的策略。 | 
| JFormattedTextField.AbstractFormatterFactory | 所有格式化器工厂的超类。每个 JFormattedTextField使用格式化器工厂来获取最符合文本字段状态的格式化器。 | 
| 默认格式化器工厂 | 通常使用的格式化器工厂。根据传入的参数和焦点状态等详细信息提供格式化器。 | 
| 默认格式化器 | JFormattedTextField.AbstractFormatter的子类,通过使用toString方法格式化任意对象。 | 
| 掩码格式化器 | DefaultFormatter的子类,使用指定的字符掩码格式化和编辑字符串。(例如,可以使用“###-####”指定七位电话号码。) | 
| InternationalFormatter | 使用 java.text.Format的实例处理与String之间的转换的DefaultFormatter的子类。 | 
| NumberFormatter | InternationalFormatter的子类,通过使用NumberFormat的实例支持数字格式。 | 
| DateFormatter | InternationalFormatter的子类,通过使用DateFormat的实例支持日期格式。 | 
JFormattedTextField 方法
| 方法或构造函数 | 目的 | 
|---|
| JFormattedTextField() JFormattedTextField(Object)
JFormattedTextField(AbstractFormatter)
JFormattedTextField(AbstractFormatterFactory)
JFormattedTextField(AbstractFormatterFactory, Object) | 创建一个新的格式化文本字段。如果存在Object参数,则指定字段的初始值并导致创建适当的格式化程序工厂。Format或AbstractFormatter参数指定用于字段的格式或格式化程序,并导致创建适当的格式化程序工厂。AbstractFormatterFactory参数指定要使用的格式化程序工厂,该格式化程序工厂确定用于字段的格式化程序。
| void setValue(Object) Object getValue() | 设置或获取格式化文本字段的值。您必须根据 JFormattedTextField的配置方式对返回类型进行转换。如果尚未设置格式化程序,则调用setValue会将格式化程序设置为字段的格式化程序工厂返回的格式化程序。 | 
|---|---|
| void setFormatterFactory(AbstractFormatterFactory) | 设置确定格式化文本字段使用的格式化程序的对象。该对象通常是 DefaultFormatterFactory类的实例。 | 
| AbstractFormatter getFormatter() | 获取格式化文本字段的格式化程序。格式化程序通常是 DefaultFormatter类的实例。 | 
| void setFocusLostBehavior(int) | 指定字段失去焦点的结果。可能的值在 JFormattedTextField中定义为COMMIT_OR_REVERT(默认值)、COMMIT(如果有效则提交,否则保持一切不变)、PERSIST(不执行任何操作)和REVERT(更改文本以反映值)。 | 
| void commitEdit() | 将值设置为由字段的格式化程序表示的对象,由字段的格式化程序确定。如果文本无效,则值保持不变,并抛出 ParseException。 | 
| boolean isEditValid() | 如果格式化程序认为当前文本有效,则返回 true,由字段的格式化程序确定。 | 
DefaultFormatter 选项
| 方法 | 目的 | 
|---|---|
| void setCommitsOnValidEdit(boolean) boolean getCommitsOnValidEdit() | 在将编辑内容推回 JFormattedTextField时设置或获取值。如果为true,则在每次有效编辑后调用commitEdit。此属性默认值为false。 | 
| void setOverwriteMode(boolean) boolean getOverwriteMode() | 插入字符时设置或获取行为。如果为 true,则新字符在插入时覆盖模型中的现有字符。此属性的默认值为true(在DefaultFormatter(因此在MaskFormatter)中)和false(在InternationalFormatter(因此在DateFormatter和NumberFormatter)中)。 | 
| void setAllowsInvalid(boolean) boolean getAllowsInvalid() | 设置或解释正在编辑的值是否允许在一段时间内无效。通常情况下,允许用户输入无效值直到尝试 commitEdit方法是很方便的。DefaultFormatter将此属性初始化为true。在标准的 Swing 格式化程序中,只有MaskFormatter将此属性设置为false。 | 
使用格式化文本字段的示例
此表列出了使用格式化文本字段的示例,并指向这些示例的描述位置。
| 示例 | 描述位置 | 注释 | 
|---|---|---|
| FormattedTextFieldDemo | 本节 | 使用四个格式化文本字段。 | 
| SpinnerDemo | 如何使用微调器 | 自定义两个微调器使用的格式化文本字段的外观。 | 
| Converter | 使用模型 | 每个 ConversionPanel将一个格式化文本字段与一个滑块配对。 | 
| TextInputDemo | 本节 | 展示如何同时使用文本字段、微调器和格式化文本字段,并演示如何使用 MaskFormatter。包括选择刚刚获得焦点的字段的文本的代码。 | 
| FormatterFactoryDemo | 本节 | 是 FormattedTextFieldDemo 的变体,使用格式化工厂指定两个格式化文本字段的多个格式化程序。 | 
如何制作窗口(主窗口)
原文:
docs.oracle.com/javase/tutorial/uiswing/components/frame.html
窗口是具有标题和边框的顶级窗口。窗口的大小包括为边框指定的任何区域。可以使用getInsets方法获取边框区域的尺寸。由于边框区域包含在窗口的整体尺寸中,边框实际上遮挡了窗口的一部分,限制了用于渲染和/或显示子组件的区域为一个矩形,其左上角位置为(insets.left,insets.top),大小为width - (insets.left + insets.right)乘以height - (insets.top + insets.bottom)。
作为JFrame类的实例实现的窗口具有装饰,如边框、标题,并支持关闭或最小化窗口的按钮组件。具有 GUI 的应用程序通常至少包括一个窗口。小程序有时也使用窗口。
要创建一个依赖于另一个窗口的窗口  例如在另一个窗口最小化时消失  请使用dialog而不是frame.。要创建出现在另一个窗口内的窗口,请使用内部窗口。
创建和显示窗口
这是FrameDemo演示应用程序创建的非常简单窗口的图片。您可以在FrameDemo.java中找到源代码。您可以运行 FrameDemo(下载 JDK 7 或更高版本)。

以下FrameDemo代码显示了如何创建和设置窗口。
//1\. Create the frame.
JFrame frame = new JFrame("FrameDemo");
//2\. Optional: What happens when the frame closes?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//3\. Create components and put them in the frame.
*//...create emptyLabel...*
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
//4\. Size the frame.
frame.pack();
//5\. Show it.
frame.setVisible(true);
以下是代码的一些细节:
- 
代码的第一行使用允许您设置窗口标题的构造函数创建了一个窗口。另一个经常使用的 JFrame构造函数是无参数构造函数。
- 
接下来的代码指定了当用户关闭窗口时发生的情况。 EXIT_ON_CLOSE操作在用户关闭窗口时退出程序。这种行为适用于此程序,因为程序只有一个窗口,关闭窗口会使程序变得无用。有关更多信息,请参阅响应窗口关闭事件。 
- 
下一部分代码向窗口内容窗格添加了一个空标签。如果您还不熟悉内容窗格以及如何向其添加组件,请阅读向内容窗格添加组件。 对于具有菜单的窗口,通常会使用 setJMenuBar方法将菜单栏添加到窗口中。有关详细信息,请参阅如何使用菜单。
- 
pack方法调整框架大小,使得所有内容都达到或超过其首选大小。与pack相对的是通过调用setSize或setBounds(也设置框架位置)来明确建立框架大小。一般来说,使用pack比调用setSize更可取,因为pack让框架布局管理器负责框架大小,布局管理器擅长调整到平台依赖和其他影响组件大小的因素。这个示例没有设置框架位置,但可以使用 setLocationRelativeTo或setLocation方法很容易地实现。例如,以下代码将框架居中显示在屏幕上:frame.setLocationRelativeTo(null);
- 
调用 setVisible(true)使框架显示在屏幕上。有时你可能会看到使用show方法。这两种用法是等效的,但为了一致性起见,我们使用setVisible(true)。
指定窗口装饰
默认情况下,窗口装饰由本机窗口系统提供。然而,你可以要求外观提供框架的装饰。你还可以指定框架根本没有窗口装饰,这是一个可以单独使用的功能,或者提供自己的装饰,或者与全屏独占模式一起使用。
除了指定谁提供窗口装饰,你还可以指定使用哪个图标来代表窗口。这个图标的使用方式取决于提供窗口装饰的窗口系统或外观。如果窗口系统支持最小化,那么图标将用于表示最小化的窗口。大多数窗口系统或外观也会在窗口装饰中显示图标。典型的图标大小是 16x16 像素,但有些窗口系统使用其他大小。
以下快照展示了三个相同的框架,除了它们的窗口装饰不同。通过每个框架中按钮的外观,你可以看出所有三个使用的是 Java 外观。第一个使用由窗口系统提供的装饰,这恰好是 Microsoft Windows,但也可以是运行 Java 平台的任何其他系统。第二个和第三个使用 Java 外观提供的窗口装饰。第三个框架使用 Java 外观提供的窗口装饰,但有一个自定义图标。
|  |  |  | 
|---|---|---|
| 由外观提供的窗口装饰 | 由窗口系统提供的窗口装饰 | 自定义图标;由外观提供的窗口装饰 | 
这里有一个示例,创建一个带有自定义图标和由外观提供的窗口装饰的框架:
//Ask for window decorations provided by the look and feel.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create the frame.
JFrame frame = new JFrame("A window");
//Set the frame icon to an image loaded from a file.
frame.setIconImage(new ImageIcon(imgURL).getImage());
如前面的代码片段所示,您必须在创建希望影响其装饰的窗口之前调用setDefaultLookAndFeelDecorated方法。您使用setDefaultLookAndFeelDecorated设置的值将用于随后创建的所有JFrame。您可以通过调用JFrame.setDefaultLookAndFeelDecorated(false)来切换回使用窗口系统装饰。某些外观和感觉可能不支持窗口装饰;在这种情况下,将使用窗口系统装饰。
创建上述图片框架的应用程序的完整源代码在FrameDemo2.java中。除了显示如何选择窗口装饰外,FrameDemo2 还展示了如何禁用所有窗口装饰,并演示了定位窗口的示例。它包括两个创建用作图标的Image对象的方法  一个从文件加载,另一个从头开始绘制。
试试这个:
- 
单击“启动”按钮以使用Java™ Web Start运行 Frame Demo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。 
- 
弹出两个窗口,都带有外观提供的装饰,但具有不同的图标。 Java 外观和感觉在其窗口装饰中显示图标。根据您的窗口系统,该图标可能会在其他地方用于表示窗口,特别是当窗口最小化时。 
- 
弹出一个或多个带有窗口系统装饰的窗口。 查看您的窗口系统是否以不同方式处理这些图标。 
- 
弹出一个或多个没有窗口装饰的窗口。 通过使用各种类型的窗口来查看窗口装饰、窗口系统和框架图标之间的交互。 
响应窗口关闭事件
默认情况下,当用户在屏幕上关闭一个窗口时,该窗口会被隐藏。尽管不可见,窗口仍然存在,程序可以再次使其可见。如果您希望有不同的行为,则需要注册一个处理窗口关闭事件的窗口监听器,或者使用setDefaultCloseOperation方法指定默认关闭行为。您甚至可以两者都做。
setDefaultCloseOperation的参数必须是以下值之一,前三个值在WindowConstants接口中定义(由JFrame、JInternalPane和JDialog实现):
DO_NOTHING_ON_CLOSE
当用户请求关闭窗口时不执行任何操作。相反,程序可能应该使用一个窗口监听器,在其windowClosing方法中执行其他操作。
HIDE_ON_CLOSE(JDialog和JFrame的默认值)
当用户关闭窗口时隐藏窗口。这将窗口从屏幕上移除,但保持可显示状态。
DISPOSE_ON_CLOSE(JInternalFrame的默认值)
当用户关闭窗口时隐藏并销毁窗口。这将窗口从屏幕上移除,并释放其使用的任何资源。
EXIT_ON_CLOSE(在JFrame类中定义)
退出应用程序,使用System.exit(0)。这仅适用于应用程序。如果在小程序中使用,可能会抛出SecurityException。
注意:
DISPOSE_ON_CLOSE如果屏幕上只有一个窗口,可能会产生与EXIT_ON_CLOSE类似的结果。更准确地说,当 Java 虚拟机(VM)中的最后一个可显示窗口被处理时,VM 可能会终止。详细信息请参见AWT 线程问题。
默认关闭操作在任何窗口监听器处理窗口关闭事件之后执行。因此,例如,假设您指定默认关闭操作是销毁一个框架。您还实现了一个窗口监听器,测试框架是否是最后一个可见的框架,并在是的情况下保存一些数据并退出应用程序。在这些条件下,当用户关闭一个框架时,窗口监听器将首先被调用。如果它没有退出应用程序,那么默认关闭操作  销毁框架  将会被执行。
有关处理窗口关闭事件的更多信息,请参见如何编写窗口监听器。除了处理窗口关闭事件外,窗口监听器还可以对其他窗口状态更改做出反应,例如图标化和激活。
框架 API
以下表列出了常用的JFrame构造函数和方法。您可能想调用的其他方法由java.awt.Frame、java.awt.Window和java.awt.Component类定义,JFrame继承自这些类。
因为每个JFrame对象都有一个根窗格,所以框架支持在框架子元素前插入输入和绘制行为,将子元素放置在不同的“层”上,并支持 Swing 菜单栏。这些主题在使用顶级容器中介绍,并在如何使用根窗格中详细解释。
用于使用框架的 API 分为以下几类:
- 
创建和设置框架 
- 
设置窗口大小和位置 
- 
与根窗格相关的方法 
创建和设置一个窗口
| 方法或构造函数 | 目的 | 
|---|---|
| JFrame() JFrame(String) | 创建一个最初不可见的窗口。 String参数为窗口提供标题。要使窗口可见,请在其上调用setVisible(true)。 | 
| void setDefaultCloseOperation(int) int getDefaultCloseOperation() | 设置或获取用户在此窗口上按下关闭按钮时发生的操作。可能的选择是:
- 
DO_NOTHING_ON_CLOSE
- 
HIDE_ON_CLOSE
- 
DISPOSE_ON_CLOSE
- 
EXIT_ON_CLOSE
前三个常量在WindowConstants接口中定义,JFrame实现了该接口。EXIT_ON_CLOSE常量在JFrame类中定义。 |
| void setIconImage(Image) Image getIconImage()
(in Frame) | 设置或获取表示窗口的图标。请注意,参数是一个java.awt.Image对象,而不是javax.swing.ImageIcon(或任何其他javax.swing.Icon实现)。 |
| void setTitle(String) String getTitle()
(in Frame) | 设置或获取窗口标题。 |
| void setUndecorated(boolean) boolean isUndecorated()
(in Frame) | 设置或获取此窗口是否应该装饰。仅在窗口尚未可显示(未打包或显示)时才有效。通常与全屏独占模式一起使用,或者启用自定义窗口装饰。 |
| static void setDefaultLookAndFeelDecorated(boolean) static boolean isDefaultLookAndFeelDecorated() | 确定随后创建的 JFrame是否应由当前外观提供其窗口装饰(如边框和用于关闭窗口的小部件)。请注意,这只是一个提示,因为某些外观可能不支持此功能。 | 
|---|
设置窗口大小和位置
| 方法 | 目的 | 
|---|---|
| void pack() (在 Window中) | 调整窗口大小,使其所有内容都达到或超过其首选大小。 | 
| void setSize(int, int) void setSize(Dimension)
(在Component中) | 设置或获取窗口的总大小。setSize的整数参数分别指定宽度和高度。|
| void setBounds(int, int, int, int) void setBounds(Rectangle)
(在Component中) | 设置或获取窗口的大小和位置。对于setBounds的整数版本,窗口的左上角位于由前两个参数指定的x, y位置,并具有由最后两个参数指定的宽度和高度。|
| void setLocation(int, int) Point getLocation()
(在Component中) | 设置或获取窗口左上角的位置。参数分别是x和y的值。|
| void setLocationRelativeTo(Component) (在 Window中) | 将窗口定位在指定组件的中心。如果参数为 null,窗口将居中显示在屏幕上。要正确居中窗口,应在设置窗口大小后调用此方法。 | 
|---|
与根窗格相关的方法
| 方法 | 目的 | 
|---|---|
| void setContentPane(Container) Container getContentPane() | 设置或获取框架的内容窗格。内容窗格包含框架内可见的 GUI 组件。 | 
| JRootPane createRootPane() void setRootPane(JRootPane)
JRootPane getRootPane() | 创建、设置或获取框架的根窗格。根窗格管理框架的内部,包括内容窗格、玻璃窗格等。
| void setJMenuBar(JMenuBar) JMenuBar getJMenuBar() | 设置或获取框架的菜单栏,以管理框架的一组菜单。 | 
|---|---|
| void setGlassPane(Component) Component getGlassPane() | 设置或获取框架的玻璃窗格。您可以使用玻璃窗格拦截鼠标事件或在程序 GUI 的顶部绘制。 | 
| void setLayeredPane(JLayeredPane) JLayeredPane getLayeredPane() | 设置或获取框架的分层窗格。您可以使用框架的分层窗格将组件放置在其他组件的前面或后面。 | 
使用框架的示例
本教程中的所有独立应用程序都使用JFrame。以下表格列出了一些应用程序,并告诉您每个应用程序的讨论位置。
| 示例 | 描述位置 | 备注 | 
|---|---|---|
| FrameDemo | 示例说明 | 显示一个带有一个组件的基本框架。 | 
| FrameDemo2 | 指定窗口装饰 | 允许您创建具有各种窗口装饰的框架。 | 
| Framework |  | 研究如何创建和销毁窗口,实现菜单栏以及退出应用程序。 | 
| LayeredPaneDemo | 如何使用分层窗格 | 演示如何使用分层窗格(但不是框架的分层窗格)。 | 
| GlassPaneDemo | 玻璃窗格 | 演示了框架玻璃窗格的使用。 | 
| MenuDemo | 如何使用菜单 | 展示如何将 JMenuBar放入JFrame中。 | 
如何使用内部窗体
原文:
docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html
使用 JInternalFrame 类,您可以在另一个窗口内显示类似 JFrame 的窗口。通常,您将内部窗体添加到桌面窗格中。桌面窗格反过来可能被用作 JFrame 的内容窗格。桌面窗格是 JDesktopPane 的一个实例,它是 JLayeredPane 的子类,具有用于管理多个重叠内部窗体的附加 API。
您应该仔细考虑是否要围绕框架或内部窗体构建程序的 GUI。从内部窗体切换到框架或反之并不一定是一项简单的任务。通过尝试框架和内部窗体,您可以了解选择其中一个的权衡。
这是一个应用程序的图片,其中有两个内部窗体(其中一个被图标化)在一个常规窗体内:

试试这个:
- 
点击“启动”按钮以使用 Java™ Web Start 运行 InternalFrameDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考 示例索引。 
- 
使用“文档”菜单中的“创建”项创建新的内部窗体。 每个内部窗体都会在前一个内部窗体首次出现的位置下方和右方 30 像素的位置弹出。这一功能在MyInternalFrame类中实现,该类是JInternalFrame的自定义子类。
下面的代码取自 InternalFrameDemo.java,在前一个示例中创建了桌面和内部窗体。
*...//In the constructor of InternalFrameDemo, a JFrame subclass:*
    desktop = new JDesktopPane();
    createFrame(); //Create first window
    setContentPane(desktop);
    ...
    //Make dragging a little faster but perhaps uglier.
    desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
...
protected void createFrame() {
    MyInternalFrame frame = new MyInternalFrame();
    frame.setVisible(true);
    desktop.add(frame);
    try {
        frame.setSelected(true);
    } catch (java.beans.PropertyVetoException e) {}
}
*...//In the constructor of MyInternalFrame, a JInternalFrame subclass:*
static int openFrameCount = 0;
static final int xOffset = 30, yOffset = 30;
public MyInternalFrame() {
    super("Document #" + (++openFrameCount),
          true, //resizable
          true, //closable
          true, //maximizable
          true);//iconifiable
    //...Create the GUI and put it in the window...
    //...Then set the window size or call pack...
    ...
    //Set the window's location.
    setLocation(xOffset*openFrameCount, yOffset*openFrameCount);
}
内部窗体 vs. 常规框架
使用内部窗体的代码在许多方面与使用常规 Swing 框架的代码类似。因为内部窗体有根窗格,为 JInternalFrame 设置 GUI 与为 JFrame 设置 GUI 非常相似。JInternalFrame 还提供其他 API,例如 pack,使其类似于 JFrame。
注意:
与常规框架一样,您必须在内部框架上调用 setVisible(true) 或 show() 才能显示它。内部框架直到您明确使其可见为止才会出现。
内部框架不是窗口或顶级容器,这使它们与框架不同。例如,您必须将内部框架添加到容器中(通常是 JDesktopPane);内部框架不能是包含层次结构的根。此外,内部框架不会生成窗口事件。相反,会导致框架触发窗口事件的用户操作会导致内部框架触发内部框架事件。
由于内部框架是使用与平台无关的代码实现的,它们提供了一些框架无法提供的功能。其中一个功能是,内部框架比框架更具有控制其状态和功能的能力。您可以以编程方式将内部框架图标化或最大化。您还可以指定要放在内部框架标题栏中的图标。您甚至可以指定内部框架是否具有支持调整大小、图标化、关闭和最大化的窗口装饰。
另一个特点是内部框架设计用于在桌面窗格内工作。JInternalFrame API 包含诸如 moveToFront 这样的方法,只有当内部框架的容器是分层窗格(如 JDesktopPane)时才有效。
使用内部框架的规则
如果您已经使用 JFrame 和其他 Swing 组件构建过任何程序,那么您已经了解了如何使用内部框架的很多知识。以下列表总结了使用内部框架的规则。有关更多信息,请参阅如何创建框架和 JComponent 类。
您必须设置内部框架的大小。
如果您不设置内部框架的大小,它将具有零大小,因此永远不会可见。您可以使用以下方法之一设置大小:setSize、pack 或 setBounds。
通常情况下,您应该设置内部框架的位置。
如果您不设置内部框架的位置,它将出现在 0,0(其容器的左上角)。您可以使用 setLocation 或 setBounds 方法指定内部框架相对于其容器的左上点。
要向内部框架添加组件,您需要将它们添加到内部框架的内容窗格中。
这与 JFrame 的情况完全相同。有关详细信息,请参阅将组件添加到内容窗格。
内部框架的对话框应该使用 JOptionPane 或 JInternalFrame 实现,而不是 JDialog。
要创建一个简单的对话框,您可以使用 JOptionPane 的 showInternal*Xxx*Dialog 方法,如如何创建对话框中所述。
你必须将内部框架添加到容器中。
如果您不将内部框架添加到容器中(通常是 JDesktopPane),则内部框架将不会显示。
您需要在内部框架上调用 show 或 setVisible。
内部窗体默认是不可见的。您必须调用setVisible(true)或show()使其可见。
内部窗体触发内部窗体事件,而不是窗口事件。
处理内部窗体事件几乎与处理窗口事件相同。有关更多信息,请参阅 How to Write an Internal Frame Listener。
性能提示:
当桌面上有许多内部窗体时,用户可能会注意到移动它们似乎很慢。轮廓拖动是避免这个问题的一种方法。使用轮廓拖动时,只有内部窗体的轮廓在当前鼠标位置绘制,而内部窗体被拖动时不会重新绘制。内部窗体的内容在停止拖动之前不会在新位置重新绘制。默认行为(称为实时拖动)是在移动时连续重新定位和重绘部分或全部内部窗体;如果桌面上有许多内部窗体,这可能会很慢。
使用JDesktopPane方法setDragMode*来指定轮廓拖动。例如:
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
内部窗体 API
下表列出了常用的JInternalFrame构造函数和方法,以及JDesktopPane提供的一些方法。除了本节列出的 API 之外,JInternalFrame还从其父类JComponent、Component和Container继承了有用的 API。请参阅 The JComponent Class 以查看这些类的方法列表。
与JInternalFrame类似,JDesktopPane也是从JComponent继承而来,因此提供了 The JComponent Class 中描述的方法。由于JDesktopPane扩展自JLayeredPane,它还支持 The Layered Pane API 中描述的方法。
使用内部窗体的 API 可分为以下几类:
- 
创建内部窗体 
- 
向内部窗体添加组件 
- 
指定内部窗体的可见性、大小和位置 
- 
在内部窗体上执行窗口操作 
- 
控制窗口装饰和功能 
- 
使用 JDesktopPane API 
创建内部窗体
| 构造函数或方法 | 目的 | 
|---|
| JInternalFrame() JInternalFrame(String)
JInternalFrame(String, boolean)
JInternalFrame(String, boolean, boolean)
JInternalFrame(String, boolean, boolean, boolean)
JInternalFrame(String, boolean, boolean, boolean, boolean) | 创建一个JInternalFrame实例。第一个参数指定内部框架要显示的标题(如果有)。其余参数指定内部框架是否应包含允许用户调整大小、关闭、最大化和最小化内部框架的装饰(按照指定的顺序)。每个布尔参数的默认值为false,表示不允许该操作。 |
| 静态整数 showInternalConfirmDialog(Component, Object) 静态字符串 showInternalInputDialog(Component, Object) | 显示内部确认对话框或输入对话框。 |
静态对象 showInternalMessageDialog(Component, Object)
静态整数 showInternalOptionDialog(Component, Object, String, int, int, Icon, Object[], Object) | 创建一个模拟对话框的JInternalFrame。有关详细信息,请参阅如何制作对话框。 |
添加组件到内部框架
| 方法 | 目的 | 
|---|---|
| void setContentPane(Container) Container getContentPane() | 设置或获取内部框架的内容窗格,通常包含内部框架的所有 GUI,除了菜单栏和窗口装饰。 | 
| void setJMenuBar(JMenuBar) JMenuBar getJMenuBar() | 设置或获取内部框架的菜单栏。 | 
| void setLayeredPane(JLayeredPane) JLayeredPane getLayeredPane() | 设置或获取内部框架的分层窗格。 | 
指定内部框架的可见性、大小和位置
| 方法 | 目的 | 
|---|---|
| void setVisible(boolean) | 使内部框架可见(如果为 true)或不可见(如果为false)。在将每个JInternalFrame添加到其容器之前,应调用setVisible(true)。(从Component继承)。 | 
| void pack() | 调整内部框架的大小,使其组件达到其首选大小。 | 
| void setLocation(Point) void setLocation(int, int) | 设置内部框架的位置。(从 Component继承)。 | 
| void setBounds(Rectangle) void setBounds(int, int, int, int) | 明确设置内部框架的大小和位置。(从 Component继承)。 | 
| void setSize(Dimension) void setSize(int, int) | 明确设置内部框架的大小。(从 Component继承)。 | 
执行内部框架的窗口操作
| 方法 | 目的 | 
|---|---|
| void setDefaultCloseOperation(int) int getDefaultCloseOperation() | 设置或获取用户尝试“关闭”内部框架时内部框架的操作。默认值为 DISPOSE_ON_CLOSE。其他可能的值为DO_NOTHING_ON_CLOSE和HIDE_ON_CLOSE。详细信息请参见响应窗口关闭事件。 | 
| void addInternalFrameListener(InternalFrameListener) void removeInternalFrameListener(InternalFrameListener) | 添加或移除内部框架监听器( JInternalFrame的窗口监听器等效)。有关更多信息,请参见如何编写内部框架监听器。 | 
| void moveToFront() void moveToBack() | 如果内部框架的父级是分层窗格,如桌面窗格,则将内部框架移动到其层的前端或后端(分别)。 | 
| void setClosed(boolean) boolean isClosed() | 设置或获取内部框架当前是否关闭。 setClosed的参数必须为true。重新打开已关闭的内部框架时,您需要将其设置为可见并添加到容器中(通常是您最初添加的桌面窗格)。 | 
| void setIcon(boolean) boolean isIcon() | 将内部框架图标化或取消图标化,或确定其当前是否已图标化。 | 
| void setMaximum(boolean) boolean isMaximum() | 最大化或恢复内部框架,或确定其是否已最大化。 | 
| void setSelected(boolean) boolean isSelected() | 设置或获取内部框架当前是否为“选定”(激活)的内部框架。 | 
控制窗口装饰和功能
| 方法 | 目的 | 
|---|---|
| void setFrameIcon(Icon) Icon getFrameIcon() | 设置或获取显示在内部框架标题栏中的图标(通常位于左上角)。 | 
| void setClosable(boolean) boolean isClosable() | 设置或获取用户是否可以关闭内部框架。 | 
| void setIconifiable(boolean) boolean isIconifiable() | 设置或获取内部框架是否可以图标化。 | 
| void setMaximizable(boolean) boolean isMaximizable() | 设置或获取用户是否可以最大化此内部框架。 | 
| void setResizable(boolean) boolean isResizable() | 设置或获取内部框架是否可以调整大小。 | 
| void setTitle(String) String getTitle() | 设置或获取窗口标题。 | 
使用JDesktopPane API
| 构造函数或方法 | 目的 | 
|---|---|
| JDesktopPane() | 创建一个新的 JDesktopPane实例。 | 
| JInternalFrame[] getAllFrames() | 返回桌面包含的所有 JInternalFrame对象。 | 
| JInternalFrame[] getAllFramesInLayer(int) | 返回桌面包含的在指定层中的所有 JInternalFrame对象。有关层的信息,请参阅如何使用分层窗格。 | 
| void setDragMode(int) int getDragMode() | 设置或获取此桌面中内部框架使用的拖动模式。整数可以是 JDesktopPane.LIVE_DRAG_MODE或JDesktopPane.OUTLINE_DRAG_MODE。Java 外观的默认值是实时拖动模式。 | 
使用内部框架的示例
以下示例使用内部框架。由于内部框架类似于常规框架,您还应查看使用框架的示例。
| 示例 | 描述位置 | 注释 | 
|---|---|---|
| MyInternalFrame | 本页。 | 实现一个出现在先前创建的内部框架偏移位置的内部框架。 | 
| InternalFrameDemo | 本页。 | 允许您创建进入应用程序的 JDesktopPane的内部框架(MyInternalFrame的实例)。 | 
| InternalFrameEventDemo | 如何编写内部框架侦听器 | 演示监听内部框架事件。还演示了在桌面窗格内定位内部框架。 | 
如何使用标签
原文:
docs.oracle.com/javase/tutorial/uiswing/components/label.html
使用JLabel类,您可以显示不可选择的文本和图像。如果您需要创建一个显示字符串、图像或两者的组件,可以使用或扩展JLabel来实现。如果组件是交互式的并具有某种状态,请使用按钮而不是标签。
通过在标签文本中指定 HTML 代码,您可以赋予标签各种特性,如多行、多字体或多颜色。如果标签仅使用单一颜色或字体,您可以通过使用setForeground或setFont方法来避免 HTML 处理的开销。有关详细信息,请参阅在 Swing 组件中使用 HTML。
请注意,默认情况下标签不是不透明的。如果您需要绘制标签的背景,建议将其不透明属性设置为"true"。以下代码片段显示了如何实现这一点。
label.setOpaque(true);
以下图片介绍了一个显示三个标签的应用程序。窗口被分为三行等高;每行中的标签尽可能宽。

试一试:
- 
单击“启动”按钮以使用Java™ Web Start运行 Label Demo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参阅示例索引。 
- 
调整窗口大小,以查看标签内容如何放置在标签的绘图区域内。 所有标签内容都具有默认的垂直对齐方式——即,标签内容在标签绘图区域中垂直居中。包含图像和文本的顶部标签具有水平居中对齐。只包含文本的第二个标签具有左侧(leading)对齐,这是从左到右语言中仅包含文本标签的默认值。只包含图像的第三个标签具有水平居中对齐,这是仅包含图像标签的默认值。 
下面是LabelDemo.java中创建上述示例标签的代码。
ImageIcon icon = createImageIcon("images/middle.gif");
. . .
label1 = new JLabel("Image and Text",
                    icon,
                    JLabel.CENTER);
//Set the position of the text, relative to the icon:
label1.setVerticalTextPosition(JLabel.BOTTOM);
label1.setHorizontalTextPosition(JLabel.CENTER);
label2 = new JLabel("Text-Only Label");
label3 = new JLabel(icon);
createImageIcon 方法的代码与本教程中使用的代码类似。您可以在如何使用图标中找到它。
通常,标签描述另一个组件。当发生这种情况时,您可以通过使用setLabelFor方法来提高程序的可访问性,以标识标签描述的组件。例如:
amountLabel.setLabelFor(amountField);
前面的代码取自如何使用格式化文本字段中讨论的FormattedTextFieldDemo示例,让辅助技术知道标签(amountLabel)提供有关格式化文本字段(amountField)的信息。有关辅助技术的更多信息,请参阅如何支持辅助技术。
标签 API
以下表格列出了常用的JLabel构造函数和方法。您可能要调用的其他方法由Component和JComponent类定义。它们包括setFont、setForeground、setBorder、setOpaque和setBackground。有关详细信息,请参阅 The JComponent Class。使用标签的 API 分为三类:
- 
设置或获取标签内容 
- 
调整标签外观 
- 
支持辅助功能 
注意:
在以下 API 中,不要将标签对齐与 X 和 Y 对齐混淆。X 和 Y 对齐由布局管理器使用,可以影响任何组件的大小或位置,而不仅仅是标签。另一方面,标签对齐对标签的大小或位置没有影响。标签对齐仅确定标签内容在标签绘制区域内的位置。通常,标签的绘制区域正好足以在标签上绘制,因此标签对齐是无关紧要的。有关 X 和 Y 对齐的更多信息,请参阅如何使用 BoxLayout。
设置或获取标签内容
| 方法或构造函数 | 目的 | 
|---|
| JLabel(Icon) JLabel(Icon, int)
JLabel() | 创建一个JLabel实例,将其初始化为具有指定的文本/图像/对齐方式。int参数指定标签内容在其绘图区域内的水平对齐方式。水平对齐必须是SwingConstants接口中定义的以下常量之一(JLabel实现的接口):LEFT、CENTER、RIGHT、LEADING或TRAILING。为了方便本地化,我们强烈建议使用LEADING和TRAILING,而不是LEFT和RIGHT。
| void setText(String) String getText() | 设置或获取标签显示的文本。您可以使用 HTML 标记格式化文本,如在 Swing 组件中使用 HTML 中所述。 | 
|---|---|
| void setIcon(Icon) Icon getIcon() | 设置或获取标签显示的图像。 | 
| void setDisplayedMnemonic(char) char getDisplayedMnemonic() | 设置或获取应该看起来像键盘替代的字母。当标签描述无法显示键盘替代但具有键盘替代的组件(如文本字段)时,这很有帮助。如果还设置了 labelFor 属性(使用 setLabelFor),那么当用户激活助记键时,键盘焦点将转移到由 labelFor 属性指定的组件。 | 
| void setDisplayedMnemonicIndex(int) int getDisplayedMnemonicIndex() | 设置或获取文本中应该被装饰以表示助记键的字符的提示。当您有两个相同字符的实例并希望装饰第二个实例时,这很有用。例如, setDisplayedMnemonicIndex(5)装饰文本中位置为 5 的字符(即文本中的第 6 个字符)。并非所有类型的外观和感觉都支持此功能。 | 
| void setDisabledIcon(Icon) Icon getDisabledIcon() | 设置或获取标签在禁用时显示的图像。如果不指定禁用图像,则外观会通过操作默认图像来创建一个。 | 
调整标签外观
| 方法 | 目的 | 
|---|
| void setHorizontalAlignment(int) void setVerticalAlignment(int)
int getVerticalAlignment() | 设置或获取标签内容应放置的区域。SwingConstants 接口定义了水平对齐的五个可能值:LEFT、CENTER(仅图像标签的默认值)、RIGHT、LEADING(仅文本标签的默认值)、TRAILING。垂直对齐有:TOP、CENTER(默认)和 BOTTOM。 |
| void setHorizontalTextPosition(int) void setVerticalTextPosition(int)
int getHorizontalTextPosition()
int getVerticalTextPosition() | 设置或获取标签文本相对于标签图像放置的位置。SwingConstants 接口定义了水平位置的五个可能值:LEADING、LEFT、CENTER、RIGHT 和 TRAILING(默认)。垂直位置有:TOP、CENTER(默认)和 BOTTOM。 |
| void setIconTextGap(int) int getIconTextGap() | 设置或获取标签文本与图像之间的像素数。 | 
|---|
支持辅助功能
| 方法 | 目的 | 
|---|---|
| void setLabelFor(Component) Component getLabelFor() | 设置或获取标签描述的组件。 | 
使用标签的示例
下表列出了一些使用标签的示例。
| 示例 | 描述位置 | 注释 | 
|---|---|---|
| LabelDemo | 本节 | 展示了如何指定水平和垂直对齐,以及如何对齐标签的文本和图像。 | 
| HtmlDemo | 在 Swing 组件中使用 HTML | 让您尝试为标签指定 HTML 文本。 | 
| BoxAlignmentDemo | 解决对齐问题 | 演示了在垂直盒式布局中使用标签可能出现的对齐问题。展示了如何解决这个问题。 | 
| DialogDemo | 如何使用对话框 | 使用可变标签显示说明并提供反馈。 | 
| SplitPaneDemo | 如何使用分割窗格 和 如何使用列表 | 在滚动窗格内使用标签显示图像。 | 
| SliderDemo2 | 如何使用滑块 | 使用 JLabel为滑块提供标签。 | 
| TableDialogEditDemo | 如何使用表格 | 实现了一个标签子类 ColorRenderer,用于在表格单元格中显示颜色。 | 
| FormattedTextFieldDemo | 如何使用格式化文本字段 | 包含四行,每行包含一个标签和描述它的格式化文本字段。 | 
| TextComponentDemo | 文本组件特性 | TextComponentDemo有一个内部类(CaretListenerLabel),它扩展了JLabel以提供一个监听事件的标签,根据事件更新自身。 | 
| ColorChooserDemo | 如何使用颜色选择器 | 使用不透明标签来显示当前选择的颜色在固定颜色背景上。 | 
查看使用 JavaFX UI 控件:标签教程,了解 JavaFX 标签控件。
如何使用分层窗格
原文:
docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
分层窗格是一个提供第三维度用于定位组件的 Swing 容器:深度,也称为Z 顺序。将组件添加到分层窗格时,您将其深度指定为整数。数字越高,组件越接近容器内的“顶部”位置。如果组件重叠,那么“更接近”的组件将绘制在深度较低的组件之上。在相同深度的组件之间的关系由它们在深度内的位置决定。
注意:
AWT 容器具有一个 API,允许您操纵组件的Z 顺序。更多信息,请参阅AWT 焦点规范。
每个具有根窗格的 Swing 容器  例如JFrame、JApplet、JDialog或JInternalFrame  都会自动拥有一个分层窗格。大多数程序不会显式使用根窗格的分层窗格,因此本节不会讨论它。您可以在根窗格中找到有关它的信息,该部分提供了概述,以及分层窗格,其中包含更多详细信息。本节告诉您如何创建自己的分层窗格,并在任何可以使用常规 Swing 容器的地方使用它。
Swing 提供了两个分层窗格类。第一个是JLayeredPane,是根窗格使用的类,也是本节示例中使用的类。第二个是JDesktopPane,是一个专门用于容纳内部窗格的JLayeredPane子类。有关使用JDesktopPane的示例,请参阅如何使用内部窗格。
这是一个创建分层窗格并在不同深度放置重叠的彩色标签的应用程序图片:

试试这个:
- 
单击“启动”按钮以使用Java™ Web Start运行 LayeredPane Demo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参阅示例索引。 
- 
在窗口的下部四处移动鼠标。杜克的图像在绿色和红色标签后面拖动,但在其他三个标签前面。 
- 
使用窗口顶部的组合框更改杜克的深度。使用复选框设置杜克是否在当前深度内的顶部位置  位置 0。 
这里是LayeredPaneDemo.java中创建分层窗格的代码:
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 310));
layeredPane.setBorder(BorderFactory.createTitledBorder(
                                    "Move the Mouse to Move Duke"));
layeredPane.addMouseMotionListener(new MouseMotionAdapter() {
    ...
});
代码使用了JLayeredPane的唯一构造函数  无参数构造函数  来创建分层窗格。其余代码使用从超类继承的方法为分层窗格设置首选大小和边框,并向其添加鼠标移动监听器。鼠标移动监听器只是根据鼠标移动来移动杜克形象。虽然我们这里没有展示代码,但示例将分层窗格添加到了框架的内容窗格中。
正如我们稍后将展示的,您可以使用add方法将组件添加到分层窗格中。当向分层窗格添加组件时,您需要指定组件的深度,并可选地指定其在深度内的位置。演示程序中的分层窗格包含六个标签  五个彩色标签和一个显示杜克形象的标签。正如程序所示,组件的深度和其在该深度内的位置都可以动态更改。
本节的其余部分涵盖了以下主题:
- 
添加组件和设置组件深度 
- 
设置组件在其深度内的位置 
- 
在分层窗格中布局组件 
- 
分层窗格 API 
- 
使用分层窗格的示例 
添加组件和设置组件深度
这里是示例程序中将彩色标签添加到分层窗格的代码:
for (int i = 0; i < *...number of labels...*; i++) {
    JLabel label = createColoredLabel(*...*);
    layeredPane.add(label, new Integer(i));
    ...
}
你可以在程序的源代码中找到createColoredLabel方法的实现。它只是创建了一个带有背景颜色、边框、一些文本和大小的不透明JLabel。
示例程序使用了add方法的两个参数版本。第一个参数是要添加的组件,第二个是一个Integer对象,指定深度。该程序使用for循环迭代变量来指定深度。实际值并不重要,重要的是深度的相对值以及在程序中如何一致地使用每个深度。
注意:
如果您使用根窗格的分层窗格,请确保使用其深度约定。有关详细信息,请参阅分层窗格。该部分向您展示如何修改LayeredPaneDemo以使用根窗格的分层窗格。通过这些修改,您可以看到拖动杜克形象与控制面板中的组合框之间的关系。
如示例程序所示,如果组件重叠,深度较高的组件位于深度较低的组件之上。要动态更改组件深度,请使用setLayer方法。在示例中,用户可以通过从组合框中进行选择来更改 Duke 的层。以下是注册在组合框上的动作监听器的actionPerformed方法:
public void actionPerformed(ActionEvent e) {
    int position = onTop.isSelected() ? 0 : 1;
    layeredPane.setLayer(dukeLabel,
                         layerList.getSelectedIndex(),
                         position);
}
这里使用的setLayer方法需要三个参数:要设置深度的组件、新深度以及深度内的位置。JLayeredPane有一个只接受组件和新深度两个参数的setLayer版本。该方法将组件放在其深度的底部位置。
注意:
将组件添加到分层窗格时,您需要用一个Integer指定层。当使用setLayer来更改组件的层时,您需要使用一个int。您可能会认为,如果您在add方法中使用int而不是Integer,编译器会抱怨或您的程序会抛出非法参数异常。但编译器什么也不说,这导致了一个常见的分层窗格问题。您可以使用本节末尾的 API 表格来检查处理层的方法的参数和返回值的类型。
设置组件在其深度内的位置
以下代码创建显示 Duke 图像的标签,然后将标签添加到分层窗格中。
final ImageIcon icon = createImageIcon("images/dukeWaveRed.gif");
...
dukeLabel = new JLabel(icon);
...
dukeLabel.setBounds(15, 225,
                    icon.getIconWidth(),
                    icon.getIconHeight());
...
layeredPane.add(dukeLabel, new Integer(2), 0);
此代码使用add方法的三个参数版本。第三个参数指定了 Duke 标签在其深度内的位置,这决定了组件与同一深度的其他组件的关系。
位置用介于-1 和(n - 1)之间的int指定,其中n是深度中组件的数量。与层号不同,位置数字越小,组件在其深度内的位置越高。使用-1 与使用n - 1 相同;它表示最底部的位置。使用 0 指定组件应位于其深度内的最顶部位置。如下图所示,除了-1 外,较低的位置数字表示深度内的较高位置。

组件在其层内的位置可以动态改变。在示例中,您可以使用复选框确定 Duke 标签是否在其深度的顶部位置。以下是注册在复选框上的动作监听器的actionPerformed方法:
public void actionPerformed(ActionEvent e) {
    if (onTop.isSelected())
        layeredPane.moveToFront(dukeLabel);
    else
        layeredPane.moveToBack(dukeLabel);
}
当用户选择复选框时,moveToFront方法将 Duke 移至最前面(位置 0)。当用户取消选择复选框时,Duke 将通过moveToBack方法移至最后。您还可以使用setPosition方法或setLayer的三个参数版本来更改组件的位置。
在分层窗格中布置组件
默认情况下,分层窗格没有布局管理器。这意味着你通常需要编写代码来定位和调整分层窗格中放置的组件的位置和大小。
该示例使用setBounds方法来设置每个标签的大小和位置:
dukeLabel.setBounds(15, 225,
                    icon.getIconWidth(),
                    icon.getIconHeight());
...
label.setBounds(origin.x, origin.y, 140, 140);
当用户移动鼠标时,程序调用setPosition来改变杜克的位置:
dukeLabel.setLocation(e.getX()-XFUDGE, e.getY()-YFUDGE);
尽管默认情况下分层窗格没有布局管理器,但你仍然可以为分层窗格分配布局管理器。Java 平台提供的所有布局管理器都会将组件排列得好像它们都在一个层上。以下是将分层窗格的布局管理器设置为GridLayout实例的上一个演示的版本,使用该布局管理器来布置六个彩色标签。

你可以在LayeredPaneDemo2.java中找到此程序的代码。你可以运行 LayeredPaneDemo2(下载 JDK 7 或更高版本)。如果你想编译示例,请查阅示例索引以获取所有必要文件的列表。
许多程序使用中间容器(如面板)及其布局管理器在同一层上布置组件,但使用绝对定位在不同层上布置组件。有关绝对定位的更多信息,请参阅无布局管理器(绝对定位)。
分层窗格 API
以下表格列出了常用的JLayeredPane构造函数和方法。你最有可能在JLayeredPane对象上调用的其他方法是它从超类继承的方法,如setBorder、setPreferredSize等。请参阅 The JComponent API 以获取常用继承方法的表格。
使用分层窗格的 API 分为以下几类:
- 
创建或获取分层窗格 
- 
组件分层 
- 
设置组件的层内位置 
创建或获取分层窗格
| 方法或构造函数 | 目的 | 
|---|---|
| JLayeredPane() | 创建一个分层窗格。 | 
| JLayeredPane getLayeredPane() (在 JApplet、JDialog、JFrame和JInternalFrame中) | 获取 applet、对话框、框架或内部框架中的自动分层窗格。 | 
组件分层
| 方法 | 目的 | 
|---|
| void add(Component) void add(Component, Object)
void add(Component, Object, int) | 将指定组件添加到分层窗格。第二个参数(如果存在)是一个Integer,表示层级。第三个参数(如果存在)表示组件在其层级内的位置。如果使用此方法的一参数版本,则组件将添加到层级 0。如果使用此方法的一或两参数版本,则组件将放置在当前位于同一层级中的所有其他组件的下方。
| void setLayer(Component, int) void setLayer(Component, int, int) | 更改组件的层级。第二个参数表示层级。第三个参数(如果存在)表示组件在其层级内的位置。 | 
|---|---|
| int getLayer(Component) int getLayer(JComponent) | 获取指定组件的层级。 | 
| int getComponentCountInLayer(int) | 获取指定层级中组件的数量。此方法返回的值对于计算位置值可能很有用。 | 
| Component[] getComponentsInLayer(int) | 获取指定层级中所有组件的数组。 | 
| int highestLayer() int lowestLayer() | 计算当前使用的最高或最低层级。 | 
设置组件的层内位置
| 方法 | 目的 | 
|---|---|
| void setPosition(Component, int) int getPosition(Component) | 设置或获取指定组件在其层级内的位置。 | 
| 将组件移至前端或后端 将组件移至后端 | 将指定的组件移至其所在层的前端或后端。 | 
使用层叠窗格的示例
这个表格展示了使用JLayeredPane的示例以及这些示例的描述位置。
| 示例 | 描述位置 | 备注 | 
|---|---|---|
| LayeredPaneDemo | 本节 | 展示了 JLayeredPane的层和层内位置。 | 
| LayeredPaneDemo2 | 本节 | 使用布局管理器来帮助布置层叠窗格中的组件。 | 
| RootLayeredPaneDemo | 层叠窗格 | 一个修改过的版本的 LayeredPaneDemo,用于使用根窗格的层叠窗格。 | 
| InternalFrameDemo | 如何使用内部框架 | 使用 JDesktopFrame来管理内部框架。 | 
如何使用列表
原文:
docs.oracle.com/javase/tutorial/uiswing/components/list.html
JList向用户显示一组项目,以一个或多个列显示,供选择。列表可能有许多项目,因此它们经常放在滚动窗格中。
除了列表外,以下 Swing 组件向用户呈现多个可选择项目:组合框、菜单、表格和复选框或单选按钮组。要显示分层数据,请使用树。
以下图显示了使用列表的两个应用程序。本节将使用这些示例作为后续讨论的基础。
|  |  | 
|---|---|
| ListDialog(ListDialogRunner 使用) | ListDemo | 
试试这个:
- 
点击“启动”按钮运行 ListDemo,使用Java™ Web Start(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。 
- 
点击“启动”按钮运行 ListDialogRunner。或者,要自行编译和运行示例,请参考示例索引。 
- 
要打开 ListDialog,请点击标题为“给宝宝起个新名字...”的窗口中的按钮。 结果对话框是一个已经定制为标题为“名称选择器”的 ListDialog 实例。 
- 
在 ListDemo 中,尝试添加(招聘)和移除(解雇)一些项目。 
本节的其余部分讨论以下主题:
- 
创建一个模型 
- 
初始化列表 
- 
在列表中选择项目 
- 
向列表添加项目和从列表中移除项目 
- 
编写自定义单元格渲染器 
- 
列表 API 
- 
使用列表的示例 
创建一个模型
创建列表模型有三种方法:
- 
DefaultListModel — 一切都已经为您准备好了。本页中的示例使用 DefaultListModel。
- 
AbstractListModel — 你管理数据并调用“fire”方法。对于这种方法,你必须继承 AbstractListModel并实现从ListModel接口继承的getSize和getElementAt方法。
- 
ListModel — 你管理一切。 
初始化列表
这是从ListDialog.java中创建和设置其列表的代码:
list = new JList(data); //data has type Object[]
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.setVisibleRowCount(-1);
...
JScrollPane listScroller = new JScrollPane(list);
listScroller.setPreferredSize(new Dimension(250, 80));
代码将一个数组传递给列表的构造函数。该数组填充了从另一个对象传递过来的字符串。在我们的示例中,这些字符串恰好是男孩的名字。
其他JList构造函数允许你从Vector或遵循ListModel接口的对象初始化列表。如果用数组或向量初始化列表,构造函数会隐式创建一个默认列表模型。默认列表模型是不可变的 — 你不能向列表中添加、删除或替换项目。要创建一个可以单独更改项目的列表,请将列表的模型设置为可变列表模型类的实例,例如DefaultListModel的实例。你可以在创建列表时设置列表的模型,也可以通过调用setModel方法来设置。查看向列表添加项目和从列表中删除项目以获取示例。
调用setSelectionMode指定用户可以选择多少项,以及它们是否必须是连续的;下一节将更多地告诉你有关选择模式的信息。
调用setLayoutOrientation让列表以多列显示其数据。值JList.HORIZONTAL_WRAP指定列表应该从左到右显示其项目,然后换行到新行。另一个可能的值是JList.VERTICAL_WRAP,它指定数据在从上到下(通常)显示后换行到新列。以下图显示了这两种换行可能性,以及默认的JList.VERTICAL。
|  |  |  | 
|---|---|---|
| HORIZONTAL_WRAP | VERTICAL_WRAP | VERTICAL | 
与调用setLayoutOrientation结合使用,调用setVisibleRowCount(-1)使列表在屏幕上的可用空间中显示尽可能多的项目。setVisibleRowCount的另一个常见用法是指定列表的滚动窗格应该显示多少行列表更喜欢显示。
在列表中选择项目
列表使用一个ListSelectionModel的实例来管理其选择。默认情况下,列表选择模型允许同时选择任意组合的项目。您可以通过在列表上调用setSelectionMode方法来指定不同的选择模式。例如,ListDialog和ListDemo都将选择模式设置为SINGLE_SELECTION(由ListSelectionModel定义的常量),以便列表中只能选择一个项目。以下表格描述了三种列表选择模式:
| 模式 | 描述 | 
|---|
| SINGLE_SELECTION 
| 一次只能选择一个项目。当用户选择一个项目时,先取消选择任何先前选择的项目。 | 
|---|
| SINGLE_INTERVAL_SELECTION 
| 可以选择多个连续的项目。当用户开始新的选择范围时,先取消选择任何先前选择的项目。 | 
|---|
| MULTIPLE_INTERVAL_SELECTION 
| 默认值。可以选择任意组合的项目。用户必须明确取消选择项目。 | 
|---|
无论您的列表使用哪种选择模式,列表在选择更改时都会触发列表选择事件。您可以通过使用addListSelectionListener方法向列表添加一个 list selection listener 来处理这些事件。列表选择监听器必须实现一个方法:valueChanged。以下是ListDemo中监听器的valueChanged方法:
public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting() == false) {
        if (list.getSelectedIndex() == -1) {
        //No selection, disable fire button.
            fireButton.setEnabled(false);
        } else {
        //Selection, enable the fire button.
            fireButton.setEnabled(true);
        }
    }
}
一个用户操作(如鼠标点击)可能会生成许多列表选择事件。如果用户仍在操作选择,则getValueIsAdjusting方法返回true。这个特定程序只关心用户操作的最终结果,因此valueChanged方法只在getValueIsAdjusting返回false时执行操作。
因为列表处于单选模式,此代码可以使用getSelectedIndex来获取刚刚选择的项目的索引。当选择模式允许选择多个项目时,JList提供了其他设置或获取选择的方法。如果愿意,您可以在列表的列表选择模型上监听事件,而不是在列表本身上。ListSelectionDemo 是一个示例,展示了如何在列表选择模型上监听列表选择事件,并允许您动态更改列表的选择模式。
添加项目到列表和从列表中删除项目
我们之前展示的 ListDemo 示例具有内容可能会改变的列表。您可以在ListDemo.java中找到 ListDemo 的源代码。以下是创建可变列表模型对象、放入初始项目并使用列表模型创建列表的 ListDemo 代码:
listModel = new DefaultListModel();
listModel.addElement("Jane Doe");
listModel.addElement("John Smith");
listModel.addElement("Kathy Green");
list = new JList(listModel);
这个特定程序使用了 Swing 提供的DefaultListModel类的一个实例。尽管类名为DefaultListModel,但列表不会有DefaultListModel,除非您的程序明确这样做。如果DefaultListModel不符合您的需求,您可以编写一个符合ListModel接口的自定义列表模型。
下面的代码片段显示了在Fire按钮上注册的动作监听器的actionPerformed方法。粗体代码行会移除列表中的选定项目。方法中的其余行会在列表现在为空时禁用火按钮,并在不为空时进行另一个选择。
public void actionPerformed(ActionEvent e) {
    int index = list.getSelectedIndex();
    listModel.remove(index);
    int size = listModel.getSize();
    if (size == 0) { //Nobody's left, disable firing.
        fireButton.setEnabled(false);
    } else { //Select an index.
        if (index == listModel.getSize()) {
            //removed item in last position
            index--;
        }
        list.setSelectedIndex(index);
        list.ensureIndexIsVisible(index);
    }
}
这是由Hire按钮和文本字段共享的动作监听器的actionPerformed方法:
public void actionPerformed(ActionEvent e) {
    String name = employeeName.getText();
    //User did not type in a unique name...
    if (name.equals("") || alreadyInList(name)) {
        Toolkit.getDefaultToolkit().beep();
        employeeName.requestFocusInWindow();
        employeeName.selectAll();
        return;
    }
    int index = list.getSelectedIndex(); //get selected index
    if (index == -1) { //no selection, so insert at beginning
        index = 0;
    } else {           //add after the selected item
        index++;
    }
    listModel.insertElementAt(employeeName.getText(), index);
    //Reset the text field.
    employeeName.requestFocusInWindow();
    employeeName.setText("");
    //Select the new item and make it visible.
    list.setSelectedIndex(index);
    list.ensureIndexIsVisible(index);
}
此代码使用列表模型的insertElementAt方法在当前选择后插入新名称,或者如果没有选择,则在列表开头插入。如果您只想添加到列表末尾,可以使用DefaultListModel的addElement方法。
每当向列表添加、移除或修改项目时,列表模型都会触发列表数据事件。请参考如何编写列表数据监听器以获取有关监听这些事件的信息。该部分包含一个类似于ListDemo的示例,但添加了按钮,用于将项目在列表中上移或下移。
编写自定义单元格渲染器
列表使用一个称为单元格渲染器的对象来显示其每个项目。默认单元格渲染器知道如何显示字符串和图标,并通过调用toString来显示Object。如果您想要更改默认渲染器显示图标或字符串的方式,或者如果您想要不同于toString提供的行为,您可以实现一个自定义单元格渲染器。按照以下步骤为列表提供自定义单元格渲染器:
- 
编写一个实现 ListCellRenderer接口的类。
- 
创建您的类的一个实例,并使用该实例调用列表的 setCellRenderer。
我们没有提供具有自定义单元格渲染器的列表示例,但我们有一个具有自定义渲染器的组合框示例,组合框使用与列表相同类型的渲染器。请参阅提供自定义渲染器中描述的示例。
列表 API
以下表格列出了常用的JList构造函数和方法。您最有可能在JList对象上调用的其他方法是其超类提供的setPreferredSize之类的方法。请参阅 The JComponent API 以查看常用继承方法的表格。
列表的大部分操作由其他对象管理。列表中的项目由列表模型对象管理,选择由列表选择模型对象管理,大多数程序将列表放在滚动窗格中以处理滚动。在大多数情况下,您不需要担心模型,因为JList会根据需要创建它们,并且您使用JList的便利方法隐式与它们交互。
也就是说,使用列表的 API 分为以下几类:
- 
初始化列表数据 
- 
显示列表 
- 
管理列表的选择 
- 
管理列表数据 
初始化列表数据
| 方法或构造函数 | 目的 | 
|---|
| JList(ListModel) JList(Object[])
JList() | 创建一个指定初始列表项的列表。第二和第三个构造函数隐式创建一个不可变的ListModel;您不应随后修改传入的数组或Vector。
| void setModel(ListModel) ListModel getModel() | 设置或获取包含列表内容的模型。 | 
|---|---|
| void setListData(Object[]) void setListData(Vector) | 设置列表中的项目。这些方法隐式创建一个不可变的 ListModel。 | 
显示列表
| 方法 | 目的 | 
|---|---|
| void setVisibleRowCount(int) int getVisibleRowCount() | 设置或获取 visibleRowCount属性。对于VERTICAL布局方向,这设置或获取要显示的行数,而无需滚动。对于HORIZONTAL_WRAP或VERTICAL_WRAP布局方向,它定义了单元格如何换行。有关更多信息,请参见setLayoutOrientation(int)。此属性的默认值为VERTICAL。 | 
| void setLayoutOrientation(int) int getLayoutOrientation() | 设置或获取列表单元格的布局方式。可能的布局格式由 JList定义的值指定,包括VERTICAL(单列单元格;默认值)、HORIZONTAL_WRAP("报纸"风格,内容水平然后垂直流动)和VERTICAL_WRAP("报纸"风格,内容垂直然后水平流动)。 | 
| int getFirstVisibleIndex() int getLastVisibleIndex() | 获取第一个或最后一个可见项目的索引。 | 
| void ensureIndexIsVisible(int) | 滚动,以使指定的索引在此列表所在的视口内可见。 | 
管理列表的选择
| 方法 | 目的 | 
|---|---|
| void addListSelectionListener(ListSelectionListener) | 注册以接收选择更改的通知。 | 
| void setSelectedIndex(int) void setSelectedIndices(int[])
void setSelectedValue(Object, boolean)
void setSelectionInterval(int, int) | 将当前选择设置为指定的范围。使用setSelectionMode来设置可接受的选择范围。布尔参数指定列表是否应尝试滚动自身,以使所选项目可见。
| int getAnchorSelectionIndex() int getLeadSelectionIndex()
Object[] getSelectedValues() | 获取有关当前选择的信息。 |
| void setSelectionMode(int) int getSelectionMode() | 设置或获取选择模式。 可接受的值为: SINGLE_SELECTION,SINGLE_INTERVAL_SELECTION或MULTIPLE_INTERVAL_SELECTION(默认值),这些值在ListSelectionModel中定义。 | 
|---|---|
| void clearSelection() boolean isSelectionEmpty() | 设置或获取是否有任何项目被选中。 | 
| boolean isSelectedIndex(int) | 确定指定的索引是否被选中。 | 
管理列表数据
| 类或方法 | 目的 | 
|---|---|
| int getNextMatch(String, int, javax.swing.text.Position.Bias) | 给定起始索引,搜索列表中以指定字符串开头的项目并返回该索引(如果未找到字符串,则返回-1)。 第三个参数指定搜索方向,可以是 Position.Bias.Forward或Position.Bias.Backward。 例如,如果您有一个包含 6 个项目的列表,getNextMatch("Matisse", 5, javax.swing.text.Position.Bias.Forward)会在索引 5 处搜索字符串"Matisse",然后(如果需要)在索引 0、索引 1 等处搜索。 | 
| void setDragEnabled(boolean) boolean getDragEnabled() | 设置或获取确定是否启用自动拖动处理的属性。 有关更多详细信息,请参阅拖放和数据传输。 | 
使用列表的示例
这个表格展示了使用JList的示例以及这些示例的描述位置。
| 示例 | 描述位置 | 注释 | 
|---|---|---|
| SplitPaneDemo | 如何使用分割窗格 | 包含一个单选、不可变列表。 | 
| ListDemo | 本节 | 演示如何在运行时向列表中添加和删除项目。 | 
| ListDialog | 本节,如何使用 BoxLayout | 实现了一个带有单选列表的模态对话框。 | 
| ListDataEventDemo | 如何编写列表数据监听器 | 演示如何监听列表模型上的列表数据事件。 | 
| ListSelectionDemo | 如何编写列表选择监听器 | 包含一个列表和一个表,它们共享相同的选择模型。您可以动态选择选择模式。 | 
| SharedModelDemo | 使用模型 | 修改 ListSelectionDemo,使列表和表共享相同的数据模型。 | 
| CustomComboBoxDemo | 提供自定义渲染器 | 展示如何为组合框提供自定义渲染器。因为列表和组合框使用相同类型的渲染器,您可以学到的内容也可以应用到列表上。事实上,列表和组合框可以共享一个渲染器。 | 
查看使用 JavaFX UI 控件:列表视图教程,了解如何在 JavaFX 中创建列表。

 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号