软件开发

当前位置:首页 > 软件开发

《Java核心技术高级特性》(第六章)(续)

6.1.3插入和移除值

不能直接编辑列表值的集合。相反地,必须先访问模型,然后再添加或移除元素。不过,说起来容易做起来难。假设想要向列表中添加更多的选项值,那么首先可以通过下面的语句获得对该模型的-一个引用:

ListModel<string> mode1■list.getMode10;

但是,正如在前一小节中看到的那样,这样做并不能带来任何好处,因为ListMode1接口并未提供任何插人或移除元素的方法。毕竟,列表模型的整个重点是它不需要存储任何元素。

让我们试试另- -种方法吧。 JList 有一个构造器可以接受- -个对象向量作为参数:

Vector<String> values = new Vector<String>0;
values. addE1 ement("quick");
values . addE1 ement("brown");
JList<String> 1ist■new JList<>(values);

现在,就可以通过编辑这个向量来添加或移除元素了,不过列表并不知道正在发生的事情,因此也就无法对这种变化做出响应。尤其是,当你向列表中添加元素时,列表无法更新它的显示视图。因此,这个构造器也不太实用。

取而代之的是,应该构建- -个DefaultListMode1对象,填人初始值,然后将它与一个列表关联起来。DefaultListMode1 类实现了ListMode1接口,并管理着- -个对象集合。

DefaultlistModel<String> model = new DefaultListMode1<>0;
model. . addElement(C"quick");
model ,addE1ement("brown");
JList<String> list ■new JList<>(mode1]);

现在,就可以从mode1对象中添加或移除元素值了。然后,mode1 对象会告知列表发生了哪些变化,接着,列表会对自身进行重新绘制。

nodel.removeElement("quick");
nodel . addE1ement("sI1ow");

由于历史遗留问题,DefaultListMode1类使用的方法名和集合类的方法名并不相同。默认的列表模型在内部是使用-个向量来存储元素值的。

➊警告: JList存在着多种构造器方法,可以用一个对象或字符串数组或向量来构建列表。你可能会认为这些构造器是使用一个DefaultListMode1来存储这些元素值的。但情况并非如此,这些构造器构建了一个普通而简单的模型,它可以访问元素值,但是如果内容发生了改变,它并不提供任何通知机制。例如,下面这段代码是使用一个Vector来构造JList的构造器的代码:

public JList(fina1 Vector<? extends E> 1istData)
this (new AbstractListMode1<E>0
public int getSizeO { return listData.size0; }
public E getElementAt(int i) { return listData.elementAt(i); }
);

这意味着,在列表被创建之后,如果要修改向量里面的内容,那么这个列表在被完全重新绘制之前,会将旧值和新值混在一起,杂乱无章地显示出来。(上面构造器中的关键字final并不能阻止你在其他地方对这个向量进行修改,它仅仅表示构造器本身不能修改1istData引用的值;一定要有这个关键宇是因为11stData对象是在内部类中使.用的。)

API javax.swing.JList<E> 1.2

●ListMode1 <E>getMode1( )

获取该列表的模型。

API javax swing.DefaultListModel<E> 1.2

●void addE 1 ement(E obj )

向该模型的末端添加一一个对象。

●boolean removeE 1 ement(Object obj )

从模型中移除第一次出现的给定对象。如果该模型中包含此对象,则返回true,否则

返回false。

6.1.4值 的绘制

到目前为止,我们在本章看到的列表包含的都是字符串。实际上只需传递一个用Icon对象填充的数组或向量,便可以很容易地显示一个图标列表。更有意思的是,可以很容易地用任何图形来表示你的列表值。

尽管JList类可以自动地显示字符串和图标,但是仍然需要在JList对象中安装- -个用于所有自定义图形的列表单元格绘制器。列表单元格绘制器可以是任何-一个实现了下面接口的类:

interface ListCel1Renderer<E>
Component getListCel1RendererComponent(List<? extends E> 1list,
E value, int index, boolean isected, boolean cellHasFocus);

这个方法会为每个单元格都调用一次,它返回-一个用于绘制单元格内容的构件。无论何时,只要某个单元格需要被绘制,该构件就会被置于合适的位置。

实现单元格绘制器的一- 种方法是创建一一个扩展了JComponent的类,如下所示:

class MCel1Renderer extends JComponent implenents ListCel1Renderer<Type>
public Component getlistCel1RendererComponent(List<? extends Type> list,
Type value, int index, boolean isSelected, boolean celTHasFocus)
stash away information needed for painting and size measurement
return this;
public void paintComponent(Graphics g)
paint code
public Dimension getPreferredsize0
size measurement code
instance fields

在程序清单6-4中,我们按照字体的实际外观显示这些选择字体(参见图64)。在paintComponent方法内部,我们用每种字体显示其自身的名称。我们还需要确保JList类的外观与常用颜色相匹配。通过调用JList类中的getF oreground/

getBackground和getSelection F oreground/

getSe1 ecti onBackground方法可以获取这些颜色。在getPreferredSize方法中,我们需要使用在卷I第7章中介绍的技术来测量字符串的大小。

如果要安装单元格绘制器,只需调用setCe11Renderer方法即可:

fontList.setCel1Renderer(new FontCellRenderer0);


相关内容

文章评论

表情

共 0 条评论,查看全部
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~