文档

Java™教程
隐藏目录
如何使用列表
指南:使用Swing创建GUI
教程:使用Swing组件
部分:如何使用各种组件

如何使用列表

JList是向用户显示一组可选择的项目的组件,这些项目可以在一个或多个列中显示。列表可以有很多项目,所以它们通常被放在滚动窗格中。

除了列表,以下Swing组件也向用户提供了多个可选择的项目:组合框菜单表格以及一组复选框单选按钮。要显示分层数据,请使用

下图显示了使用列表的两个应用程序。本节将以这些示例为基础进行后续讨论。

ListDialog的快照,显示一个简单的列表 ListDemo的快照,可以添加和删除列表项
ListDialog
(由ListDialogRunner使用)
ListDemo

试试看: 
  1. 点击“启动”按钮使用Java™ Web Start运行ListDemo(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引启动ListDemo示例
  2. 点击“启动”按钮运行ListDialogRunner。或者,要自己编译和运行示例,请参考示例索引启动ListDialogRunner示例
  3. 要打开ListDialog,请点击名为“Name That Baby”的窗口中的“选择一个新名称…”按钮。
    结果对话框是一个已经自定义标题为“名称选择器”的ListDialog实例。
  4. 在ListDemo中,尝试添加(招聘)和删除(解雇)几个项目。

创建模型

有三种方式可以创建列表模型:

初始化列表

下面是来自ListDialog.java的代码,用于创建和设置列表:

list = new JList(data); //data的类型为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
HORIZONTAL_WRAP VERTICAL_WRAP VERTICAL

结合调用setLayoutOrientation方法,调用setVisibleRowCount(-1)可以使列表在屏幕上显示尽可能多的项目。另一个常见的用法是使用setVisibleRowCount指定列表首选显示的行数。

选择列表中的项目

列表使用ListSelectionModel的实例来管理其选择。默认情况下,列表选择模型允许同时选择任意组合的项目。您可以通过在列表上调用setSelectionMode方法来指定不同的选择模式。例如,ListDialogListDemo都将选择模式设置为SINGLE_SELECTION(由ListSelectionModel定义的常量),以便只能选择列表中的一个项目。下表描述了三种列表选择模式:

模式 描述
SINGLE_SELECTION
Single selection means only one item can be selected at once

一次只能选择一个项目。当用户选择一个项目时,任何先前选择的项目都会先被取消选择。
SINGLE_INTERVAL_SELECTION
Single interval selection means multiple, contiguous items can be selected at once

可以选择多个连续的项目。当用户开始新的选择范围时,任何先前选择的项目都会先被取消选择。
MULTIPLE_INTERVAL_SELECTION 
Multiple interval selection means any combination of items can be selected at once

默认。可以选择任意组合的项目。用户必须显式取消选择项目。

无论列表使用哪种选择模式,列表在选择改变时都会触发列表选择事件。您可以通过使用addListSelectionListener方法将一个列表选择监听器添加到列表中来处理这些事件。列表选择监听器必须实现一个方法:valueChanged。下面是ListDemo中监听器的valueChanged方法:

public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting() == false) {

        if (list.getSelectedIndex() == -1) {
        //没有选择,禁用fire按钮。
            fireButton.setEnabled(false);

        } else {
        //选择了,启用fire按钮。
            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的实例。尽管类名中含有"Default",但列表只有在程序明确指定时才具有DefaultListModel。如果DefaultListModel不符合您的需求,您可以编写一个自定义的列表模型,该模型必须符合ListModel接口的规范。

下面的代码片段显示了在Fire按钮上注册的动作监听器的actionPerformed方法。粗体代码行删除了列表中选定的项目。方法中的其余行在列表为空时禁用火按钮,并在列表不为空时进行另一选择。

public void actionPerformed(ActionEvent e) {
    int index = list.getSelectedIndex();
    listModel.remove(index);

    int size = listModel.getSize();

    if (size == 0) { //没有剩下的,禁用火焰。
        fireButton.setEnabled(false);

    } else { //选择一个索引。
        if (index == listModel.getSize()) {
            //在最后位置删除的项目
            index--;
        }

        list.setSelectedIndex(index);
        list.ensureIndexIsVisible(index);
    }
}

下面是共享Hire按钮和文本字段的动作监听器的actionPerformed方法:

public void actionPerformed(ActionEvent e) {
    String name = employeeName.getText();

    //用户没有输入唯一名称...
    if (name.equals("") || alreadyInList(name)) {
        Toolkit.getDefaultToolkit().beep();
        employeeName.requestFocusInWindow();
        employeeName.selectAll();
        return;
    }

    int index = list.getSelectedIndex(); //获取选择的索引
    if (index == -1) { //没有选择,所以插入到开头
        index = 0;
    } else {           //在选择的项目之后添加
        index++;
    }

    listModel.insertElementAt(employeeName.getText(), index);

    //重置文本字段。
    employeeName.requestFocusInWindow();
    employeeName.setText("");

    //选择新项目并使其可见。
    list.setSelectedIndex(index);
    list.ensureIndexIsVisible(index);
}

此代码使用列表模型的insertElementAt方法在当前选择之后插入新名称,或者如果没有选择,则在列表开头插入。如果只想添加到列表的末尾,可以改为使用DefaultListModeladdElement方法。

每当列表中添加、删除或修改项目时,列表模型都会触发列表数据事件。有关监听这些事件的信息,请参考如何编写列表数据监听器。该部分包含了一个类似于ListDemo的示例,但添加了在列表中将项目上移或下移的按钮。

编写自定义单元格渲染器

列表使用一个称为单元格渲染器的对象来显示其每个项目。默认的单元格渲染器知道如何显示字符串和图标,并通过调用toString来显示Object。如果您想更改默认渲染器显示图标或字符串的方式,或者如果您想要与toString提供的行为不同的行为,您可以实现一个自定义的单元格渲染器。按照以下步骤为列表提供自定义的单元格渲染器:

我们没有提供自定义单元格渲染器的列表示例,但我们有一个自定义渲染器的组合框示例 —— 组合框使用与列表相同类型的渲染器。请参阅提供自定义渲染器中描述的示例。

列表 API

下表列出了常用的JList构造函数和方法。您最有可能在JList对象上调用的其他方法是其超类提供的setPreferredSize等方法。请参阅JComponent API以查看常用继承方法的表格。

列表的大部分操作由其他对象管理。列表中的项目由列表模型对象管理,选择由列表选择模型对象管理,大多数程序将列表放在滚动窗格中以处理滚动。在大多数情况下,您无需担心模型,因为JList会根据需要创建它们,并使用JList的便利方法隐式与它们交互。

话虽如此,使用列表的 API 可分为以下几类:

初始化列表数据
方法或构造函数 目的
JList(ListModel)
JList(Object[])
JList(Vector)
JList()
创建包含指定初始列表项的列表。第二个和第三个构造函数隐式创建一个不可变的ListModel;您不应在随后修改传入的数组或Vector
void setModel(ListModel)
ListModel getModel()
设置或获取包含列表内容的模型。
void setListData(Object[])
void setListData(Vector)
设置列表中的项目。这些方法隐式创建一个不可变的ListModel
显示列表
方法 目的
void setVisibleRowCount(int)
int getVisibleRowCount()
设置或获取visibleRowCount属性。对于VERTICAL布局方向,设置或获取不需要滚动即可显示的首选行数。对于HORIZONTAL_WRAPVERTICAL_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)setSelectionModeint getAnchorSelectionIndex()
int getLeadSelectionIndex()
int getSelectedIndex()
int getMinSelectionIndex()
int getMaxSelectionIndex()
int[] getSelectedIndices()
Object getSelectedValue()
Object[] getSelectedValues()void setSelectionMode(int)
int getSelectionMode()SINGLE_SELECTIONSINGLE_INTERVAL_SELECTIONMULTIPLE_INTERVAL_SELECTIONListSelectionModelvoid clearSelection()
boolean isSelectionEmpty()boolean isSelectedIndex(int)
管理列表数据
类或方法 目的
int getNextMatch(String, int, javax.swing.text.Position.Bias) 在给定的起始索引处搜索列表中以指定字符串开头的项,并返回该索引(如果未找到字符串,则返回-1)。第三个参数指定搜索方向,可以是Position.Bias.ForwardPosition.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中创建列表。


上一页: 如何使用分层面板
下一页: 如何使用菜单