免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3557 | 回复: 1
打印 上一主题 下一主题

turbochen(原作)制作更酷的JList界面 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2002-09-03 15:46 |只看该作者 |倒序浏览
制作更酷的JList界面    turbochen(原作)
  
关键字     java,listcellrenderer,callback
  



内容:
1。绘制器的工作原理。
2。用自订的绘制器更换JList和JComboBox的外观。
3。让新的外观响应鼠标事件。

借助swing体系的mvc设计理念,为组件更换不同的外观成为轻而易举的事情。本文主要以JList和JComboBox为例讲解ListCellRenderer的原理与用法.


一、绘制器的工作原理
不管是JList还是JComboBox,它们都用到了ListCellRenderer,因为JComboBox本身就是由一个下拉式的JList和TextField组成的. 在这里,它们使用了callback的机制。

callback的一是种常见的方式是在A类中调用B类中的方法,在A类中先要登记一个(也可以是多个)B类的实例引用,在需要调用时再通过该实例来调用它的内部方法.这样的机制在很多的设计模式中都有用到,如Observer等.还有AWT的事件机制也用到了callback.

要实现callback,通常将B类设计成一个能被callback的接口.在JList的绘制器中,swing提供了一个ListCellRenderer接口,
public interface ListCellRenderer {
    Component getListCellRendererComponent(
        JList list,
        Object value,
        int index,
        boolean isSelected,
        boolean cellHasFocus)&#59;
}
这个接口只提供一个方法,我们只要实现了这个接口,并将它的实例引用传给JList,就可以将JList替换成不同的样式了.看一下ListCellRenderer是如何工作的,

在绘制JList的每个Cell之前,它会去调用getListCellComponent( ),得到一个Component,并
将这个Component绘制在正确的位置.因为getListCellComponent( )返回的是Component,所以我们几乎可以扩展任意一个Component,来改变JList,JComboBox等的外观.

二、制作自已的绘制器
我们现在要想让JList中显示一组学生名单,同时每个名单前显示该学生的图标.如下图所示

我们先来想一想,Swing中有什么组件既可以显示图标也可以显示文字? JLabel.对了。我们就用JLabel作为JList的绘制器, 看看我扩展的JLabel类,它实现了ListCellRenderer接口:
        /* 可以显示图标的ListCell绘制器 */
        public class IconListItemRenderer extends JLabel implements ListCellRenderer
        {
            private Border
                selectedBorder = BorderFactory.createLineBorder(Color.blue,1),
                emptyBorder = BorderFactory.createEmptyBorder(1,1,1,1)&#59;

            public Component getListCellRendererComponent(
                        JList list,
                        Object value,
                        int index,
                        boolean isSelected,
                        boolean cellHasFocus)
                {

                IconListItem item = (IconListItem)value&#59;
                this.setIcon(item.getIcon())&#59;
                this.setText(item.getText())&#59;

                if ( isSelected ) setBorder (selectedBorder)&#59;
                else setBorder(emptyBorder)&#59;
                return this&#59;
            }
        }
大家看到,getListCellRendererComponent方法会传入几个参数,我们就用它传入的几个参数设置JLabel的外观:图标与文字。在这个类中,我们用一个IconListItem接收调用者传过来的value,
        IconListItem item = (IconListItem) value&#59;
IconListItem是我另外定义好的一个类,它用来存放每一个List Item的值,
        import javax.swing.*&#59;
        public class IconListItem
        {
            Icon icon&#59;
            String text&#59;
            public IconListItem(Icon icon, String text)
            {
                this.icon = icon&#59;
                this.text = text&#59;
            }
            public Icon getIcon() { return icon&#59;}
            public String getText() { return text&#59;}
            public void setIcon(Icon icon){ this.icon = icon&#59;}
            public void setText(String text){ this.text = text&#59; }
        }
这样的话,我就可以用getIcon()和getText()方法取得每个List Item的值了,
        IconListItem item = (IconListItem) value&#59;
        this.setIcon(item.getIcon())&#59;
        this.setText(item.getText())&#59;

至此,我们就可以用以下方法方便的更换JList的外观了,
        JList list = new JList()&#59;
        list.setCellRenderer(new IconListItemRenderer())&#59;  file://安装我们自订的cellRenderer
        DefaultListModel listModel = new DefaultListModel()&#59;
        list.setModel(listModel)&#59;
        IconListItem item = new IconListItem(new ImageIcon(...),"John&quot&#59;
        listModel.addElement(item)&#59;    // 为List增加Item
        ...
由于JComboBox也有一个下拉式清单,所以它的清单也是用ListCellRenderer来绘制的,所以我们也可以将这个IconListItemRenderer给它用:
        JComboBox list = new JComboBox()&#59;
        list.setRenderer(new IconListItemRenderer())&#59;  //装我们自订的cellRenderer
        DefaultComboBoxModel comboModel = new DefaultComboBoxModel()&#59;
        list.setModel(comboModel)&#59;
        IconListItem item = new IconListItem(new ImageIcon(...),"John&quot&#59;
        comboModel.addElement(item)&#59;    // 为List增加Item
        ...
注意,JComboBox安装绘制器时是用setRenderer()方法,JList是用setCellRenderer()方法,名字稍有不同.

以上大家看到的是可显示一个图标的List, 下面我们再看一个可显示CheckBox的List是如何实现的,以下是例图:

代码实现:
        import javax.swing.*&#59;
        import java.awt.*&#59;
        import javax.swing.border.*&#59;
        import java.awt.event.*&#59;
        /* 可以显示CheckBox的ListCell绘制器 */
        public class CheckListItemRenderer extends JCheckBox implements ListCellRenderer
        {
            public Component getListCellRendererComponent(
                        JList list,
                        Object value,
                        int index,
                        boolean isSelected,
                        boolean cellHasFocus)
            {
                CheckListItem item = (CheckListItem)value&#59;
                this.setSelected(item.getCheck())&#59;
                this.setText(item.getText())&#59;
                this.setFont(list.getFont())&#59;
                this.setEnabled(list.isEnabled())&#59;
                return this&#59;
            }
        }
同样这个绘制器中用一个CheckListItem存放每个List Item的值:
        public class CheckListItem
        {
            boolean check&#59;
            String text&#59;
            public CheckListItem(boolean check, String text)
            {
                this.check = check&#59;
                this.text = text&#59;
            }
            public boolean getCheck() { return check&#59; }
            public void setCheck(boolean _check) { check = _check&#59; }
            public String getText() { return text&#59; }
            public void setText(String _text) { text = _text&#59; }
        }
这个绘制器的用法同IconListItemRenderer一样,不多讲了.

三、让自订的绘制器响就鼠标事件
使用以上的CheckListItemRenderer时,大家会发现,虽然List中可以显示CheckBox了,但是用鼠标点击时,没有反应! 现在我就来解决这个问题.要澄清的是,ListCellRenderer本身是只返回一个组件用来绘制一个单元格,不能对用户动作作出反应。为些我们必须在JList上下功夫.JList有一个addMouseListener()方法可以为自身安装一个鼠标监听器,在这里,我实现了一个MouseAdapter,并让它对mousePressed作出响应:
        class CheckListMouseListener extends MouseAdapter
        {
              public void mousePressed(MouseEvent e) {
                JList list = (JList) e.getSource()&#59;
                int index = list.locationToIndex(e.getPoint())&#59;
                CheckListItem item = (CheckListItem)list.getModel().getElementAt(index)&#59;
                item.setCheck(! item.getCheck())&#59;
                Rectangle rect = list.getCellBounds(index, index)&#59;
                list.repaint(rect)&#59;
            }
        }
使用时, 用addMouseListener(new CheckListMouseListener())就行了.

除了包含CheckBox的JList外,许多情况下,我们需要为自制的绘制器加上动作响应,如我们要实现一个可编辑的JList, 除了要扩展JTextField及实现ListCellRenderer之外,还要写一个鼠标监听器和键盘监听器,当双击时,JList变成可编辑状态,当回车时,还原成不可编辑状态.具体的实现过程,我就不详叙了,留给大家作练习.


上面内容,我写了一个演示程序,下面是它的演示画面,

你可以从这里下载完整的演示程序.


论坛徽章:
0
2 [报告]
发表于 2006-03-22 11:21 |只看该作者

求助:可编辑的JList

>>>>除了包含CheckBox的JList外,许多情况下,我们需要为自制的绘制器加上动作响应,如我们要实现一个可编辑的JList, 除了要扩展JTextField及实现ListCellRenderer之>>>>>>外,还要写一个鼠标监听器和键盘监听器,当双击时,JList变成可编辑状态,当回车时,还原成不可编辑状态.具体的实现过程,我就不详叙了,留给大家作练习.


楼主,能否给出程序框架???? 我尝试了一下,还是没法实现“可编辑”功能。

谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP