Java中做一个带有图标和文字的JList列表(类似文件管理器列表或者QQ好友列表)

        这几天研究了一下JList,发现自定义它的样式真的是很难的过程。不过在此我想把我研究的东西整理并分享一下,希望对大家有所帮助。

一、列表基本操作

        首先我们来创建一个JList对象,并给它加一个滚动条:

JList jl=new JList();        //实例化JList对象
JScrollPane jsp=new JScrollPane();        //实例化滚动条对象
jsp.setViewportView(jl);        //把JList加到滚动条里面

再把滚动条对象jsp加入到JPanel对象即可。

不过如何给JList加元素呢?通常我们使用默认数据模型DefaultListModel对象,在默认数据模型对象里面添加元素(addElement()方法),再把模型对象放入JList的构造方法里面,那么,我把上面代码改变如下:

DefaultListModel dfl=new DefaultListModel();        //实例化默认数据模型对象
dfl.addElement("a");        //给模型加入字符串元素a
dfl.addElement("b");        //给模型加入字符串元素b
JList jl=new JList(dfl);        //实例化JList对象,构造方法写入默认数据模型对象
JScrollPane jsp=new JScrollPane();        //实例化滚动条对象
jsp.setViewportView(jl);        //把JList加到滚动条里面

这样就实现了最简单的文字列表了:

观察DefaultListModel对象的addElement()方法,发现参数是Object,也就是说他可以装任何类型数据。我试着把图片对象(ImageIcon)和文件对象(File)装进去试试,改变代码如下:

DefaultListModel dfl=new DefaultListModel();        //实例化默认数据模型对象
dfl.addElement("a");        //给模型加入字符串元素a
dfl.addElement("b");        //给模型加入字符串元素b
dfl.addElement(new ImageIcon("res\\testicon.png"));        //给模型加入图片类型元素
dfl.addElement(new File("res\\testicon.png"));        //给模型加入文件类型元素
JList jl=new JList(dfl);        //实例化JList对象,构造方法写入默认数据模型对象
JScrollPane jsp=new JScrollPane();        //实例化滚动条对象
jsp.setViewportView(jl);        //把JList加到滚动条里面

效果:

可见,不同类型数据元素有着不同的显示和绘制方法,其余大家可以自行尝试。

二、重写渲染器以实现自定义列表样式

不过怎么自定义这个列表使其又有图片又有文字呢?

首先我们要知道,JList有一个渲染器(DefaultListCellRenderer),它决定着JList如何显示内容。要想自定义这个列表样式,我们就必须 重写这个渲染器。

在这个渲染器里面有一个getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus)方法,它决定着列表如何显示等等。

在此之前我们必须了解getListCellRendererComponent方法自带的五个参数(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus)分别是什么意义,否则我们不知道从何下手来自定义列表。

查看官方文档得知意义如下:

JList<? extends Object> list表示我们正在创建的JList对象,其中<? extends Object>表示我们的列表对象元素类型是任意的。这个参数基本上我们不会使用。

Object value这个代表了我们列表中的元素,可以是任何类型,他是list.getModel().getElementAt(index)的返回值。

int index表示列表中被我们鼠标选择的元素的索引,例如列表中第一个元素被选中了,则这个值就是0。

boolean isSelected表示我们的列表是否有元素被选中。

boolean cellHasFocus表示我们的列表是否有焦点(???)。

知道了这5个参数的意义,我们就可以很好的用他们来重写我们的渲染器了。当然,刚开始这里有一点我一直弄不明白,就是上面的参数Object value的意义,因为他是Object,所以我们可能难以判断其真实的、具体的类型,那么怎么来使用呢?于是我想看看它的“真面目”,或者是它包含着什么信息。

不过我们知道了,他是list.getModel().getElementAt(index)的返回值,所以我决定先在JList所在的类里面试试这个方法是什么。

我又将上述JList相关代码下面加上了这个方法,改变如下:

DefaultListModel dfl=new DefaultListModel();        //实例化默认数据模型对象
dfl.addElement("a");        //给模型加入字符串元素a
dfl.addElement("b");        //给模型加入字符串元素b
dfl.addElement(new ImageIcon("res\\testicon.png"));        //给模型加入图片类型元素
dfl.addElement(new File("res\\testicon.png"));        //给模型加入文件类型元素
JList jl=new JList(dfl);        //实例化JList对象,构造方法写入默认数据模型对象
JScrollPane jsp=new JScrollPane();        //实例化滚动条对象
jsp.setViewportView(jl);        //把JList加到滚动条里面
/**
    使用Object的toString()方法,用控制台输出获取到的表格的第1、2、3、4个内容。
*/
System.out.println(jl.getModel().getElementAt(0).toString());        
System.out.println(jl.getModel().getElementAt(1).toString());
System.out.println(jl.getModel().getElementAt(2).toString());
System.out.println(jl.getModel().getElementAt(3).toString());

然后控制台输出如下:

我们发现,通过toString()方法,表格内容包含的文字信息被输出了。也就是说,我们通过toString()方法,就可以吧渲染器里面value值给以String形式获取了!

好了,解除了疑惑,我们现在就要开始自己重写渲染器,来自定义列表样式了!

新建一个类,我这里起名为CRTest,然后重写方法:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //继承渲染器类
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重写渲染器的方法

        return this;
    }
}

需要注意的是,默认渲染器类继承了JLabel,因此在这个里面设置样式我们就用JLabel的方法即可。

现在给列表加上图片,改变渲染器代码如下:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //继承渲染器类
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重写渲染器的方法
        setText(value.toString());		//设置文字(获取每个元素文字信息将其显示)
        setIcon(new ImageIcon("res\\testicon.png"));        //设置图标
        return this;
    }
}

然后再JList所在的类设置渲染器为我们自己写的渲染器,加上下面这句话:

jl.setCellRenderer(new CRTest());        //设置渲染器为我们自己的

效果如下:

通过设置图片大小、背景颜色等等,我们可以实现列表每个元素的图标的自适应、设置鼠标放上去时和被选中时显示的颜色等等。

改变渲染器代码如下:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //继承渲染器类
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重写渲染器的方法
        setText(value.toString());		//设置文字(获取每个元素文字信息将其显示)
        ImageIcon ico=new ImageIcon("res\\testicon.png");		//实例化一个ImageIcon对象
        Image img=ico.getImage();		//实例化Image对象获取ico对象的内容 
        img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把图片全部缩放为25x25
        ico.setImage(img);		//ImageIcon对象重新获取缩放后图标
        setIcon(ico);		//设置图标
        if(isSelected) {		//当某个元素被选中时
            setForeground(Color.WHITE);		//设置前景色(文字颜色)为白色
            setBackground(Color.BLUE);		//设置背景色为蓝色
            System.out.println(index+"被选中");
        } else {		//某个元素未被选中时(取消选中)
            setForeground(Color.BLACK);		//设置前景色(文字颜色)为黑色
            setBackground(Color.WHITE);		//设置背景色为白色
        }
        return this;
    }
}

 效果:

还可以添加如下方法设置每个单元格水平、垂直位置关系,大家可以加入自行尝试:

setVerticalTextPosition(SwingConstants.CENTER);        //垂直
setHorizontalTextPosition(SwingConstants.CENTER);        //水平
//上面CENTER意思是设置到中间,改变这个CENTER可以换位其它位置

如果我想每一个元素图标不同怎么办呢?那也很简单,在渲染器里面判断value值,然后分别设置即可,我改变代码如下:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //继承渲染器类
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重写渲染器的方法
        setText(value.toString());		//设置文字(获取每个元素文字信息将其显示)
        if(value.toString().equals("a")) {		//判断value(列表值)来分情况设置不同图标
            ImageIcon ico=new ImageIcon("res\\testicon.png");		//实例化一个ImageIcon对象
            Image img=ico.getImage();		//实例化Image对象获取ico对象的内容 
            img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把图片全部缩放为25x25
            ico.setImage(img);		//ImageIcon对象重新获取缩放后图标
            setIcon(ico);		//设置图标
        } else {
            ImageIcon ico=new ImageIcon("res\\testicon-2.png");		//实例化一个ImageIcon对象
            Image img=ico.getImage();		//实例化Image对象获取ico对象的内容 
            img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把图片全部缩放为25x25
            ico.setImage(img);		//ImageIcon对象重新获取缩放后图标
            setIcon(ico);
        }
        if(isSelected) {		//当某个元素被选中时
            setForeground(Color.WHITE);		//设置前景色(文字颜色)为白色
            setBackground(Color.BLUE);		//设置背景色为蓝色
            System.out.println(index+"被选中");
        } else {		//某个元素未被选中时(取消选中)
            setForeground(Color.BLACK);		//设置前景色(文字颜色)为黑色
            setBackground(Color.WHITE);		//设置背景色为白色
        }
        return this;
    }
}

效果:

这样,我们就完成了列表自定义了!

我们还可以设置列表是横排还是竖着显示。回到JList所在的类,通过JList的setLayoutOrientation()方法和setVisibleRowCount()方法实现。如下,我加入下面两行代码:

jl.setLayoutOrientation(JList.HORIZONTAL_WRAP);		//设置表格横着排列元素
jl.setVisibleRowCount(1);		//设置总行数为1行

 效果:

setVisibleRowCount设置为2时:

其余大家可以自己尝试。

那么以上就是自定义列表的方法了,我们总共有2个类,其中注意渲染器类重写时每个参数的意义!这非常重要!

完整代码:

主类:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
public class JListObj {
	@SuppressWarnings({ "unchecked", "rawtypes", "static-access", "deprecation" })
	public static void main(String[] args) {
		JFrame jf=new JFrame("列表对象获取");
		jf.setSize(500,300);
		jf.setDefaultCloseOperation(jf.EXIT_ON_CLOSE);
		DefaultListModel dfl=new DefaultListModel();
		dfl.addElement("a");
		dfl.addElement("b");
		dfl.addElement(new ImageIcon("res\\testicon.png"));
		dfl.addElement(new File("res\\testicon.png"));
		JList jl=new JList(dfl);
		jl.setCellRenderer(new CRTest());		//设置渲染器为我们自己的
		JScrollPane jsp=new JScrollPane();
		jsp.setBounds(14, 13, 431, 210);
		jsp.setViewportView(jl);
		JPanel jp=new JPanel();
		jf.getContentPane().add(jp);
		jp.setLayout(null);	
		jp.add(jsp);
		jf.show();
		/**
			使用Object的toString()方法,用控制台输出获取到的表格的第1、2、3、4个内容。
		 */
		System.out.println(jl.getModel().getElementAt(0).toString());
		System.out.println(jl.getModel().getElementAt(1).toString());
		System.out.println(jl.getModel().getElementAt(2).toString());
		System.out.println(jl.getModel().getElementAt(3).toString());
	}
}

自定义渲染器类(重写默认渲染器):

import java.awt.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class CRTest extends DefaultListCellRenderer {
	public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {
		setText(value.toString());		//设置文字
		if(value.toString().equals("a")) {		//判断value(列表值)来分情况设置不同图标
			ImageIcon ico=new ImageIcon("res\\testicon.png");		//实例化一个ImageIcon对象
			Image img=ico.getImage();		//实例化Image对象获取ico对象的内容 
			img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把图片全部缩放为25x25
			ico.setImage(img);		//ImageIcon对象重新获取缩放后图标
			setIcon(ico);		//设置图标
		} else {
			ImageIcon ico=new ImageIcon("res\\testicon-2.png");		//实例化一个ImageIcon对象
			Image img=ico.getImage();		//实例化Image对象获取ico对象的内容 
			img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把图片全部缩放为25x25
			ico.setImage(img);		//ImageIcon对象重新获取缩放后图标
			setIcon(ico);
		}
		if(isSelected) {		//当某个元素被选中时
			setForeground(Color.WHITE);		//设置前景色(文字颜色)为白色
			setBackground(Color.BLUE);		//设置背景色为蓝色
			System.out.println(index+"被选中");
		} else {		//某个元素未被选中时(取消选中)
			setForeground(Color.BLACK);		//设置前景色(文字颜色)为黑色
			setBackground(Color.WHITE);		//设置背景色为白色
		}
		return this;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章