目录
5 JList、JCpmboBox实现列表框
5.1 简单列表框
5.2 不强制存储列表项的ListModel和ComboBoxMedel
5.3 强制存储列表项的DefaultListModel和DefaultComboBoxModel
5.4 使用ListCellRenderer改变列表外观
无论从哪个角度来看,JList和JComboBox都是极其相似的,他们都有一个列表框,只是JComboBox的列表框需要以下拉方式显示出来;JList和JComboBox都可以通过调用setRenderer()方法来改变列表项的表现形式。甚至维护这两个组件的Model都是相似的,JList使用ListModel,JComboBox使用ComboBoxModel,而ComboBoxModel是ListModel的子类。
使用JList或JComboBox实现简单列表框的步骤:
1.创建JList和JComboBox实现简单列表框的步骤:
JList(final E[ ] listData);创建JList对象,把listData数组中的每项内容转换成一个列表项显示
JList(final Vector extends E> listData);创建JList对象,把listData数组中的每项内容转换成一个列表项展示
JComboBox(E[ ] items);
JComboBox(Vector
items);
2.设置JList或JComboBox的外观行为
---------------------------------------JList--------------------------------------------------------------
addSelectionInterval(int anchor,int lead);在已经选中列表项的基础上,增加选中从anchor到lead索引范围内的所有列表项
setFixedCellHeight(int hight)/setFixedCellWidth(int width);设置列表项的高度和宽度
setLayoutOrientation(int layoutOrientation);设置列表框的布局方向
setSelectedIndex(int index);默认选中项
setSelectedIndices(int [ ] indices);设置默认选中的多个列表项
setSelectedValue(Object anObject,boolean shouldScroll);设置默认选中项,并滚动到该项显示
setSelectionBackground(Color selectionBackground);设置选中项的背景颜色
setSelectionForeground(Color selectionForeground);设置选中项的前景色
setSelectionInterval(int anchor,int lead);设置从anchor到lead范围内的所有列表项被选中
setSelectionMode(int selectionMode);设置选中模式,默认没有限制,也可以设置为单选或者区域选中
setVisibleRowCount(int visibleRowCount);设置列表框的可视高度足以显示多少行列表项
---------------------------------------JComboBox----------------------------------------------------
setEditable(boolean aFlag);设置是否可以直接修改列表文本框的值,默认为不可以
setMaximumRowCount(int count);设置列表框的可视高度足以显示多少行列表项
setSelectedIndex(int anIndex);设置默认选中项
setSelectedItem(Object anObject);根据列表项的值,设置默认选中项
3.设置监听器,监听列表变化,JList通过addListSelectionListener完成,JComboBox通过addItemListener完成。
案例:
public class ListTest {
JFrame jf = new JFrame("列表框测试");
String[] books = {"java自学宝典","轻量级javaEE企业应用实战","Android基础教程","jQuery实战教程","SpringBoot企业级开发"};
//定义 布局选择按钮 所在的面板
JPanel layoutPanel = new JPanel();
ButtonGroup layoutGroup = new ButtonGroup();
//定义 选择模式按钮 所在面板
JPanel selectModePanel = new JPanel();
ButtonGroup selectModeGroup = new ButtonGroup();
JTextArea favorite = new JTextArea(4,40);
//用一个字符串数组来创建一个JList对象
JList bookList ;
JComboBox bookSelector;
public void init(){
//组装视图
//组装Jlist相关内容
bookList = new JList<>(books);
addBtn2LayoutPanel("纵向滚动",JList.VERTICAL);
addBtn2LayoutPanel("纵向换行",JList.VERTICAL_WRAP);
addBtn2LayoutPanel("横向换行",JList.HORIZONTAL_WRAP);
addBtn2SelectModelPanel("无限制",ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
addBtn2SelectModelPanel("单选",ListSelectionModel.SINGLE_SELECTION);
addBtn2SelectModelPanel("单范围",ListSelectionModel.SINGLE_INTERVAL_SELECTION);
//对JList做设置
bookList.setVisibleRowCount(3);
bookList.setSelectionInterval(2,4);
//处理条目选中事件
bookList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
//获取当前选中的条目
List selectedValuesList = bookList.getSelectedValuesList();
//把当前条目的内容设置到文本域中。
favorite.setText("");
for (String str : selectedValuesList) {
favorite.append(str+"\n");
}
}
});
Box bookListVBox = Box.createVerticalBox();
bookListVBox.add(new JScrollPane(bookList));
bookListVBox.add(layoutPanel);
bookListVBox.add(selectModePanel);
//组装JComboBox
Vector vector = new Vector<>();
// List list = List.of("java自学宝典", "轻量级javaEE企业应用实战", "Android基础教程", "jQuery实战教程", "SpringBoot企业级开发");
// vector.addAll(list);
for (int i = 0; i < books.length; i++) {
vector.add(books[i]);
}
bookSelector = new JComboBox<>(vector);
bookSelector.setEditable(true);
bookSelector.setMaximumRowCount(4);
bookSelector.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
//获取当前已经选中的条目,把内容设置到文本域中
Object selectedItem = bookSelector.getSelectedItem();
favorite.setText(selectedItem.toString());
}
});
//组装顶部的左右两部分
Box topBox = Box.createHorizontalBox();
topBox.add(bookListVBox);
JPanel bookSelectPanel = new JPanel();
bookSelectPanel.add(bookSelector);
topBox.add(bookSelectPanel);
//组装底部
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BorderLayout());
bottomPanel.add(new JLabel("您最喜欢的图书:"),BorderLayout.NORTH);
bottomPanel.add(favorite);
//组装整体
Box holeBox = Box.createVerticalBox();
holeBox.add(topBox);
holeBox.add(bottomPanel);
jf.add(holeBox);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
}
//封装方法,往layoutPanel中添加单选按钮
public void addBtn2LayoutPanel(String name,int layoutType){
//设置标题边框
layoutPanel.setBorder(new TitledBorder(new EtchedBorder(),"确定选项布局"));
//创建单选按钮
JRadioButton button = new JRadioButton(name);
layoutPanel.add(button);
//让第一个按钮默认选中
if (layoutGroup.getButtonCount()==0){
button.setSelected(true);
}
layoutGroup.add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
bookList.setLayoutOrientation(layoutType);
}
});
}
//封装方法,给selectModelPanel添加按钮
public void addBtn2SelectModelPanel(String name,int selectionModel){
//设置标题边框
selectModePanel.setBorder(new TitledBorder(new EtchedBorder(),"确定选择模式"));
//创建单选按钮
JRadioButton button = new JRadioButton(name);
selectModePanel.add(button);
//让第一个按钮默认选中
if (selectModeGroup.getButtonCount()==0){
button.setSelected(true);
}
selectModeGroup.add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
bookList.setSelectionMode(selectionModel);
}
});
}
public static void main(String[] args) {
new ListTest().init();
}
}
与ProgressBar一样,JList和JComboBox也采用了MVC设计模式,JList和JComboBox只负责外观的显示,而组件底层的状态数据则由对应的Model来维护,JList对应的Model是ListModel接口,JComboBox对应的Model是ComboBox接口,其代码如下:
public interface ListModel{ int getSize(); E getElementAt(int index); void addListDataListener(ListDataListener l); void removeListDataListener(ListDataListener l); } public interface ComboBoxModel extends ListModel { void setSelectedItem(Object anItem); Object getSelectedItem(); }
从上面接口来看,这个ListModel不管JList里的所有列表项的存储形式,它甚至不强制存储所有的列表项,只要ListModel的实现类提供了getSize()和getElementAt()两个方法,JList就可以根据该ListModel对象来生成列表项。ComboBoxModel继承了ListModel,它添加了“选择项”的概念,选择项代表JComboBox显示区域内可见的列表项。
在使用JList和JComboBox时,除了可以使用jdk提供的Model实现类,程序员自己也可以根据需求,自己定义Model的实现类,实现对应的方法使用。
案例:
自定义NumberListModel和NumberComboBoxModel实现类,允许使用数据范围来创建JList和JComboBox:
public class NumberListModel extends AbstractListModel {
BigDecimal start;
BigDecimal end;
BigDecimal step;
public NumberListModel(BigDecimal start, BigDecimal end, BigDecimal step) {
this.start = start;
this.end = end;
this.step = step;
}
@Override
public int getSize() {
int floor = (int) Math.floor(end.subtract(start).divide(step,2, RoundingMode.HALF_DOWN).doubleValue());
return floor+1;
}
@Override
public BigDecimal getElementAt(int index) {
BigDecimal ele = new BigDecimal(index).multiply(step).add(start).setScale(2, RoundingMode.HALF_DOWN);
return ele;
}
}
public class NumberComboBoxListModel extends NumberListModel implements ComboBoxModel {
//当前选中条目的索引
private int selectedId;
public NumberComboBoxListModel(BigDecimal start, BigDecimal end, BigDecimal step) {
super(start, end, step);
}
@Override
public void setSelectedItem(Object anItem) {
if (anItem instanceof BigDecimal){
BigDecimal curr = (BigDecimal) anItem;
selectedId = curr.subtract(super.start).divide(super.step,2, RoundingMode.HALF_DOWN).intValue();
}
}
@Override
public Object getSelectedItem() {
BigDecimal item = new BigDecimal(selectedId).multiply(super.step).add(super.start).setScale(1, RoundingMode.HALF_DOWN);
return item;
}
}
public class ListModelTest {
JFrame jf = new JFrame("测试ListModel");
JList jList = new JList<>(new NumberListModel(new BigDecimal(1),new BigDecimal(21),new BigDecimal(2)));
JComboBox jComboBox = new JComboBox<>(new NumberComboBoxListModel(new BigDecimal(0.1),new BigDecimal(1.2),new BigDecimal(0.1)));
JLabel label = new JLabel("您选择的值是:");
JTextField jTextField = new JTextField(15);
public void init(){
//组装视图
//组装顶部
jList.setVisibleRowCount(4);
jList.setSelectionInterval(2,4);
jList.setFixedCellWidth(90);
jList.setFixedCellHeight(30);
jList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
List selectedValuesList = jList.getSelectedValuesList();
jTextField.setText("");
for (BigDecimal item : selectedValuesList) {
jTextField.setText(jTextField.getText()+item.toString()+",");
}
}
});
jComboBox.setMaximumRowCount(4);
jComboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
Object selectedItem = jComboBox.getSelectedItem();
jTextField.setText(selectedItem.toString());
}
});
Box hBox = Box.createHorizontalBox();
hBox.add(new JScrollPane(jList));
JPanel tempPanel = new JPanel();
tempPanel.add(jComboBox);
hBox.add(tempPanel);
jf.add(hBox);
//组装底部
JPanel bottomPanel = new JPanel();
bottomPanel.add(label);
bottomPanel.add(jTextField);
jf.add(bottomPanel,BorderLayout.SOUTH);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
}
public static void main(String[] args) {
new ListModelTest().init();
}
}
前面只是介绍了如何创建JList、JComboBox对象,当调用JList和JComboBox构造方法时传入数组或Vector作为参数,这些数组元素或集合元素将会作为列表项。当使用JList或JComboBox时常常还需要动态地增加、删除列表项,例如JCombox提供了下列方法完成增删操作:
addItem( E item);添加一个列表项
insertItemAt(E item,int index);向指定索引处插入一个列表项
removeAllItems();删除所有列表项
removeItem(Object anObject);删除指定列表项
removeItemAt(int anIndex);删除指定索引处的列表项
JList并没有提供这些类似的方法,如果需要创建一个可以添加、删除列表项的JList对象,则应该在创建JList的显式使用DefaultListModel作为构造参数。因为DefaultListModel作为JList的Model,它负责维护JList组件的所有列表数据,所以可以通过向DefaultListModel中添加、删除元素来实现向JList对象中增加、删除列表项。
DefaultListModel提供了如下方法来添加、删除元素:
add(int index,E element);在该ListModel的指定位置插入指定元素
addElement(E obj);将指定元素添加到该ListModel的末尾
insertElementAt(E obj,int index);在该ListModel的指定位置处插入指定元素
Object remove(int index);删除该ListModel中指定位置处的元素
removeAllElements();删除该ListModel中所有元素
removeElement(E obj);删除该ListModel中第一个与参数匹配的元素
removeElementAt(int index);删除该ListModel中指定索引处的元素
removeRange(int fromIndex,int toIndex);删除该ListModel中指定范围内的所有元素
set(int index,E element);将该ListModel指定索引处的元素替换成指定元素
setElement(E obj,int index);将该ListModel指定索引处的元素替换成指定元素
案例:
使用DefaultListModel实现下图效果:
public class DefaultListModelTest {
JFrame jf = new JFrame("测试DefaultListModel");
JTextField bookName = new JTextField(20);
JButton removeBtn = new JButton("删除选中图书");
JButton addBtn = new JButton("添加指定图书");
//创建JList
JList bookList;
DefaultListModel model = new DefaultListModel<>();
public void init(){
//组装视图
model.addElement("java自学宝典");
model.addElement("轻量级JavaEE企业应用实战");
model.addElement("Android基础教程");
model.addElement("JQuery实战教程");
bookList = new JList<>(model);
//设置Jlist
bookList.setVisibleRowCount(4);
//设置单选
bookList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jf.add(new JScrollPane(bookList));
//组装底部
addBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String name = bookName.getText();
if (!name.trim().equals("")){//不是空字符串才添加
model.addElement(name);
}
}
});
removeBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedIndex = bookList.getSelectedIndex();
if (selectedIndex>=0){
model.remove(selectedIndex);
}
}
});
JPanel bottomPanel = new JPanel();
bottomPanel.add(bookName);
bottomPanel.add(addBtn);
bottomPanel.add(removeBtn);
jf.add(bottomPanel,BorderLayout.SOUTH);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
}
public static void main(String[] args) {
new DefaultListModelTest().init();
}
}
前面程序中的JList和JComboBox采用的都是简单的字符串列表项,实际上,JList和JComboBox还可以支持图标列表项,如果在创建JList或JComboBox时传入图标数组,则创建的JList和JComboBox的列表项就是图标。
如果希望列表项是更复杂的组件,例如,希望像QQ一样每个列表项既有图标,又有字符串,此时需要使用ListCellRenderer接口的实现类对象,自定义每个条目组件的渲染过程:
public interface ListCellRenderer{ Component getListCellRendererComponent( JList extends E> list,//列表组件 E value,//当前列表项的内容 int index,//当前列表项的索引 boolean isSelected,//当前列表项是否被选中 boolean cellHasFocus);//当前列表项是否获取了焦点 }
通过JList的setCellRenderer(ListCellRenderer super E> cellRenderer)方法 ,把自定义的ListCellRenderer对象传递给JList,就可以按照自定义的规则绘制列表项组件了。
案例:
使用ListCellRenderer实现下图效果:
public class ListCellRendererTest {
private JFrame mainWin = new JFrame("好友列表");
private String[] friends = {
"李清照",
"苏格拉底",
"李白",
"弄玉",
"虎头"
};
//定义一个JList对象
JList friendsList = new JList(friends);
public void init() {
//组装视图
//给JList设置ListCellRenderer对象,指定列表项绘制的组件
friendsList.setCellRenderer(new MyRenderer());
mainWin.add(friendsList);
mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWin.pack();
mainWin.setVisible(true);
}
private class MyRenderer extends JPanel implements ListCellRenderer{
private String name;
private ImageIcon icon;
//记录背景色
private Color backGround;
//记录前景色:文字的颜色
private Color forceGround;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
//重置成员变量的值
this.name = value.toString();
this.icon = new ImageIcon("E:\\GUISwing\\img\\tree\\"+name+".gif");
this.backGround = isSelected? list.getSelectionBackground() : list.getBackground();
this.forceGround = isSelected? list.getSelectionForeground() : list.getForeground();
return this;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(60,80);
}
//绘制列表项的内容
@Override
public void paint(Graphics g) {
int imageWidth = icon.getImage().getWidth(null);
int imageHeight = icon.getImage().getHeight(null);
//填充背景矩形
g.setColor(backGround);
g.fillRect(0,0,getWidth(),getHeight());
//绘制头像
g.drawImage(icon.getImage(),this.getWidth()/2 -imageWidth/2 ,10,null);
//绘制昵称
g.setColor(forceGround);
g.setFont(new Font("StSong",Font.BOLD,18));
g.drawString(this.name,this.getWidth()/2 - this.name.length()*20/2,imageHeight+30);
}
}
public static void main(String[] args) {
new ListCellRendererTest().init();
}
}