首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中的JList和DefaultListModel的亲密关系

Java中的JList和DefaultListModel的亲密关系

作者头像
JavaEdge
发布2020-05-26 16:55:45
9810
发布2020-05-26 16:55:45
举报
文章被收录于专栏:JavaEdgeJavaEdge

对比JComboBox

JList从含义上看是一个列表,有点和JComboBox相似。

  • JComboBox的内容只能用一列显示出来
  • JList的内容可以多列显示 这就是JList存在的意义

构造器

一个对象数组

String[] words= { "quick", "brown", "hungry", "wild"};
JList wordList = new JList(words);

ListModel

  • 构造一个JList从指定显示元素从非空的model。 所有JList构造方法都委托给此方法。 此构造注册到列表中ToolTipManager ,允许本小区渲染器提供工具提示。
在这里插入图片描述
在这里插入图片描述

然后就是JList的多列显示,使用setLayoutOrientation(参数)方法来实现,共有3个参数,默认值是JList.VERTICAL,只用一列来显示,但不会自动滚动,需要添加滚动面板才能出现滚动条。setVisibleRowCount(n);方法可以设置最多显示多少行(若没有添加滚动面板,此设置无效,所有内容均会显示)。另外两个参数是JList.VERTICAL_WRAP和JList.HORIZONTAL_WRAP,其含义分别是“在保证行数不超过setVisibleRowCount(n)的情况下,纵向或横向排列元素”。此时滚动面板无效,因为行数永远不可能超标,因此滚动面板也永远不会出现 。比如最大显示行数为4,总共有5个元素,显示结果如下:

事件处理

与其他控件不同,他处理的不是Action事件,而是ListSelectionEvent事件,监听器为ListSelectionListener。

在这个事件处理过程中,又将鼠标的操作分为2种状态

  1. 按下鼠标不松手,在各个元素间拖动
  2. 松开鼠标

即,当你按下鼠标后,会触发一个事件,拖动到另一个控件,又触发一个事件,继续拖动则继续触发事件,最后松手,触发一个事件。

那么,如何区分这2种情况呢?

ListSelectionEvent提供了一个方法getValueIsAdjusting(),如果该方法返回true,则代表情况1;反之代表情况2。

请注意,JList控件不提供鼠标双击元素的处理事件,若要处理鼠标双击的情况,则应该添加鼠标监听器,代码如下:

 public void mouseClicked(MouseEvent evt)
{
   if (evt.getClickCount() == 2)
   {
      JList source = (JList) evt.getSource();
      Object[] selection = source.getSelectedValues();
      doAction(selection);
   }
}

AbstractListModel 类

没必要把元素存入一个数组,只要能临时把元素计算出来就行。 具体实现方法就是继承AbstractListModel类,实现其中的2个方法即可,代码如下:

class WordListModel extends AbstractListModel
{
   /**
      Constructs the model.
      @param n the word length
   */
   public WordListModel(int n) { length = n; }

   public int getSize()
   {
      return (int) Math.pow(LAST - FIRST + 1, length);
   }

   public Object getElementAt(int n)
   {
      StringBuilder r = new StringBuilder();;
      for (int i = 0; i < length; i++)
      {
         char c = (char)(FIRST + n % (LAST - FIRST + 1));
         r.insert(0, c);
         n = n / (LAST - FIRST + 1);
      }
      return r;
   }

   private int length;
   public static final char FIRST = 'a';
   public static final char LAST = 'z';
}

接下来就是元素的插入和删除,看似简单的功能,实现起来可不容易。

天真的想法

我用一个数组构造JList,那么我只要将数组中的元素增加或减少,那么JList的内容自然会增加或减少。 这绝对是个错误的认识,对数组内容的修改不会影响到JList。

那么正确的做法是什么呢?

DefaultListModel 类

用一个特别的类来构造JList,也就是DefaultListModel类,然后对这个类的内容添加或者减少,那么JList会很快的做出响应。

为什么这个类会这么神奇呢? 他继承自AbstractListModel类,内部用一个Vector来存储数据

在这里插入图片描述
在这里插入图片描述

在它的添加元素方法中

在这里插入图片描述
在这里插入图片描述

调用了父类的fireIntervalAdded方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

同理,在他的删除元素方法中,他调用了父类的fireIntervalRemoved方法,因此可以将JList的内容刷新。

最后就是

绘制元素

在JList中,内部显示的每一个元素叫做一个Cell。

如果我想让内部元素的显示方式更完美一些,比如居中显示,比如每一个Cell字体颜色不一样,那么我们就要借助JList的setCellRenderer方法来实现。

该方法接受一个实现了ListCellRenderer接口的参数,而该接口只有一个方法getListCellRendererComponent,但是,该方法的实现是比较简单的,他只需要构造一个Component对象并返回这个对象,这个对象就是一个Cell。

因此,真正的难点在于,如何修改这个Component的内部显示方式,从而使得他可以满足一个Cell的显示方式。 一般来讲,我们都是用一个JPanel作为绘制Cell的对象,因为在JPanel上显示文字和图像都是很方便的。

最后说一个小技巧,我们实现一个类,从JPanel继承而来,同时又实现了ListCellRenderer接口,那么我们只用实现这一个类就可以了,到时候把自己返回。下面我们来看一下具体的代码:

  class FontCellRenderer extends JPanel implements ListCellRenderer
 {
    public Component getListCellRendererComponent(JList list, Object value, int index,
       boolean isSelected, boolean cellHasFocus)
    {
       text = (String)value;
       background = isSelected ? list.getSelectionBackground() : list.getBackground();
       foreground = isSelected ? list.getSelectionForeground() : list.getForeground();
       return this;
    }

    public void paintComponent(Graphics g)
    {
       g.setColor(background);
       g.fillRect(0, 0, getWidth(), getHeight());  //设置背景色
       g.setColor(foreground);
       g.drawString(text, 5, 15);   //在制定位置绘制文本
    }

    public Dimension getPreferredSize()
    {
       return new Dimension(30, 20);   //Cell的尺寸
    }

    private String text;
    private Color background;
    private Color foreground;
 }

我们定义了一个类,继承自JPanel并实现了指定接口。在这个类里面有3个私有变量,分别存放Cell的内容,Cell的前景色和背景色。因为Cell的绘制完全由程序员来实现,因此这些内容都是必须的。之后就是接口中规定的getListCellRendererComponent方法,这个方法其实很简单,就是对三个变量进行赋值并返回自己。其中前景色和背景色又分为2中情况,就是选中时和未选中时,这点需要注意。接下来我们有实现了2个方法,其中PaintComponent负责Cell的绘制,GetPreferedSize负责设置Cell的尺寸。对于尺寸有一点需要注意,上述代码给的是一个固定尺寸。如果尺寸不固定有变化,那么最终会选择最大的那个尺寸作为所有Cell的尺寸。如果你想在绘制Cell的时候加入什么花样,那么尽管在PaintComponent中施展你的才华吧,上述代码只提供了在指定位置绘制文本,算是抛砖引玉了。这里也有一点需要注意,那就是JPanel本身提供的“居中”,“设置背景色”,“设置前景色”,等方法一律失效,所有的功能一律要使用JAVA 2D来实现,算是一点小小的难度。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对比JComboBox
  • 构造器
    • 一个对象数组
      • ListModel
      • 事件处理
      • AbstractListModel 类
        • 天真的想法
        • DefaultListModel 类
        • 绘制元素
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档