Swing-JList用法-入门
注:本文所有素材均来源于How to Use Lists,本文为该文章的学习笔记。
JList是Swing中的列表控件,形状如下所示:
实际上,JList有3种不同的样式:
分别为HORIZONTAL_WRAP、VERTICAL_WRAP、VERTICAL,通过setLayoutOrientation
进行设置。
构造model
JList每行只有一列,每一列称为一个element。根据MVC架构,其内部的model维护着一个数组,存放了所有的成员元素。因此,对于JList内部元素的处理,都应调用其model的相关方法。
JList共有3种model:
DefaultListModel:对内部成员的操作均已实现,你只需要使用相应的方法即可。
AbstractListModel:手动管理数据并调用相关操作,必须继承AbstractListModel并自己实现其中的
getSize和
getElementAt方法。
ListModel:手动管理所有事情。
一般来说,我们使用第一种即可。
初始化JList
建议使用DefaultListModel对象作为参数来初始化JList。如果你使用一个数组或vector来初始化JList,或者调用JList.setListData方法来填充它,JList会隐式地生成一个不可修改的默认model,这意味着你无法再对JList进行增删改等操作。
选择元素
JList中的元素选择有三种模式,可通过setSelectionMode来设置:
添加删除元素
调用model的add/remove/insert等方法来实现元素的添加和删除。这里没什么要特别注意的。
定制单元格渲染器
JList使用“单元格渲染器”来显示所有的元素。默认的渲染器只会显示string和图标,对于其它对象,一律调用其toString方法来处理。如果你有特殊的需求,可以使用以下步骤来定制渲染器:
(1)写一个实现了 ListCellRenderer接口的类;
(2)调用setCellRenderer
方法,将你的定制渲染器作为参数使用;
Oracle并没有给出Jlist使用定制渲染器的例子,只有一个是关于Combo Box的,其实是一样的啦。Providing a Custom Renderer
选择事件
在《Swing-JList选择事件监听器ListSelectionListener-入门》中专门介绍
数据事件
如果想要对JList中数据的变更进行监听,那么你需要使用addListDataListener添加一个监听器,该监听器必须实现ListDataListener接口。How to Write a List Data Listener进行了详细的介绍并提供了demo。
Demo
下面这个demo包含了JList的常用方法,修改自官网源程序ListDemo.java
/* * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle or the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package GUI.components; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; /* ListDemo.java requires no other files. */ public class ListDemo extends JPanel implements ListSelectionListener { private JList list; private DefaultListModel listModel; private static final String hireString = "Hire"; private static final String fireString = "Fire"; private JButton fireButton; private JTextField employeeName; public ListDemo() { super(new BorderLayout()); listModel = new DefaultListModel(); listModel.addElement("Jane Doe"); listModel.addElement("John Smith"); listModel.addElement("Kathy Green"); //Create the list and put it in a scroll pane. list = new JList(listModel); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setSelectedIndex(0); list.addListSelectionListener(this); list.setVisibleRowCount(5); JScrollPane listScrollPane = new JScrollPane(list); JButton hireButton = new JButton(hireString); HireListener hireListener = new HireListener(hireButton); hireButton.setActionCommand(hireString); hireButton.addActionListener(hireListener); hireButton.setEnabled(false); fireButton = new JButton(fireString); fireButton.setActionCommand(fireString); fireButton.addActionListener(new FireListener()); employeeName = new JTextField(10); employeeName.addActionListener(hireListener); employeeName.getDocument().addDocumentListener(hireListener); String name = listModel.getElementAt( list.getSelectedIndex()).toString(); //Create a panel that uses BoxLayout. JPanel buttonPane = new JPanel(); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); buttonPane.add(fireButton); buttonPane.add(Box.createHorizontalStrut(5)); buttonPane.add(new JSeparator(SwingConstants.VERTICAL)); buttonPane.add(Box.createHorizontalStrut(5)); buttonPane.add(employeeName); buttonPane.add(hireButton); buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); add(listScrollPane, BorderLayout.CENTER); add(buttonPane, BorderLayout.SOUTH); } class FireListener implements ActionListener { public void actionPerformed(ActionEvent e) { //This method can be called only if //there's a valid selection //so go ahead and remove whatever's selected. int index = list.getSelectedIndex(); listModel.remove(index); int size = listModel.getSize(); if (size == 0) { //Nobody's left, disable firing. fireButton.setEnabled(false); } else { //Select an index. if (index == listModel.getSize()) { //removed item in last position index--; } list.setSelectedIndex(index); list.ensureIndexIsVisible(index); } } } //This listener is shared by the text field and the hire button. class HireListener implements ActionListener, DocumentListener { private boolean alreadyEnabled = false; private JButton button; public HireListener(JButton button) { this.button = button; } //Required by ActionListener. public void actionPerformed(ActionEvent e) { String name = employeeName.getText(); //User didn't type in a unique name... if (name.equals("") || alreadyInList(name)) { Toolkit.getDefaultToolkit().beep(); employeeName.requestFocusInWindow(); employeeName.selectAll(); return; } int index = list.getSelectedIndex(); //get selected index if (index == -1) { //no selection, so insert at beginning index = 0; } else { //add after the selected item index++; } listModel.insertElementAt(employeeName.getText(), index); //If we just wanted to add to the end, we'd do this: //listModel.addElement(employeeName.getText()); //Reset the text field. employeeName.requestFocusInWindow(); employeeName.setText(""); //Select the new item and make it visible. list.setSelectedIndex(index); list.ensureIndexIsVisible(index); } //This method tests for string equality. You could certainly //get more sophisticated about the algorithm. For example, //you might want to ignore white space and capitalization. protected boolean alreadyInList(String name) { return listModel.contains(name); } //Required by DocumentListener. public void insertUpdate(DocumentEvent e) { enableButton(); } //Required by DocumentListener. public void removeUpdate(DocumentEvent e) { handleEmptyTextField(e); } //Required by DocumentListener. public void changedUpdate(DocumentEvent e) { if (!handleEmptyTextField(e)) { enableButton(); } } private void enableButton() { if (!alreadyEnabled) { button.setEnabled(true); } } private boolean handleEmptyTextField(DocumentEvent e) { if (e.getDocument().getLength() <= 0) { button.setEnabled(false); alreadyEnabled = false; return true; } return false; } } //This method is required by ListSelectionListener. public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting() == false) { if (list.getSelectedIndex() == -1) { //No selection, disable fire button. fireButton.setEnabled(false); } else { //Selection, enable the fire button. fireButton.setEnabled(true); } } } /** * Create the GUI and show it. For thread safety, * this method should be invoked from the * event-dispatching thread. */ private static void createAndShowGUI() { //Create and set up the window. JFrame frame = new JFrame("ListDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane. JComponent newContentPane = new ListDemo(); newContentPane.setOpaque(false); //content panes must be opaque frame.setContentPane(newContentPane); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }