这几天研究了一下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;
}
}