高级Swing——列表
1. 列表
1.1 JList构件
JList可以将多个选项放置在单个框中。为了构建列表框,首先需要创建一个字符串数组,然后将这个数组传递给JList构造器。
String[] words= { "quick", "brown", "hungry", "wild", . . . };
JList<String> wordList = new JList<>(words);
列表框不能自动滚动,要想为列表框加上滚动条,必须将它插入到一个滚动面板中:
JScrollPane scrollPane = new JScrollPane(wordList);
然后应该应该把滚动面板而不是列表框,插入到外围面板上。
默认情况下,列表框构件可以显示8个选项;可以使用setVisibleRowCount方法改变这个值:
wordList.setVisibleRowCount(4); // display 4 items
还可以使用以下三个值中的任意一个来设置列表框摆放的方向:
• JList.VERTICAL ( 默认值) :垂直摆放所有选项。
• JList.VERTICAL_WRAP: 如果选项数超过了可视行数,就开始新的一列。
• JList.HORIZONTAL_WRAP: 如果选项数超过了可视行数,就开始新的一行,并且按照水平方向进行填充。
在默认的情况下,用户可以选择多个选项。为了选择多个选项,只需要按住CTRL键,然后在要选择的选项上单击。要选择处于连续范围内的选项,首先选择第一个选项,然后按住SHIFT键,并在最后一个选项上点击即可。
使用setSelectionMode方法,还可以对用户的选择模式加以限制:
wordList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// select one item at a time
wordList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
// select one item or one range of items
列表框使用一种不同的事件通知机制,它不需要监听动作事件,而是监听列表选择事件。可以向列表构件添加一个列表选择监听器,然后在监听器中实现下面这个方法:
public void valueChanged(ListSelectionEvent evt)
在用户选择了若干个选项的同时,将产生一系列列表选择事件。假如用户在一个新选项上单击,当鼠标按下的时候,就会有一个事件来报告选项的改变。这是一种过渡型事件,在调用event.getValueIsAdjusting()时,如果该选择仍未最终结束则返回true。然后,当松开鼠标时,就产生另一事件,此时event.getValueIsAdjusting()返回false。如果你对这种过渡型事件不感兴趣,那么可以等待event.getValueIsAdjusting()调用返回false的事件。不过,如果希望只是要点击鼠标就给用户一个即时反馈,那么就需要处理所有的事件。
一旦被告知某个事件已经发生,那么就需要弄清楚当前选择了哪些选项。如果是单选模式,调用getSelectedValue可以获取所有选中列表的元素的值;否则调用getSelectedValues返回一个包含所有选中选项的对象数组。之后,可以以常规方式处理它。
for (String value : wordList.getSelectedValuesList())
// do something with value
注意:列表构件不响应鼠标的双击事件。正如Swing设计者所构想的那样,使用列表选择一个选项,然后点击某个按钮执行某个动作。但是,某些用户界面允许用户在一个列表选项上双击鼠标,作为选择一个选项并调用一个默认动作的快捷方式。如果想实现这中行为,那么必须对这个列表框添加一个鼠标监听器,然后按照下面这样捕获鼠标事件:
public void mouseClicked(MouseEvent evt)
{
if (evt.getClickCount() == 2)
{
JList source = (JList) evt.getSource();
Object[] selection = source.getSelectedValues();
doAction(selection);
}
}
下面的程序展示了一个填入字符串的列表框。请注意valueChanged方法是怎样根据被选项来创建消息字符的。
package list; import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; public class ListFrame extends JFrame {
private static final int DEFAULT_WIDTH=400;
private static final int DEFAULT_HEIGHT=300;
private JPanel listPanel;
private JList<String> wordlist;
private JLabel label;
private JPanel buttonPanel;
private ButtonGroup group;
private String prefix="The ";
private String suffix="fox jump over the lazy dog."; public ListFrame(){
this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
String[] words = {"quick","brown","hungry","wild","silent","huge","private","abstract","static","final"};
wordlist = new JList<>(words);
wordlist.setVisibleRowCount(4);
JScrollPane scrollPane = new JScrollPane(wordlist); listPanel = new JPanel();
listPanel.add(scrollPane);
wordlist.addListSelectionListener(new ListSelectionListener(){ @Override
public void valueChanged(ListSelectionEvent e) {
StringBuilder text = new StringBuilder(prefix);
for(String value : wordlist.getSelectedValuesList()){
text.append(value);
text.append(" ");
}
text.append(suffix);
label.setText(text.toString());
} }); buttonPanel = new JPanel();
group = new ButtonGroup();
makeButton("Vertical", JList.VERTICAL);
makeButton("Vertical Wrap",JList.VERTICAL_WRAP);
makeButton("Horizontal Wrap",JList.HORIZONTAL_WRAP); this.add(listPanel, BorderLayout.NORTH);
label = new JLabel(prefix+suffix);
this.add(label, BorderLayout.CENTER);
this.add(buttonPanel, BorderLayout.SOUTH);
this.setTitle("ListTest");
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} /**
* 设置按钮
* @param string 按钮名字
* @param vertical 按钮类型
*/
private void makeButton(String string, final int vertical) {
JRadioButton button = new JRadioButton(string);
buttonPanel.add(button);
if(group.getButtonCount()==0) button.setSelected(true);
group.add(button);
button.addActionListener(new ActionListener(){ @Override
public void actionPerformed(ActionEvent e) {
wordlist.setLayoutOrientation(vertical);
listPanel.revalidate(); //重新布局并绘制
} }); }
public static void main(String[] args) {
new ListFrame(); } }
1.2 列表模式
通过前一节,我们已经对列表构件的一些常用方法有了一定的了解:
1)指定一组在列表中显示的固定字符串
2)将列表放置到一个滚动面板中
3)捕获列表选择事件
列表构件使用了模型-视图-控制器这种设计模式,将可视化外观(以某种方式呈现的一列选项)和底层数据(一个对象集合)进行了分离。JList类负责数据的可视化外观。实际上,它对这些数据是怎样存储的知之甚少,它只知道可以通过某个实现了ListModel接口的对象来获取这些数据:
public interface ListModel<E>
{
int getSize();
E getElementAt(int i);
void addListDataListener(ListDataListener l);
void removeListDataListener(ListDataListener l);
}
通过这个接口,JList就可以获得元素的个数,并且能够获取每一个元素。另外,JList对象可以将其自身添加为一个ListDataListener。在这种方式下,一旦元素集合发生了变化,就会通知JList,从而使它能够重新绘制列表。
为什么这种通用性非常有用呢?为什么JList对象不直接存储一个对象数组呢?
请注意,这个接口并未指定这些对象是怎样存储的。尤其是,它根本就没有强制要求这些对象一定要被存储!无论何时调用getElementAt方法,它都会对每个值进行重新计算。如果想显示一个极大的集合,而且又不想存储这些值,那么这个方法可能会有所帮助。
下面我们举一个例子:允许用户在列表框中所有三个字母的单词当中进行选择。
三个字母的组合一共有26x26x26=17576个。我们不希望将所有这些组合都存储起来,而是想用户滚动这些单词的时候,依照请求对它们重新计算。
事实证明,这实现起来很容易。其中比较麻烦的部分,即添加和删除监听器,在我们所继承的AbstractListModel类中已经为我们实现了。我们只需要提供getSize和getElementAt方法即可:
class WordListModel extends AbstractListModel<String>
{
public WordListModel(int n) { length = n; }
public int getSize() { return (int) Math.pow(26, length); }
public String getElementAt(int n)
{
// compute nth string
. . .
}
. . .
}
既然我们已经有了一个模型,那么就可以构建一个列表,让用户可以通过滚动来选择该模型所提供的任意元素:
JList<String> wordList = new JList<>(new WordListModel(3));
wordList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane scrollPane = new JScrollPane(wordList);
这里的关键是这些字符串从来都没有被存储过,而只有那些用户实际要求查看的字符串才会被生成。
我们还必须进行另外一项设置。那就是,我们必须告诉列表构件,所有的选项都有一个固定的宽度和高度。最简单的方法就是通过设置单元格的尺寸大小(cell dimension)来设定原型单元格的值(prototype cell value):
wordList.setPrototypeCellValue("www");
原型单元格的值通常用来确定所有单元格的尺寸(我们使用字符串“www"是因为"w"在大多数字体中都是最宽的小写字母)。另外,可以像下面这样设置一个固定不变的单元格尺寸。
wordList.setFixedCellWidth(50);
wordList.setFixedCellHeight(15);
如果你既没有设置原型值也没有设置固定的单元格尺寸,那么列表构建就必须计算每个选项的宽度和高度。这可能需要花费更长的时间。
完整的程序代码如下:
WordListModel.java
package longList; import javax.swing.AbstractListModel;
//计算生成列表元素
public class WordListModel extends AbstractListModel<String>{ private static final long serialVersionUID = 1L;
private int length;
public static final char FIRST = 'a';
public static final char LAST = 'z'; public WordListModel(int n){
length = n;
}
@Override
public int getSize() {
// TODO Auto-generated method stub
return (int) Math.pow(LAST-FIRST+1, length);
} @Override
public String getElementAt(int n) {
// TODO Auto-generated method stub
StringBuilder r = new StringBuilder();
for(int i=0;i<length;i++){
char c = (char)(FIRST + n%(LAST-FIRST+1));
r.insert(0,c);
n=n/(LAST-FIRST+1);
}
return r.toString();
} }
LongListFrame.java
package longList; import java.awt.BorderLayout;
import java.awt.Container; import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
//允许用户在列表框中所有三个字母的单词当中进行选择
public class LongListFrame extends JFrame{ private static final long serialVersionUID = 1L;
private JList<String> wordList;
private JLabel label;
private String prefix = "The quick brown ";
private String suffix = " jumps over the lazy dog."; public LongListFrame(){
wordList = new JList<String>(new WordListModel(3));
wordList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
wordList.setPrototypeCellValue("www");
JScrollPane scrollPane = new JScrollPane(wordList); JPanel p = new JPanel();
p.add(scrollPane);
wordList.addListSelectionListener(new ListSelectionListener(){ @Override
public void valueChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
setSubject(wordList.getSelectedValue());
} });
Container contentPane = getContentPane();
contentPane.add(p, BorderLayout.NORTH);
label = new JLabel(prefix+suffix);
contentPane.add(label, BorderLayout.CENTER);
setSubject("fox");
this.setTitle("LongListTest");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.pack(); //按组件的首选大小布局
}
//在label中添加选中的信息
public void setSubject(String word) {
StringBuilder text = new StringBuilder(prefix);
text.append(word);
text.append(suffix);
label.setText(text.toString());
} public static void main(String[] args) {
new LongListFrame();
} }
1.3 插入和移除值
不能直接编辑列表值的集合。相反地,必须先访问模型,然后再添加或移除元素。
我们需要先构建一个 DefaultListModel对象,填入初始值,然后将他与一个列表关联起来。 DefaultListModel类实现了ListModel接口,并管理着一个对象集合。
DefaultListModel<String> model = new DefaultListModel<>();
model.addElement("quick");
model.addElement("brown");
. . .
JList<String> list = new JList<>(model);
现在,就可以从model对象中添加或移除元素值了。然后,model对象会告知列表发生了哪些变化,接着,列表会对自身进行重新绘制。
model.removeElement("quick");
model.addElement("slow");
由于历史遗留问题,DefaultListModel类使用的方法名和集合类的方法名并不相同。默认的列表模型在内部是使用一个向量来存储元素值的。
1.4 值的绘制
具有绘画单元格的类表框如下程序如下:
FontCellRenderer.java
package listRendering; import java.awt.*;
import javax.swing.*; /**
* A cell renderer for Font objects that renders the font name in its own font.
*/
public class FontCellRenderer extends JComponent implements ListCellRenderer<Font>
{
private Font font;
private Color background;
private Color foreground; public Component getListCellRendererComponent(JList<? extends Font> list,
Font value, int index, boolean isSelected, boolean cellHasFocus)
{
font = value;
background = isSelected ? list.getSelectionBackground() : list.getBackground();
foreground = isSelected ? list.getSelectionForeground() : list.getForeground();
return this;
} public void paintComponent(Graphics g)
{
String text = font.getFamily();
FontMetrics fm = g.getFontMetrics(font);
g.setColor(background);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(foreground);
g.setFont(font);
g.drawString(text, 0, fm.getAscent());
} public Dimension getPreferredSize()
{
String text = font.getFamily();
Graphics g = getGraphics();
FontMetrics fm = g.getFontMetrics(font);
return new Dimension(fm.stringWidth(text), fm.getHeight());
}
}
ListRenderingFrame.java
package listRendering; import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*; /**
* This frame contains a list with a set of fonts and a text area that is set to the selected font.
*/
public class ListRenderingFrame extends JFrame
{
private static final int TEXT_ROWS = 8;
private static final int TEXT_COLUMNS = 20; private JTextArea text;
private JList<Font> fontList; public ListRenderingFrame()
{
java.util.List<Font> fonts = new ArrayList<>();
final int SIZE = 24;
fonts.add(new Font("Serif", Font.PLAIN, SIZE));
fonts.add(new Font("SansSerif", Font.PLAIN, SIZE));
fonts.add(new Font("Monospaced", Font.PLAIN, SIZE));
fonts.add(new Font("Dialog", Font.PLAIN, SIZE));
fonts.add(new Font("DialogInput", Font.PLAIN, SIZE));
fontList = new JList<Font>(fonts.toArray(new Font[]{}));
fontList.setVisibleRowCount(4);
fontList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
fontList.setCellRenderer(new FontCellRenderer());
JScrollPane scrollPane = new JScrollPane(fontList); JPanel p = new JPanel();
p.add(scrollPane);
fontList.addListSelectionListener(new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent evt)
{
Font font = fontList.getSelectedValue();
text.setFont(font);
} }); Container contentPane = getContentPane();
contentPane.add(p, BorderLayout.SOUTH);
text = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
text.setText("The quick brown fox jumps over the lazy dog");
text.setFont(fonts.get(0));
text.setLineWrap(true);
text.setWrapStyleWord(true);
contentPane.add(text, BorderLayout.CENTER);
pack();
}
}
ListRenderingTest.java
package listRendering; import java.awt.*;
import javax.swing.*; /**
* This program demonstrates the use of cell renderers in a list box.
* @version 1.24 2012-01-26
* @author Cay Horstmann
*/
public class ListRenderingTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new ListRenderingFrame();
frame.setTitle("ListRenderingTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
javax.swing.JList < E > 1.2
• Color getBackground()
返回未选定单元格的背景颜色。
• Color getSelectionBackground()
返回选定单元格的背景颜色。
• Color getForeground()
返回未选定单元格的前景颜色。
• Color getSelectionForeground()
返回选定单元格的前景颜色。
• void setCellRenderer(ListCellRenderer<? super E> cellRenderer)
设置用于绘制列表中单元格的绘制器。
javax.swing.ListCellRenderer<E> 1.2
• Component getListCellRendererComponent(JList<? extends E> list, E item, int index, boolean isSelected, boolean hasFocus)
返回一个其paint方法用于绘制单元格内容的构件,如果列表的单元格尺寸没有固定,那么该构件还必须实现getPreferredSize。
参数: list 单元格正在被绘制的列表
item 要绘制的选项
index 存储在模型中的选项索引
inSelected true表示指定的单元格被选定
hasFocus true表示焦点在指定的单元格上
高级Swing——列表的更多相关文章
- Delphi 基本数据类型列表 高级数据类型列表 字符类型查询列表清单
原文:Delphi 基本数据类型列表 高级数据类型列表 字符类型查询列表清单 长长的列表文字类型文件 分类 范围 字节 备注 简单类型 序数 整数 Integer -2147483648 .. 214 ...
- Swing列表框组件
public class JListTest extends JFrame{ private static final long serialVersionUID=1L; publ ...
- 高级特性(6)- 高级Swing
6.1 列表 6.1.1 JList构件 6.1.2 列表模式 6.1.3 插入和移除值 6.1.4 值的绘制6.2 表格 6.2.1 简单表格 6.2.2 表格模型 6.2.3 对行和列的操作 6. ...
- Dynamics CRM 将实体从高级查找列表中移除不可见
有时我们不需要将某个实体显示给一般用户比如配置实体,但是这种类型的实体有时候又需要给一般用户读权限ODATA的时候得能读,站点地图上的隐藏比较容易用工具配置下权限即可.其实做到这步一般就可以了但有的客 ...
- 高级数据类型--列表[list]
List(列表) 是 Python 中使用 最频繁 的数据类型,在其他语言中通常叫做 数组,专门用于存储 一串 信息,列表用 [] 定义,数据 之间使用 , 分隔,列表的 索引 从 0 开始. nam ...
- Python高级教程-列表生成式
List Comprehensions(列表生成式) 列表生成式,是Python内置的非常简单却强大的可以用来创建list的生成式. 例如,要生成list:[1,2,3,4,5,6,7,8,9,10] ...
- Python高级特性——列表生成式(list Comprehensions)
List Comprehensions 即列表生成式,是Python内置的强大的用来生成列表list的生成式. 简单菜: >>> l = list(range(2,13)) > ...
- eNSP配置基本与高级访问控制列表
首先我们进行基本的acl控制 拓扑图如下所示 首先我们对路由器进行基本ip配置 并在路由器上设置ospf协议 添加相邻的网段 在路由器上运行了ospf协议后 使用display ip route-ta ...
- Python实用笔记 (9)高级特性——列表生成式
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, ...
随机推荐
- How To Set Up Port Forwarding in Linux
Port forwarding usually used when we want our computer act like a router. Our computer receive the p ...
- Linux_系统信息
公司里一些仿真软件得进Linux系统,好奇公司用的什么Linux版本,于是搜罗了几个命令如下: 1 uname - Print system info -a, print all info -s, ...
- Hadoop系列(二)hadoop2.2.0伪分布式安装
一.环境配置 安装虚拟机vmware,并在该虚拟机机中安装CentOS 6.4: 修改hostname(修改配置文件/etc/sysconfig/network中的HOSTNAME=hadoop),修 ...
- Linux环境变量(小马哥推荐)
/etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置. /etc/bashrc:为每一 ...
- dom 封装表单控件
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- HDu 1001 Sum Problem 分类: ACM 2015-06-19 23:38 12人阅读 评论(0) 收藏
Sum Problem Time Limit: 1000/500 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...
- psutil documentation
Quick links Home page Blog Download Forum What’s new About From project’s home page: psutil (python ...
- HDU 2196 Computer (树dp)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=2196 给你n个点,n-1条边,然后给你每条边的权值.输出每个点能对应其他点的最远距离是多少 ...
- CodeForces 711B Chris and Magic Square (暴力,水题)
题意:给定n*n个矩阵,其中只有一个格子是0,让你填上一个数,使得所有的行列的对角线的和都相等. 析:首先n为1,就随便填,然后就是除了0这一行或者这一列,那么一定有其他的行列是完整的,所以,先把其他 ...
- 关于WebPlayer Sandbox的小节
不可以像其他build target一样读写I/O 不可以call一些private或者internal methord 只要在一个top level的domain下可以不需要xml dmain po ...