++ Swing读书笔记
1-1:Swing常用的package
PACHAGE | 内 容
-----------------|-------------------------------
javax.swing | 最常用的pachage,包含了各种swing组件的类
javax.swing.border | 包含与swing组件外框有关的类
javax..swing.colorchooser | 针对swing调色盘组件(JColorChooser)所设计的类
javax.swing.event | 处理由swing组件产生的事件,有别于AWT事件
javax.swing.filechooser | 包含针对swing文件选择对话框(JFileChooser)所设计的类
----------------------------------------------
javax.swing.plaf | 处理swing组件外观的相关类
javax.swing.plaf.basic |
javax.swing.plaf.metal |
javax.swing.plaf.multi |
----------------------------------------------
javax.swing.table | 针对swing表格组件(JTable)所设计的类
----------------------------------------------
javax.swing.text | 包含与swing文字组件相关的类
javax.swing.text.html |
javax.swing.text.html.parser |
javax.swing.text.rtf |
----------------------------------------------
javax.swing.tree | 针对swing树关元件(JTree)所设计的类
javax.swing.undo | 提供swing文字组件Redo或Undo的功能
1-2:swing的版面结构
Swing中几乎所有组件都是从JComponent衍生而来,也就是说这些组件都是lightweight Component,均由纯java code所编写面成
、Swing中以下几个组件不是由JComponent继承面来:
JFrame(JRoot Pane)
JDialog(JRoot Pane)
JWindow(JRoot Pane)
JApplet(JRoot Pane)
以上四个组件是heavyweight Component,必须使用到native code来画出这四个窗口组件,因为要在操作系统中显示窗口画面,必
须使用操作系统的窗口资源,而以往的AWT组件大多使用native code所构造出来,因此Swing中的JFrame便继承原有AWT中的Frame
类,面不是继承JComponent类。同样,JApplet是继承原有AWT中的JApplet类,也不是继承JComponent类。
JFrame、JDialog、JWindow及JApplet这四个组件统称为最上层组件,因为其余的swing组件都必须依附在此四组件之一上才能
显示出来。此四组件均实现(Implement)RootPaneContainer这个界面(Interface),此界面定义了各种容器取得与设置并不是真实的容器,它是由Glass Pane
与Layered Pane所组成(Layered Pane里拥有Content Pane与Menu Bar,而Menu Bar可选择使用或不使用),
我们不能在JRootPane上加入任何的组件,因为它只是一个虚拟的容器,若要在最上层组件上加入组件,必须加在Layered Pane或是
Layered Pane里的Content Pane上。以JFrame为例,一般我们要在JFrame上加入其他组件(如JButton、JLabel等)必须先取得JFrame
的Content Pane,然后将要加入的组件放在此Content Pane中,而不是直接就加到JFrame上。因此若要在JFrame中加入一个按钮,不
能像以前AWT时一样写成frame.add(button)的形式,而必须先取得JFrame的Content Pane,然后将按钮加入Content Pane中,如:
frame.getContentPane().add(button)
否则在编译的时候将有错误信息产生。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
注意:
1.组件必须加在容器中,而容器本身具有层次性的关系,就如同珠宝盒一般,大盒子里面可以放小盒子,小盒子里面还可以放更小的盒子,而珠宝就可以放
在某一个盒子中,这里的珠宝就代表组件,盒子就代表容器。因此若您想在JFrame加入任何组件时,必须
先取得JFrame的容器来放置这些组件,而由于JFrame、JDialog、JWindow与JApplet是显示Swing组件的源头,我们可以称它们为根
组件,也就是所谓的最上层组件。
2.RootPaneContainer它是一个interface,共有5个类实现(Implement)它,分别是JFrame、JAppleet、JWindow、JDialog、
JInternalFrame,其中JInternalFrame是一个lightweight Component,它不是一个最上层组件,也就是说JInternalFrame不能单独显示出来,必须依附在最上
层组件中,我们将在下面讨论组件,而JFrame,JApplet,JWindow,JDialog均为最上层组件。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
RootPaneContainer定义了下面几种方法:
方法
Container getContentPane()返回contentPane
Component getGlassPane()返回glassPane
JLayeredPane getLayeredPane()返回layeredPane
JRootPane getRootPane返回属于这个组件的JRootPane
Void setContentPane(Container contentpane)设置ContentPane
Void setGlassPane(Component glassPane)设置GlassPane
Void setLayeredPane(JLayeredPane layeredPane)设置LayeredPane
JFrame如何取得Content Pane的实际流程,下面是一段很简单的程序代码:
public class Simple{
Simple(){
JFrame frame=new JFrame();
Container contentPane=frame.getContentPane();
JButton button=new JButton();
contentPane.add(button);
}
}
当我们写frame.getContentPane()时,会返回此frame的Content Pane,也就是一个容器组件,有了容器之后我们才能将button组件
摆进去,此时JFrame才算拥有button组件。所以JFrame就好像是一块空地,要在这空地上信人应该先盖一栋房子(容器),然后人
、家具、设备等等(组件)就能搬进此房子中。下面的层次结构说明了最上层组件都含有JRootPane组件,JRootPane本身就含有容
器组件,可让最上层组件装入其他的组件。
|Frame------JFrame(JRoot Pane)
|
Window|Dialog-----JDialog(JRoot Pane)
|
|
|-----------JWindow(JRoot Pane)
Applet -----------JApplet(JRoot Pane)
图示:
|Grass Pane
|
Root Pane|
| |Content Pane
|Layered Pane|
|Menu Bar
++ Swing读书笔记
1-3:版面管理器(Layout Menager)
|BorderLayout
|FlowLayout
|GridLayout
AWT----|CardLayout
|GridBagLayout
Swing--|BoxLayout
1-3-1:BorderLayout的使用:
BorderLayout的类层次结构图:
java.lang.Object
--java.awt.BorderLayout
构造函数:BorderLayout()建立一个没有间距的border layout
BorderLayout(int hgap,int vgap)建立一个组件间有间距的border layout
BorderLayout将版面划分为东、西、南、北、中
例子:BorderLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BorderLayoutDemo{
public BorderLayoutDemo(){
JFrame f=new JFrame();
Container contentPane=f.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new JButton("EAST"),BorderLayout.EAST);
contentPane.add(new JButton("WEST"),BorderLayout.WEST);
contentPane.add(new JButton("SOUTH"),BorderLayout.SOUTH);
contentPane.add(new JButton("NORTH"),BorderLayout.NORTH);
contentPane.add(new JLabel("CENTER",JLabel.CENTER),BorderLayout.CENTER);
f.setTitle("BorderLayout");
f.pack();
f.setVisible(true);
/***read**/
/*处理关闭窗口的操作,若你没写这一段,就算你已经关闭窗口了,但程序并不会终止。
*/
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
/***read**/
}
public static void main(String[] args){
BorderLayoutDemo b=new BorderLayoutDemo();
}
}
设置组件的间距,你可以使用有间距参数的BorderLayout构造函数,也可以利用BorderLayout的setHgap(int hgap)与
setVgap(int vgap)两个方法来达成。
1-3-2:FlowLayout的使用:
FlowLayout的类层次结构图:
java.lang.Object
--java.awt.FlowLayout
构造函数:FlowLayout()建立一个新的Flow Layout,此FlowLayout默认值是居中对齐,组件彼此有5单位的水平与垂直间距。
FlowLayout(int align)建立一个新的Flow Layout,此FlowLayout可设置排列方式,组件彼此有5单位的水平与垂直
间距。
FlowLayout(int align,int hgap,int vgap)建立一个新的Flow Layout,此FlowLayout可设置排列方式与组件间距。
FlowLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FlowLayoutDemo{
public FlowLayoutDemo(){
JFrame f=new JFrame();
Container contentPane=f.getContentPane();
/*你可以使用有间距的FlowLayout构造函数,使FlowLayout的排列具有间距,并
*并可利用排列方向参数来指定靠什么方向排列,FlowLayout共有五种排列方式,
*依次是CENTER(默认值),LEFT,RIGHT,LEADING,TRAILING,若我们将下面程序第13
*行改成contentPane.setLayout(new FlowLayout(FlowLayout.LEFT));
*/
contentPane.setLayout(new FlowLayout());
contentPane.add(new JButton("first"));
contentPane.add(new JButton("second"));
contentPane.add(new JButton("third"));
contentPane.add(new JButton("fourth"));
contentPane.add(new JButton("fifth"));
contentPane.add(new JButton("Last"));
f.setTitle("FlowLayout");
//f.pack();//必须将f.pach()去掉,否则setSize功能将没有作用
f.setSize(400,220);
f.setVisible(true);
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public static void main(String[] args){
FlowLayoutDemo b=new FlowLayoutDemo();
}
}
1-3-3:GridLayout的使用:
GridLayout的类层次结构图:
java.lang.Object
--java.awt.GridLayout
GridLayout比FlowLayout多了行和列的设置,也就是说你要先设置GridLayout共有几行几列,就如同二维平面一般,然后你加
进去的组件会先填第一行的格子,然后再从第二行开始填,依此类扒,就像是一个个的格子一般。而且GridLayout会将所填进去组
件的大小设为一样。
构造函数:GridLayout()建立一个新的GridLayout,默认值是1行1列。
GridLayout(int rows,int cols)建立一个几行几列的GridLayout.
GridLayout(int rows,int cols, int hgap,int vgap)建立一个几行几列的GridLayout,并设置组件的间距。
例子:GridLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CardLayoutDemo implements ActionListener{
JPanel p1,p2,p3,p4;
int i=1;
JFrame f;
public CardLayoutDemo(){
f=new JFrame();//当做top-level组件
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
p1=new JPanel();
Button b=new Button("Change Card");
b.addActionListener(this);//当按下"Change Card"时,进行事件监听,将会有系统操作产生。
p1.add(b); //处理操作在52-64行.
contentPane.add(p1);
p2=new JPanel();
p2.setLayout(new FlowLayout());
p2.add(new JButton("first"));
p2.add(new JButton("second"));
p2.add(new JButton("third"));
p3=new JPanel();
p3.setLayout(new GridLayout(3,1));
p3.add(new JButton("fourth"));
p3.add(new JButton("fifth"));
p3.add(new JButton("This is the last button"));
p4=new JPanel();
p4.setLayout(new CardLayout());
p4.add("one",p2);
p4.add("two",p3);
/*要显示CardLayout的卡片,除了用show(Container parent,String name)这个方法外
*,也可试试first(Container),next(Container),previous(Container),last(Container)这
*四个方法,一样可以达到显示效果。
*/
((CardLayout)p4.getLayout()).show(p4,"one");
contentPane.add(p4);
f.setTitle("CardLayout");
f.pack();
f.setVisible(true);
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public void actionPerformed(ActionEvent event){
switch(i){
case 1:
((CardLayout)p4.getLayout()).show(p4,"two");
break;
case 2:
((CardLayout)p4.getLayout()).show(p4,"one");
break;
}
i++;
if (i==3) i=1;
f.validate();
}
public static void main(String[] args){
new CardLayoutDemo();
}
}
1-3-5:GridBagLayout的使用:是java中最有弹性但也是最复杂的一种版面管理器。它只有一种构造函数,但必须配合
GridBagConstraints才能达到设置的效果。
GridBagLayout的类层次结构图:
java.lang.Object
--java.awt.GridBagLayout
构造函数:
GirdBagLayout()建立一个新的GridBagLayout管理器。
GridBagConstraints()建立一个新的GridBagConstraints对象。
GridBagConstraints(int gridx,int gridy,int gridwidth,int gridheight,double weightx,double weighty,
int anchor,int fill, Insets insets,int ipadx,int ipady)建立一个新的GridBagConstraints对象
,并指定其参数的值。
参数说明:
gridx,gridy:设置组件的位置,gridx设置为GridBagConstraints.RELATIVE代表此组件位于之前所加入组件的右边。
若将gridy设置为GridBagConstraints.RELATIVE代表此组件位于以前所加入组件的下面。建议定义出
gridx,gridy的位置,以便以后维护程序。表示放在几行几列,gridx=0,gridy=0时放在0行0列。
gridwidth,gridheight:用来设置组件所占的单位长度与高度,默认值皆为1。你可以使用GridBagConstraints.REMAINDER常
量,代表此组件为此行或此列的最后一个组件,而且会占据所有剩余的空间。
weightx,weighty:用来设置窗口变大时,各组件跟着变大的比例,当数字越大,表示组件能得到更多的空间,默认值皆为0。
anchor: 当组件空间大于组件本身时,要将组件置于何处,有CENTER(默认值)、NORTH、NORTHEAST、EAST、SOUTHEAST、
WEST、NORTHWEST可供选择。
insets:设置组件之间彼此的间距,它有四个参数,分别是上,左,下,右,默认为(0,0,0,0).
ipadx,ipady:设置组件内的间距,默认值为0。
我们以前提过,GridBagLayout里的各种设置都必须通过GridBagConstraints,因此当我们将GridBagConstraints的参数都设置
好了之后,必须new一个GridBagConstraints的对象出来,以便GridBagLayout使用。
例子:
GridBagLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridBagLayoutDemo{
public GridBagLayoutDemo(){
JButton b;
GridBagConstraints c;
int gridx,gridy,gridwidth,gridheight,anchor,fill,ipadx,ipady;
double weightx,weighty;
Insets inset;
JFrame f=new JFrame();
GridBagLayout gridbag=new GridBagLayout();
Container contentPane=f.getContentPane();
contentPane.setLayout(gridbag);
b=new JButton("first");
gridx=0;
gridy=0;
gridwidth=1;
gridheight=1;
weightx=10;
weighty=1;
anchor=GridBagConstraints.CENTER;
fill=GridBagConstraints.HORIZONTAL;
inset=new Insets(0,0,0,0);
ipadx=0;
ipady=0;
c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,
fill,inset,ipadx,ipady);
gridbag.setConstraints(b,c);
contentPane.add(b);
b=new JButton("second");
gridx=1;
gridy=0;
gridwidth=2;
gridheight=1;
weightx=1;
weighty=1;
anchor=GridBagConstraints.CENTER;
fill=GridBagConstraints.HORIZONTAL;
inset=new Insets(0,0,0,0);
ipadx=50;
ipady=0;
c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,
fill,inset,ipadx,ipady);
gridbag.setConstraints(b,c);
contentPane.add(b);
b=new JButton("third");
gridx=0;
gridy=1;
gridwidth=1;
gridheight=1;
weightx=1;
weighty=1;
anchor=GridBagConstraints.CENTER;
fill=GridBagConstraints.HORIZONTAL;
inset=new Insets(0,0,0,0);
ipadx=0;
ipady=50;
c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,
fill,inset,ipadx,ipady);
gridbag.setConstraints(b,c);
contentPane.add(b);
b=new JButton("fourth");
gridx=1;
gridy=1;
gridwidth=1;
gridheight=1;
weightx=1;
weighty=1;
anchor=GridBagConstraints.CENTER;
fill=GridBagConstraints.HORIZONTAL;
inset=new Insets(0,0,0,0);
ipadx=0;
ipady=0;
c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,
fill,inset,ipadx,ipady);
gridbag.setConstraints(b,c);
contentPane.add(b);
b=new JButton("This is the last button");
gridx=2;
gridy=1;
gridwidth=1;
gridheight=2;
weightx=1;
weighty=1;
anchor=GridBagConstraints.CENTER;
fill=GridBagConstraints.HORIZONTAL;
inset=new Insets(0,0,0,0);
ipadx=0;
ipady=50;
c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,
fill,inset,ipadx,ipady);
gridbag.setConstraints(b,c);
contentPane.add(b);
f.setTitle("GridBagLayout");
f.pack();
f.setVisible(true);
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public static void main(String[] args){
new GridBagLayoutDemo();
}
}
1-3-5:BoxLayout的使用:
BoxLayout的类层次结构图:
java.lang.Object
--java.awt.BoxLayout
BoxLayout提供了两个常数X_AXIS,Y_AXIS来表示水平或垂直排列。若放进去的组件不等高,则系统将会使所有的组件与最高组件
等高,还有,若你将组件都摆在同一行时,系统不因组件宽度在于Container的宽度,而使组件自动摆在下一行,你必须自行处理换
行的操作。
构造函数:
BoxLayout(Container targe,int axis)建立一个水平或垂直的BoxLayout.
讲到BoxLayout,我们就不得不提到Box这个Container,Box这个Container默认的Layout为BoxLayout,而它只能使用这个Layout,
否则编译时会有Error产生,如同前面所讲的,BoxLayout是以水平或垂直方式排列,因此,当我们要产生一个Box Container时,
就必须指定它的排列方式,下面为Box的构造函数:
Box(int axis) 建立一个Box Container,并指定组件的排列方式是水平或垂直。
上面的axis参数,我们可以使用BoxLayout.X_AXIS或BoxLayout.Y_AXIS来指定。或是利用Box类所提供的两个方法:
createHorizontalBox()与createVerticalBox(),来建立BoxContainer.
Box类提供4种透明的组件来做更方便的版面管理。分别是glue、strut、rigid、filler:
下面以两个相连的按钮当例子,起始状态如下:
B1.java
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4 public class B1{
5 public B1(){
6 JFrame f=new JFrame();
7 Container contentPane=f.getContentPane();
8 Box baseBox=Box.createHorizontalBox();
9 contentPane.add(baseBox);
10 baseBox.add(new JButton("A"));
11 baseBox.add(new JButton("B"));
12 f.setTitle("BoxLayout");
13 f.setSize(new Dimension(200,50));
14 f.setVisible(true);
15 f.addWindowListener(
16 new WindowAdapter(){
17 public void windowClosing(WindowEvent e){
18 System.exit(0);
19 }
20 }
21 );
22 }
public static void main(String[] args){
B1 b=new B1();
}
}
Glue:当glue插入在两组件间时,它会将两组件挤到最左与最右(或最上与最下),透明的glue将会占满整个中间的空间。
例:
在10与11行间加入下面一行程序:
baseBox.add(Box.createHorizontalGlue());
Strut:当你不想将A与B按钮挤到最旁边时,你可以使用Strut组件,来设置所需要的大小,但仅能限定一维的大小,例如限定
水平或垂直高度。
例:在10与11行间加入下面一行程序:
baseBox.add(Box.createHorizontalStrut(50));//A,B之间间隔50个像素。
Rigid:这个透明组件跟Strut很像,但它可以设置二维的限制,也就是可以设置水平与垂直的限制宽度。
例:在10与11行间加入下面一行程序:
baseBox.add(Box.createRigidArea(new Dimension(50,50)));
为了将Rigid的高度功能显示出来,因此以pack()方法代替setSize()方法,11行替换为:f.pack();
若我们将高度再拉长,例如baseBox.add(Box.createRigidArea(new Dimension(50,50)));的Dimension改成(50,100),则两
组件的上下空白将会增大,因为透明的Rigid组件高度增高了。
Filler:Filler是Box的inner class,它的功能跟Rigid很像,都可以指定长宽的大小限制,且Filler可以指定最大、较佳、最小的长
宽大小,以下是Filler的构造函数:
Box.Filler(Dimension min,Dimension pref Dimension max)建立一个指定大小的Filler对象。
参数min表示最小的显示区域大小,如同上面的例子所示,若所设置最小区域的高度大于按钮A与B的高度,则按钮A与B的上方
与下方将有空白出现。
pref表示较佳的显示区域大小。max表示最大的显示区域大小。
例:在10与11行间加入下面一行程序:
baseBox.add(new Box.Filler(new Dimension(50,50),
new Dimension(100,50),
new Dimension(200,50)));
Box类所提供的方法:
Static Component createGlue()构造一个Glue组件可向水平与垂直方向延伸
Static Box createHorizontalBox()构造一个水平排列的Box组件
Static Component createHorizontalGlue()构造一个水平的Glue组件
Static Component createHorizontalStrut(int width)构造一个水平的Strut组件
Static Component createRigidArea(Dimension d)构造一个Rigid组件
Static Box createVerticalBox()构造一个垂直排列的Box组件
Static Component createVerticalGlue()构造一个垂直的Glue组件
Static Component createVerticalStrut(int height)构造一个垂直的Strut组件
AccessibleContext getAccessibleContext()取得与JComponent相关边的AccessibleContext
Void setLayout(LayoutManager l)丢出AWTError,因为Box只能使用BoxLayout
例子:BoxLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BoxLayoutDemo{
public BoxLayoutDemo(){
JFrame f=new JFrame();
Container contentPane=f.getContentPane();
Box baseBox=Box.createHorizontalBox();//先产生水平排列方式的Box组件,当作基底容器(BaseBox)
contentPane.add(baseBox);
/*产生垂直排列方式的Box组件来安置第一与第三个按钮
*/
Box vBox=Box.createVerticalBox();
JButton b=new JButton("first");
vBox.add(b);
b=new JButton("third");
b.setMaximumSize(new Dimension(100,150));
vBox.add(b);
baseBox.add(vBox);
/*产生垂直排列方式的Box组件来安置第二与另一个水平排列方式的Box组件
*/
Box vBox1=Box.createVerticalBox();
baseBox.add(vBox1);
b=new JButton("second");
b.setAlignmentX(Component.CENTER_ALIGNMENT);
b.setMaximumSize(new Dimension(300,50));
vBox1.add(b);
Box hBox=Box.createHorizontalBox();
vBox1.add(hBox);
/*将第四与最后一个按钮加入水平排列方式的Box组件中
*/
Box vBox2=Box.createVerticalBox();
vBox2.add(Box.createVerticalStrut(50));
vBox2.add(new JButton("fourth"));
vBox2.add(Box.createVerticalStrut(50));
hBox.add(vBox2);
Box vBox3=Box.createVerticalBox();
vBox3.add(Box.createVerticalGlue());
vBox3.add(new JButton("THis is the last button"));
hBox.add(vBox3);
f.setTitle("BoxLayout");
f.pack();
f.setVisible(true);
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public static void main(String[] args){
BoxLayoutDemo b=new BoxLayoutDemo();
}
}
++ Swing读书笔记事件处理
2-1:事件处理:
Source Event Event Listener
--------------------------------------------------------------------------------------------------------------
AbstractButton ActionEvent ActionListener
(JButton,JtoggleButton, ChangeEvent ChangeListener
JCheckBox,JRadioButton ItemEvent ItemListener
-------------------------------------------------------------------------------------------------------
JTextField ActionEvent ActionListener
JpasswordField CaretEvent CaretListener
DocumentEvent DocumentListener
UndoableEvent UndoableListener
-------------------------------------------------------------------------------------------------------
JTextArea CaretEvent CaretListener
DocumentEvent DocumentListener
UndoableEvent UndoableListener
-------------------------------------------------------------------------------------------------------
JTextPane CaretEvent CaretListener
JEditorPane DocumentEvent DocumentListener
UndoableEvent UndoableListener
HyperlinkEvent HyperlinkListener
-------------------------------------------------------------------------------------------------------
JComboBox ActionEvent ActionListener
ItemEvent ItemListener
-------------------------------------------------------------------------------------------------------
JList ListSelectionEvent ListSelectionListener
ListDataEvent ListDataListener
-------------------------------------------------------------------------------------------------------
JFileChooser ActionEvent ActionListener
-------------------------------------------------------------------------------------------------------
JMenuItem ActionEvent ActionListener
ChangeEvent ChangeListener
ItemEvent ItemListener
MenuKeyEvent MenuKeyListener
MenuDragMouseEvent MenuDragMouseListener
-------------------------------------------------------------------------------------------------------
JMenu MenuEvent MenuListener
-------------------------------------------------------------------------------------------------------
JPopupMenu PopupMenuEvent PopupMenuListener
-------------------------------------------------------------------------------------------------------
JProgressBar ChangeEvent ChangeListener
-------------------------------------------------------------------------------------------------------
JSlider ChangeEvent ChangeListener
-------------------------------------------------------------------------------------------------------
JScrollBar AdjustmentEvent AdjustMentListener
-------------------------------------------------------------------------------------------------------
JTable ListSelectionEvent ListSelectionListener
TableModeEvent TableModeListener
TableColumnModelEvent TableColumnModeListener
CellEditorEvent CellEditorListener
-------------------------------------------------------------------------------------------------------
JTabbedPane ChangeEvent ChangeListener
-------------------------------------------------------------------------------------------------------
JTree TreeSelectionEvent TreeSelectionListener
TreeExpansionEvent TreeExpansionListener
TreeWillExpandEvent TreeWillExpandListener
TreeModeEvent TreeModeListener
-------------------------------------------------------------------------------------------------------
JTimer ActionEvent ActionListener
-------------------------------------------------------------------------------------------------------
底层事件:
---------------------------------------------------------------------------------------------------------------
Event Listener
ComponentEvent ComponentListener
ContainerEvent ConatainerListener
FocusEvent FocusListener
KeyEvent KeyListener
MouseEvent MouseListener
MouseMotionEvent MouseMotionListener
WindowEvent WindowListener
ComponentEvent:主要处理组件大小的改变,位置的改变,或是可见与不可见状态(hidden or visible)等。
ContainerListener:主要在处理组件的加入或移出容器。
FocusListener:主要在处理焦点的取得或移开焦点等操作。
MouseListener:主要就是在处理鼠标是否在某个组件上,是否按下鼠标键,是否离开某个组件等操作,主要针对鼠标按键与位置
作处理。
MouseMotionListener:主要就是在追踪鼠标的位置,如(X,Y)坐标的位置,主人是针对鼠标坐标与拖曳操作作处理。
WindowListener:主要在处理窗口的所有操作。如处理active窗口或是de-active窗口,处理窗口的最大、最小化,处理窗口的关闭
、打开、退出等。
以上所述的每种EventListener都是一种interface,里面只有定义这个EventListener的interface,然后在这个类中,把要处理事
件的程序代码写在此interface的方法中。这是处理事件的标准操作,当然还有其他编写模式,如:利用inner class的匿名类方法
,就可以不用在class后面加上implements EventListener的表示法,或是利用Adapter类,就不用一一将interface中的每种方法都
实现。
让我们来了解一下,每一种EventListener的interface到底提供了哪几种方法要我们实现(Implement)!我们把事件区分成是由
Swing或是AWT所引发:
Swing EventListener Method
----------------------------------------------------------------------------------------------------------------
CaretListener caretUpdate(CaretEvent e)
--------------------------------------------------------------------------------------------------------------
CellEditorListener editingCanceled(ChangeEvent e)
editingStopped(ChangeEvent e)
--------------------------------------------------------------------------------------------------------------
ChangeListener stateChanged(ChangeEvent e)
--------------------------------------------------------------------------------------------------------------
DocumentListener changedUpdate(DocumentEvent e)
insertUpdate(DocumentEvent e)
removeUpdate(DocumentEvent e)
--------------------------------------------------------------------------------------------------------------
HyperlinkListener hyperlinkUpdate(HyperlinkEvent e)
--------------------------------------------------------------------------------------------------------------
ListDataListener contentsChanged(ListdataEvent e)
intervalAdded(ListDataEvent e)
intervalRemoved(ListDataEvent e)
--------------------------------------------------------------------------------------------------------------
ListSelectionListener valueChanged(ListSelectionEvent e)
--------------------------------------------------------------------------------------------------------------
MenuDragMouseListener menuDragMouseDragged(MenuDragMouseEvent e)
menuDragMouseEntered(menuDragMouseEvent e)
menuDragMouseExited(MenuDragMouseEvent e)
menuDragMouseReleased(MenuDragMouseEvent e)
--------------------------------------------------------------------------------------------------------------
MenuKeyListener menuKeyPressed(MenuKeyEvent e)
menuKeyReleased(MenuKeyEvent e)
menuKeyTyped(MenuKeyEvent e)
--------------------------------------------------------------------------------------------------------------
MenuListener menuCanceled(MenuEvent e)
menuDeselected(MenuEvent e)
menuSelected(MenuEvent e)
--------------------------------------------------------------------------------------------------------------
PopupMenuListener popupMenuCanceled(PopupMenuEvent e)
popupMenuWillBecomeInvisible(PopupMenuEvent e)
popupMenuWillBecomeVisible(PopupMenuEvent e)
--------------------------------------------------------------------------------------------------------------
TableColumnModelListener columnAdded(TableColumnModelEvent e)
columnMarginChanged(ChangeEvent e)
columnMoved(TableColumnModelEvent e)
columnRemoved(TableColumnModelEvent e)
columnSelectionChanged(ListSelectionEvent e)
--------------------------------------------------------------------------------------------------------------
TableModelListener tableChanged(TableModelEvent e)
--------------------------------------------------------------------------------------------------------------
TreeExpansionListener treeCollapsed(TreeExpansionEvent event)
treeExpanded(TreeExpansionEvent event)
---------------------------------------------------------------------------------------------------------------
TreeModelListener treeNodesChanged(TreeModelEvent e)
treeNodesInserted(TreeModelEvent e)
treeNodesRemoved(TreeModelEvent e)
treeStructureChanged(TreeModelEvent e)
---------------------------------------------------------------------------------------------------------------
TreeSelectionListener valueChanged(TreeSelectionEvent e)
---------------------------------------------------------------------------------------------------------------
TreeWillExpandListener treeWillCollapse(TreeExpansionEvent event)
treeWillExpand(TreeExpansionEvent event)
---------------------------------------------------------------------------------------------------------------
UndoableEditListener undoableEditHappened(UndoableEditEvent e)
---------------------------------------------------------------------------------------------------------------
AWT EventListener Method
--------------------------------------------------------------------------------------------------------------
ActionListener actionPerformed(ActionEvent e)
--------------------------------------------------------------------------------------------------------------
AdjustmentListener adjustmentValueChanged(AdjustmentEvent e)
--------------------------------------------------------------------------------------------------------------
ComponentListener componentHidden(ComponentEvent e)
componentMoved(ComponentEvent e)
componentResized(ComponentEvent e)
componentShown(ComponentEvent e)
--------------------------------------------------------------------------------------------------------------
ContainerListener componentAdded(ContainerEvent e)
componentRemoved(ContainerEvent e)
--------------------------------------------------------------------------------------------------------------
FocusListener focusGained(FocusEvent e)
focusLost(FocusEvent e)
--------------------------------------------------------------------------------------------------------------
ItemListener itemStateChanged(ItemEvent e)
--------------------------------------------------------------------------------------------------------------
KeyListener keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
--------------------------------------------------------------------------------------------------------------
MouseListener mouseClicked(MouseEvent e)
mouseEntered(MouseEvent e)
mouseExited(MouseEvent e)
mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
--------------------------------------------------------------------------------------------------------------
MouseMotionListener mouseDragged(MouseEvent e)
mouseMoved(MouseEvent e)
--------------------------------------------------------------------------------------------------------------
WindowListener windowActivated(WindowEvent e)
windowClosed(WindowEvent e)
windowClosing(WindowEvent e)
windowDeactivated(WindowEvent e)
windowDeiconified(WindowEvent e)
windowIconified(WindowEvent e)
windowOpened(WindowEvent e)
---------------------------------------------------------------------------------------------------------------
常用的Adapter类如下:
Adapter 对应的EventListener
---------------------------------------------------------------------------------------------------------------
java.awt.event.ComponentAdapter ComponentListener
java.awt.event.ContainerAdapter ContainerListener
java.awt.event.FocusAdapter FocusListener
java.awt.event.KeyAdapter KeyListener
java.awt.event.MouseAdapter MouseListener
java.awt.event.MouseMotionAdapter MouseMotionListener
java.awt.event.WindowAdapter WindowListener
---------------------------------------------------------------------------------------------------------------
在java中提供两个方法让你知道到底是哪个组件触发了事件,那就是getSource()与getActionCommane();getActionCommand()
方法是ActionEvent类所提供,而getSource()方法是EventObject类所提供,但ActionEvent类继承了EventObject类,因此这两个
方法ActionEvent都可以使用,看下面的例子就知道了:
EventDemo5.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventDemo5 extends WindowAdapter implements ActionListener
{
JButton b1 = null;
JButton b2 = null;
public EventDemo5()
{
JFrame f = new JFrame("EventDemo5");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
b1 = new JButton("按我有声音喔");
b2 = new JButton("按我可开新窗口");
b1.addActionListener(this);
b2.addActionListener(this);
contentPane.add(b1);
contentPane.add(b2);
f.pack();
f.show();
f.addWindowListener(this);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b1)//getSource判断哪个按钮被按下了。
Toolkit.getDefaultToolkit().beep();
if(e.getSource()==b2)
{
JFrame newF = new JFrame("新窗口");
newF.setSize(200,200);
newF.show();
}
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
public static void main(String args[])
{
new EventDemo5();
}
}
-------------------------------------------------------------------------------------------------------------
EventDemo6.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventDemo6 extends WindowAdapter implements ActionListener
{
JButton b1 = null;
JButton b2 = null;
public EventDemo6()
{
JFrame f = new JFrame("EventDemo6");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
b1 = new JButton("按我有声音喔");
b2 = new JButton("按我可开新窗口");
b1.addActionListener(this);
b2.addActionListener(this);
contentPane.add(b1);
contentPane.add(b2);
f.pack();
f.show();
f.addWindowListener(this);
}
public void actionPerformed(ActionEvent e)
{
if((e.getActionCommand()).equals("按我有声音喔")) //getActionCommand()方法会返回按钮上的文字字符串。
Toolkit.getDefaultToolkit().beep();
if((e.getActionCommand()).equals("按我可开新窗口"))
{
JFrame newF = new JFrame("新窗口");
newF.setSize(200,200);
newF.show();
}
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
public static void main(String args[])
{
new EventDemo6();
}
}
++ Swing读书笔记鼠标事件
2-1-1:MouseListener的使用:
--------------------------------------------------------------------------------------------------------------
MouseListener mouseClicked(MouseEvent e)
mouseEntered(MouseEvent e)
mouseExited(MouseEvent e)
mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
--------------------------------------------------------------------------------------------------------------
MouseDemo1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*我们继承WindowAdapter抽象类并实现MouseListener interface,
*因此我们必须把MouseListener中的5个方法都实现,如果不想实现
*可用匿名内部类的方法编写处理程序。
*/
public class MouseDemo1 extends WindowAdapter implements MouseListener{
JFrame f=null;
JButton b1=null;
JLabel label=null;
public MouseDemo1(){
f=new JFrame("MouseDemo1");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
b1=new JButton("按钮");
label=new JLabel("起始状态,还没有鼠标事件",JLabel.CENTER);
b1.addMouseListener(this);
contentPane.add(label);
contentPane.add(b1);
f.pack();
f.show();
f.addWindowListener(this);
}
public void mousePressed(MouseEvent e){
label.setText("你已经压下鼠标按钮");
}
public void mouseReleased(MouseEvent e){
label.setText("你已经放开鼠标按钮");
}
public void mouseEntered(MouseEvent e){
label.setText("鼠标光标进入按钮");
}
public void mouseExited(MouseEvent e){
label.setText("鼠标光标离开按钮");
}
public void mouseClicked(MouseEvent e){
label.setText("你已经按下按钮");
}
public void windowClosing(WindowEvent e){
System.exit(0);
}
public static void main(String[] args){
new MouseDemo1();
}
}
2-1-2:MouseMotionListener的使用:
下面是讨论MouseMotionListener的使用时机,它提供的下面的两个方法,可让你随时掌握鼠标的坐标,并处理拖曳鼠标
的操作。
--------------------------------------------------------------------------------------------------------------
MouseMotionListener mouseDragged(MouseEvent e)
mouseMoved(MouseEvent e)
--------------------------------------------------------------------------------------------------------------
下面的范例让你知道鼠标在JFrame上的坐标,并拖曳出直线来。
例子:MouseDemo3.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*为了达到画线的功能,我们分别implements MouseListener与MouseMotionListener.
*/
public class MouseDemo3 extends JFrame implements MouseListener,MouseMotionListener{
int flag;//flag=1代表Mouse Moved,flag=2代表Mouse Dragged
int x=0;
int y=0;
int startx,starty,endx,endy;//起始坐标与终点坐标
public MouseDemo3(){
Container contentPane=getContentPane();
contentPane.addMouseListener(this);
contentPane.addMouseMotionListener(this);
setSize(300,300);
show();
addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
/*由mousePressed(),mouseReleased()取得示拖曳的开始与结束坐标*/
public void mousePressed(MouseEvent e){
startx=e.getX();
starty=e.getY();
}
public void mouseReleased(MouseEvent e){
endx=e.getX();
endy=e.getY();
}
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e){
}
public void mouseClicked(MouseEvent e){
}
/*mouseMoved(),mouseDragged()取得鼠标移动的每一个坐标,并调用repaint()方法*/
public void mouseMoved(MouseEvent e){
flag=1;
x=e.getX();
y=e.getY();
repaint();
}
public void mouseDragged(MouseEvent e){
flag=2;
x=e.getX();
y=e.getY();
repaint();
}
public void update(Graphics g){
g.setColor(this.getBackground());
g.fillRect(0,0,getWidth(),getHeight());
paint(g);
}
public void paint(Graphics g){
g.setColor(Color.black);
if (flag==1){
g.drawString("鼠标坐标:("+x+","+y+")",10,50);
g.drawLine(startx,starty,endx,endy);
}
if (flag==2){
g.drawString("拖曳鼠标价坐标:("+x+","+y+")",10,50);
g.drawLine(startx,starty,x,y);
}
}
public static void main(String[] args){
new MouseDemo3();
}
}
++ Swing读书笔记键盘事件处理
3-1-1:键盘事件处理:
--------------------------------------------------------------------------------------------------------------
KeyListener keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
--------------------------------------------------------------------------------------------------------------
KeyDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class KeyDemo extends KeyAdapter implements ActionListener{
JFrame f=null;
JLabel label=null;
JTextField tField=null;
String keyString="";
public KeyDemo(){
f=new JFrame("KeyEventDemo");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(3,1));
label=new JLabel();
tField=new JTextField();
tField.requestFocus();
tField.addKeyListener(this);
JButton b=new JButton("清除");
b.addActionListener(this);
contentPane.add(label);
contentPane.add(tField);
contentPane.add(b);
f.pack();
f.show();
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public void actionPerformed(ActionEvent e){
keyString="";
label.setText("");
tField.setText("");
tField.requestFocus();
}
/*输入字母"O"之后,会产生新窗口*/
public void keyTyped(KeyEvent e){
char c=e.getKeyChar();/*注意getKeyChar()的用法*/
if (c=='o'){
JFrame newF=new JFrame("新窗口");
newF.setSize(200,200);
newF.show();
}
keyString=keyString+c;
label.setText(keyString);
}
public static void main(String[] args){
new KeyDemo();
}
}
除了上面所提的getKeyChar()方法外,KeyEvent类还有两个方法也常常被用到,那就是getKeyCode()与
getKeyModifiersText(int modifiers).键盘上每一个按钮都有对应码(Code),可用来查知用户按了什么键,
如[Shift]键code为16。利用getKeyCode()方法就可以得知这个码,不过读者要注意,这个方法在keyTyped()
上是无法检测出来的,因为keyTyped()只管用户输入的字符,而不会管到键盘的对应码,算是处理比较高层
事件的方法。也就是说keyTyped()方法是keyboad independent,因为不同的键盘可能有不同的对应码(如Windows
U.S. keyboard与windows French keyboard就有不同的对应码)。因此你一定要将getKeyCode()方法写在
keyPressed()或keyReleased()方法中才会有效,因为这两个方法是处理比较低层的方法。
另外getKeyModifiersText()方法可返回修饰键的字符串,如返回“Shift”字符串或是“Ctrl+Shift”字符串,
不过你要先传入modifiers参数。你可以直接使用getModifiers()方法来得到modifiers参数。这个方法是定义在
InputEvent类中,而KeyEvent继承它,因此就能直接使用这个方法。同样,你必须将getKeyModifiersText()与
getModifiers()方法放在keyPressed()或keyReleased()方法中才会有效。
++ 注意
1.KeyEvent类还有两个方法也常常被用到,那就是getKeyCode()与
getKeyModifiersText(int modifiers).键盘上每一个按钮都有对应码(Code),可用来查知用户按了什么键,
如[Shift]键code为16。利用getKeyCode()方法就可以得知这个码,不过读者要注意,这个方法在keyTyped()
上是无法检测出来的,因为keyTyped()只管用户输入的字符,而不会管到键盘的对应码,算是处理比较高层
事件的方法。也就是说keyTyped()方法是keyboad independent,因为不同的键盘可能有不同的对应码(如Windows
U.S. keyboard与windows French keyboard就有不同的对应码)。因此你一定要将getKeyCode()方法写在
keyPressed()或keyReleased()方法中才会有效,因为这两个方法是处理比较低层的方法。
class test{
public static void main(String args[]){
for (int i = 0;i < args.length; i++) {
System.out.println("File " + i + ":" + args[i]);
}
if (args.length<=0) {
System.out.println("No files!");
}
}
}
++ Swing读书笔记窗口与面板的使用
4-1-1:JFrame的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--java.awt.Window
--javax.swing.JFrame
结构函数:
JFram()
JFrame(String title)
例子:JFrame1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JFrame1 implements ActionListener{
public JFrame1(){
JFrame f=new JFrame("JFrameDemo");
/*我们要在JFrame中加入其他组件必须取得Content Pane,然后再加入组件到此Content Pane中。
*相对于AWT,若要在AWT中的Frmae加入某一个组件只要直接调用add()方法即可,不需要先取得
*Content Pane再加入组件。Swing这样的做法似乎多了一道手续,却带来更强大、更有弹性的
*功能,原因就在于Swing的JFrame具有层次(Layer)的概念,可以让你在JFrame中放入的组件不
*会造成混乱。例如当一个JFrame有按钮(JButton)、菜单(JMenu)、快速菜单(Pop-up menu)、
*工具栏(Toolbar)与工具栏符号提示(Tool tip)时,到底哪个组件应该摆在什么组件上面或
*下面,JFrame都有办法处理。以后我们再讨论这个问题。
*/
Container contentPane=f.getContentPane();
JButton b=new JButton("Click me to get new Window");
b.addActionListener(this);
contentPane.add(b);
f.pack();
f.show();//使JFrame变成可看见的(Visible)
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public void actionPerformed(ActionEvent e){
JFrame newf=new JFrame();//产生一个没有标题的JFrame
newf.setSize(200,200);
newf.show();
}
public static void main(String[] args){
new JFrame1();
}
}
4-1-2:Swing的容器结构与JLayeredPane的使用:
类层次结构图:
java.lang.Object
--java.awt.Compontent
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JLayeredPane
我们可把Swing容器的结构看似如下图所示:
|Grass Pane
|
Root Pane|
| |Content Pane
|Layered Pane|
|Menu Bar
其中,Root Pane可以看成是虚拟的容器,包含着Grass Pane、Layered Pane、Content Pane与Menu Bar.Swing的容器包括JApplet
,JFrame,JDialog,JWindow与JInternalFrame都是构造在此结构上,JApplet、JFrame、JDialog、JWindow都是heavyweight容器,只
有JInternalFrame是lightweight容器。当我们要加入某个组件到Swing的容器中时,并不是直接加入到Root Pane,而是加入到
RootPane下面的某一成员(Layered Pane或Content Pane)
Content Pane与Menu Bar只是Layered Pane的其中一层,我们称此层为Frame-Content Layer.若你想知道Frame-Content Layer
在Layered Pane的层次是什么?你可以由JLayeredPane类中的Frame_Content_layer类常数取得。
由此我们可以知道,Layered Pane基本上可拥有非常多的“层”(Layer),那么如何分辨哪一层是在哪一层的上面或下面呢?
答案是Z_order.Z_order本身具有两个整数值,一个是代表层(Layer)的深度,另一个代表同层的相关位置(Position),当Z_order
的Layer数值越小时,表示其位置就在越底层,当Z_order的Layer数值越大时,表示其位置就在越上层。在JLayeredPane类中,共定
义了6个Z_order常数供用户参考,如下所示:
DEFAULT_LAYER:Z_order的Layer数值为0,以整数对象Integer(0)来表示,一般我们加入的组件若没有标记是第几层,默认值就
把组件放在此Default Layer中。
PALETTE_LAYER:Z_order的Layer数值为100,以整数对象Integer(100)来表示,位于Default Layer之上,一般用于放置可移动的
工具栏(Floatable Toolbar).
MODAL_LAYER:Z_order的Layer数值为200,以整数对象Integer(200)来表示,位于PALETTE_LAYER之上,一般用于放置对话框
(Dialog Box).
POPUP_LAYER:Z_order的Layer数值为300,以整数对象Integer(300)来表示,位于MODAL_LAYER之上,一般用于快捷菜单(Poup
Menu)与工具栏提示(Tool Tips)中.
DRAG_LAYER:Z_order的Layer数值为400,以整数对象Integer(400)来表示,位于POPUP_LAYER之上,一般用于拖曳组件使其在不同
区域上.
FRAME_CONTENT_LAYER:Z_order的Layer数值为-30000,以整数对象Integer(-30000)来表示,一般来说,Frame Content Layer
最底层的是Layer,用来表示Content Pane与Menu Bar的位置,大部份情况我们不会更改到这个数值。
一般程序会提供良好的Z-order自动管理机制,当然java也不例外,因此大部份情况我们不会使用到Z-order,因为系统会自动
帮我们管理得好好的。用户只需将所需的组件直接加入Content Pane即可,不需要知道它们之间的顺序关系。但如果今天您必须处
理对象之间的层次关系时,例如Word中你可以把某个绘图对象下推至下一层,你就必须亲自处理Z-order的关系了。
下面我们来看如何利用JLayeredPane来控制对象的层次关系:
这个例子分别用7个JLabel对象层层相叠,每个JLabel对象都有不同的Z-order数值,形成7层相叠的效果!
JLayeredPane1.java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JLayeredPane1 extends JFrame{
public JLayeredPane1(){
super("JLayeredPane");
/*由小到大定义组件深度数值,也就是Z-order layer的大小。
*/
Integer[] layerConstants={
JLayeredPane.DEFAULT_LAYER,JLayeredPane.PALETTE_LAYER,
new Integer(101),JLayeredPane.MODAL_LAYER,new Integer(201),
JLayeredPane.POPUP_LAYER,JLayeredPane.DRAG_LAYER
};
/*定义每个JLabel的颜色
*/
Color[] colors={
Color.red,Color.blue,Color.magenta,Color.cyan,Color.yellow,
Color.green,Color.pink
};
Point position=new Point(10,10);
JLabel[] label=new JLabel[7];
JLayeredPane layeredPane=getLayeredPane();//取得窗口的Layered Pane
for(int i=0;i<7;i++){
label[i]=createLabel("第"+(i+1)+"层",colors[i],position);
position.x=position.x+20;
position.y=position.y+20;
//将组件(JLabel)放入Layered Pane中并给予深度(Z-order layer)的数值。
layeredPane.add(label[i],layerConstants[i]);
}
setSize(new Dimension(280,280));
show();
addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public JLabel createLabel(String content,Color color,Point position){
JLabel label=new JLabel(content,JLabel.CENTER);
label.setVerticalAlignment(JLabel.TOP);
label.setBackground(color);
label.setForeground(Color.black);
label.setOpaque(true);
label.setBounds(position.x,position.y,100,100);
return label;
}
public static void main(String[] args){
new JLayeredPane1();
}
}
从上面的例子可以看出,虽然“Button1”的层次比“按钮一”低,但它却显示在“按钮一”之上,原因"按钮一"是加在
Content Pane中而不是加在LayeredPane上,因此显示时以Content Pane与加在Content Pane上的组件来做层次的比较。
从面的例子可以看出,Z-order layer数值越小的组件在越底层,也就会被Z-order layer值较大的组件所覆盖。那如果两个
组件都在同一层且相互重叠,怎么知道它们之间的层次关系呢?答案是利用Z-order的另外一个整数值:position。position
数值的关系跟 Z-order的layer数值恰好相反,在同一层中的对象,若position数值越小者则在越上层,position数值越大者则
在越下层。position的数值是从-1~n~1,n是指在同一层中组件的个数,数值-1代表最底层,意思跟n-1一样;数值0代表最上层。
你可以使用JLayeredPane类提供的moveToBack()方法将组件推至position为-1(最底端)的位置,或是使用moveToFront()方法
将组件推至position为0(最顶端)的位置。我们来看下面的范例:JLayeredPane3.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JLayeredPane3 extends JFrame{
public JLayeredPane3(){
super("JLayeredPane");
JLabel label1=new JLabel("左Label",JLabel.CENTER);
label1.setVerticalAlignment(JLabel.TOP);
label1.setBackground(Color.red);
label1.setForeground(Color.black);
label1.setOpaque(true);
label1.setBounds(20,20,150,150);
JLabel label2=new JLabel("右sLabe2",JLabel.CENTER);
label2.setVerticalAlignment(JLabel.TOP);
label2.setBackground(Color.red);
label2.setForeground(Color.black);
label2.setOpaque(true);
label2.setBounds(50,50,150,150);
JLayeredPane layeredPane=getLayeredPane();
layeredPane.add(label1,new Integer(10),1);
layeredPane.add(label2,new Integer(10),0);
setSize(new Dimension(280,280));
show();
addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public static void main(String[] args){
new JLayeredPane3();
}
}
++ Swing读书笔记JInternalFrame的使用(窗口与面板)
5-1-1:JInternalFrame的使用
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JInternalFrame
JinternalFrame的使用跟JFrame几乎一样,可以最大化、最小化、关闭窗口、加入菜单等功能;唯一不同的是JinternalFrame是
lightweight component ,也就是说JInternalFrame不能单独出现,必须依附在最上层组件上。由于这个特色,JInternalFrame能
够利用java提供的Look and Feel功能作出完全不同于原有操作系统所提供的窗口外型,也比JFrame更具有弹性。
一般我们会将Internal Fram加入Desktop Pane方便管理,Desktop Pane是一种特殊的Layered pane,用来建立虚拟桌面(Vitual
Desktop).它可以显示并管理众多Internal Frame之间的层次关系。以下是JDesktopPane的类层次结构图;
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JLayeredPane
--javax.swing.JDesktop
我们先来看看如何构造JInternalFrame与JDesktopPane,再来看它跟Desktop Pane之间的关系。下面分别是JInternalFram与
JDesktopPane的构造函数:
JInternalFrame构造函数:
JInternalFrame():建立一个不能更改大小、不可关闭、不可最大最小化、也没有标题的Internal Frame。
JInternalFrame(String title):建立一个不能更改大小、不可关闭、不可最大最小化、但具有标题的Internal Frame。
JInternalFrame(String title,boolean resizable):建立一个不可关闭、不可最大最小化、但可变更大小且具有标题的
Internal Frame。
JInternalFrame(String title,boolean resizable,boolean closable):建立一个可关闭、可更改大小、且具有标题,但不可
最大化最小化的Internal Frame.
JInternalFrame(String title,boolean resizable,boolean closable,boolean maximizable):建立一个可关闭、可更改大小、
具有标题、可最大化,但不可最小化的Internal Frame.
JInternalFrame(String title,boolean resizable,boolean closable,boolean maximizable,boolean iconifiable):
建立一个可关闭、可更改大小、具有标题、可最大化与最小化的Internal Frame.
JDesktopPane构造函数:
JDesktopPane():建立JDesktopPane组件。
如何利用JDesktoPane来管理JInternalFrame:
JInternalFrame1.java
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class JInternalFrame1 extends JFrame implements ActionListener{
JDesktopPane desktopPane;
int count = 1;
public JInternalFrame1() {
super("JInternalFrame1");
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());
JButton b = new JButton("Create New Internal Frames");
b.addActionListener(this);//当用户按下按钮时,将运行actionPerformed()中的程序
contentPane.add(b, BorderLayout.SOUTH);
/*建立一个新的JDesktopPane并加入于contentPane中
*/
desktopPane = new JDesktopPane();
contentPane.add(desktopPane);
setSize(350, 350);
show();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
/*产生一个可关闭、可改变大小、具有标题、可最大化与最小化的Internal Frame.
*/
public void actionPerformed(ActionEvent e)
{
JInternalFrame internalFrame = new JInternalFrame(
"Internal Frame "+(count++), true, true, true, true);
internalFrame.setLocation( 20,20);
internalFrame.setSize(200,200);
internalFrame.setVisible(true);
//取得JInternalFrame的Content Pane,用以加入新的组件。
Container icontentPane = internalFrame.getContentPane();
JTextArea textArea = new JTextArea();
JButton b = new JButton("Internal Frame Button");
/*将JTextArea与JButton对象加入JInternalFrame中。由此呆知,JInteranlFrame加入组件
*的方式与JFrame是一模一样。
*/
icontentPane.add(textArea,"Center");
icontentPane.add(b,"South");
//将JInternalFrame加入JDesktopPane中,如此一来,即使产生很多JInternalFrame,JDesktopPane也
//能将它们之间的关系管理得相当良好。
desktopPane.add(internalFrame);
try {
internalFrame.setSelected(true);
} catch (java.beans.PropertyVetoException ex) {
System.out.println("Exception while selecting");
}
}
public static void main(String[] args) {
new JInternalFrame1();
}
}
5-1-2:JPanel的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JPanel
Panel民是java中时常用到的容器之一,Panel除了可以让组件加入外,有效的利用Panel可以使版面管理更为容易。Swing的
JPanel支持double buffering的功能,使得JPanel在处理动画上更为流畅,较不会有画面闪烁的情况发生。下面为它的构造函
数:
JPanel构造函数:
JPanel():建立一个具有double buffering功能的JPanel,默认的版面管理是Flow Layout.
JPanel(boolean isDoubleBuffered):选择建立是否具有double buffering功能的JPanel,默认的版面管理是Flow Layout.
JPanel(LayoutManager layout):建立一个具有double buffering功能JPanel,可自定义版面管理器.
JPanel(LayoutManager layout,boolean isDoubleBuffered):选择建立是否具有double buffering功能的JPanel,并自定义版面管
理器.
下面这个例子我们用JPanel来排列5个JLabel对象,你将可以发现利用JPanel搭配版面管理,可以做出更复杂的排列效果。
JPanel1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JPanel1
{
public JPanel1()
{
JFrame f = new JFrame("JPanelDemo");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
JLabel[] label = new JLabel[5];
for(int i=0; i
label[i] = new JLabel("Label "+(i+1),JLabel.CENTER);
label[i].setBackground(Color.lightGray);
label[i].setBorder(BorderFactory.createEtchedBorder());
label[i].setOpaque(true);//setOpaqueIture)方法的目的是让组件变成不透明,这样我们在JLabel上所设置的颜色
// 才能显示出来。
}
JPanel panel1 = new JPanel(new GridLayout(1,1));
panel1.add(label[0]);
JPanel panel2 = new JPanel(new GridLayout(1,2));
JPanel panel3 = new JPanel(new GridLayout(1,2));
panel3.add(label[1]);
panel3.add(label[2]);
JPanel panel4 = new JPanel(new GridLayout(2,1));
panel4.add(label[3]);
panel4.add(label[4]);
panel2.add(panel3);
panel2.add(panel4);
contentPane.add(panel1);
contentPane.add(panel2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] arg)
{
new JPanel1();
}
}
由上例可知,利用JPanel可以使版面的排列方式更生动,若没有JPanel的帮助,想直接由contentPane排列成如上例所示,便必须
借助复杂的GridBagLayout版面管理器了。
5-1-3:JSplitPane的使用:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JSplitPane
Split Pane(分割面版)一次可将两个组件同时显示在两个显示区中,若你想要同时在多个显示区显示组件,你便必须同时使
用多个Split Pane。JSplitPane提供两个常数让你设置到底是要水平分割还是垂直分割。这两个常数分别是:HORIZONTAL_SPIT,
VERTICAL_SPLIT.除了这两个重要的常数外,JSplitPane还提供许多类常数让你使用,我们会在下面的例子中介绍比较常用的类常数
,其余信息请参年java API.
JsplitPane构造函数:
JSplitPane():建立一个新的JSplitPane,里面含有两个默认按钮,并以水平方向排列,介没有Continuous Layout功能。
JSplitPane(int newOrientation):建立一个指定水平或垂直方向切割JSplitPane,但没有Continuous Layout功能。
JSplitPnae(int newOrientation,boolean newContinuousLayout):建立一个指定水平或垂直方向切割的JSplitPane,且指定是否具
有Continuous Layout功能。
JSplitPane(int newOrientation,boolean newContinuousLayout,Component newLeftComponent,Component newRightComponent):
建立一个指定水平或垂直方向切割的JSplitPane,且指定显示区所要显示的组件,并设置是否Continuous
Layout功能。
JSplitPane(int newOrientation,COmponent newLeftComponent,COmponent newRightComponent):
建立一个指定水平或垂直方向切割的JSplitPane,且指定显示区所要显示的组件,但没有Continuous Layout功能
。
上面所说的Continuous Layout意思是指当你拖曳切割面版的分隔线时,窗口内的组件是否会随着分隔线的拖曳而动态改变大小
。newContinuousLayout是一个boolean值,若设为true,则组件大小会随着分隔线的拖曳而一起改动;
若设为false,则组件大小在分隔线停止改动时才确定。你也可以使用JSplitPane中的setContinuousLayout()方法来设置此项目。
JSplitPane的例子:JSplitPane1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JSplitPane1{
public JSplitPane1(){
JFrame f=new JFrame("JSplitPaneDemo");
Container contentPane=f.getContentPane();
JLabel label1=new JLabel("Label 1",JLabel.CENTER);
label1.setBackground(Color.green);
label1.setOpaque(true);//setOpaqueIture)方法的目的是让组件变成不透明,这样我们在JLabel上所设置的颜色
// 才能显示出来。
JLabel label2=new JLabel("Label 2",JLabel.CENTER);
label2.setBackground(Color.pink);
label2.setOpaque(true);
JLabel label3=new JLabel("Label 3",JLabel.CENTER);
label3.setBackground(Color.yellow);
label3.setOpaque(true);
/*加入label1,label2到splitPane1中,并设置此splitPane1为水平分割且具有Continuous Layout的
*功能。
*/
JSplitPane splitPane1=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,false,label1,label2);
/*设置splitPane1的分隔线位置,0.3是相对于splitPane1的大小而定,因此这个值的范围在0.0~1.0
*中。若你使用整数值来设置splitPane的分隔线位置,如第34行所示,则所定义的值以pixel为计算单位
*/
splitPane1.setDividerLocation(0.3);
/*设置JSplitPane是否可以展开或收起(如同文件总管一般),设为true表示打开此功能。
*/
splitPane1.setOneTouchExpandable(true);
splitPane1.setDividerSize(10);//设置分隔线宽度的大小,以pixel为计算单位。
JSplitPane splitPane2=new JSplitPane(JSplitPane.VERTICAL_SPLIT,false,splitPane1,label3);
splitPane2.setDividerLocation(35);
//设置JSplitPane是否可以展开或收起(如同文件总管一般),设为true表示打开此功能.
splitPane2.setOneTouchExpandable(false);
splitPane2.setDividerSize(5);
contentPane.add(splitPane2);
f.setSize(250,200);
f.show();
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public static void main(String[] args){
new JSplitPane1();
}
}
++ Swing读书笔记JTabbedPane,JScroolPane,JScrolBa的使用
6-1-1:JTabbedPane的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JTabbedPane
JTabbedPane构造函数:
JTabbedPane():建立一个空的JTabbedPane对象。
JTabbedPane(int tabPlacement):建立一个空的JTabbedPane对象,并指定摆放位置,如TOP,BOTTOM,LEFT,RIGHT.
JTabbedPane的事件处理模式:
JTabbedPane以处理ChangeEvent事件为主。每当在JTabbedpane选换标签时,都会产生ChangeEvent事件。因此要处理选换标签所
对应的操作,必须实现ChangeListener这个interface.另外JTabbedPane上的每个标签都有索引值(index),一般若没有加以设置
,索引置从左到右依次是0,1,2.....,依此类推,因此下例中,Picture的索引值为0,Label 2的索引值为1。
一个标签都有所对应的操作。
例子: JTabbedPane2
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*由于ChangeEvent是属于Swing的事件,而不是AWT的事件,因此import Swing的事件类来处理
*ChangeEvent事件。
*/
import javax.swing.event.*;
public class JTabbedPane2 implements ActionListener,ChangeListener{
int index=0;
int newNumber=1;
JTabbedPane tabbedPane=null;
public JTabbedPane2(){
JFrame f=new JFrame("JTabbedPane2");
Container contentPane=f.getContentPane();
JLabel label1=new JLabel(new ImageIcon(".//icons//flower.jpg"));
JPanel panel1=new JPanel();
panel1.add(label1);
JLabel label2=new JLabel("Label 2",JLabel.CENTER);
label2.setBackground(Color.pink);
label2.setOpaque(true);
JPanel panel2=new JPanel();
panel2.add(label2);
JLabel label3=new JLabel("Label 3",JLabel.CENTER);
label3.setBackground(Color.yellow);
label3.setOpaque(true);
JPanel panel3=new JPanel();
panel3.add(label3);
tabbedPane=new JTabbedPane();
tabbedPane.setTabPlacement(JTabbedPane.TOP);//设置标签置放位置。
/*由于ChangeEvent是属于Swing的事件,而不是AWT的事件,因此import Swing的事件类来处理
*ChangeEvent事件。
*/
tabbedPane.addChangeListener(this);
tabbedPane.addTab("Picture",null,panel1,"图案");
tabbedPane.addTab("Label 2",panel2);
tabbedPane.addTab("Label 3",null,panel3,"label");
tabbedPane.setEnabledAt(2,false);//设Label 3标签为Disable状态
JButton b=new JButton("新增标签");
b.addActionListener(this);
contentPane.add(b,BorderLayout.SOUTH);
contentPane.add(tabbedPane,BorderLayout.CENTER);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void WindowClosing(WindowEvent e){
System.exit(0);
}
});
}
/*实现ChangeListener方法,目的在使若左边的标签有点选过,右边的标签才会显示Enable状态。getSelectedIndex()方法可返回
*目前点选标签的index值,getTabCount()方法可返回JTabbedPane上目前共有几个标签,而setEnabledAt()方法则是使某个标签
*的状态为Enable或Disable(true为Enable,false为Disable).
*/
public void stateChanged(ChangeEvent e){
if (index!=tabbedPane.getSelectedIndex()){
if(index
}
index=tabbedPane.getSelectedIndex();
}
/*实现ActionListener接口,当用户按下"新增标签"按钮时,就
*会在tabbedPane上新增一个Disable状态的标签。
*/
public void actionPerformed(ActionEvent e){
JPanel pane1=new JPanel();
JLabel label4=new JLabel("new label"+newNumber,JLabel.CENTER);
label4.setOpaque(true);
pane1.add(label4);
tabbedPane.addTab("new "+newNumber,pane1);
tabbedPane.setEnabledAt(newNumber+2,false);
newNumber++;
tabbedPane.validate();
}
public static void main(String[] args){
new JTabbedPane2();
}
}
6-1-1:JScrollPane的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JScrollPane
JScrollPane构造函数:
JScrollPane():建立一个空的JScrollPane对象。
JScrollPane(Component view):建立一个新的JScrollPane对象,当组件内容大于显示区域时会自动产生滚动轴。
JScrollPane(Component view,int vsbPolicy,int hsbPllicy):建立一新的JScrollPane对象,里面含有显示组件,并设置滚动轴
出现时机。
JScrollPane(int vsbPolicy,int hsbPolicy):建立一个新的JScrollPane对象,里面不含有显示组件,但设置滚动轴出现时机。
JScrollPane或利用下面这些参数来设置滚动轴的出现的时机,这些参数是定义在ScrollPaneConstants interface中,而
JScrollPane类实现此界面,因此也就能使用这些参数:
HORIZONTAL_SCROLLBAR_ALAWAYS:显示水平滚动轴。
HORIZONTAL_SCROLLBAR_AS_NEEDED:当组件内容水平区域大于显示区域时出现水平滚动轴。
HORIZONTAL_SCROLLBAR_NEVER:不显示水平滚动轴。
VERTICAL_SCROLLBAR_ALWAYS:显示垂直滚动轴。
VERTICAL_SCROLLBAR_AS_NEEDED:当组件内容垂直区域大于显示区域时出现垂直滚动轴。
VERTICAL_SCROLLBAR_NEVER:不显示垂直滚动轴。
范例:JScrollpane1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JScrollpane1 implements ActionListener{
JScrollPane scrollPane;
public JScrollpane1(){
JFrame f=new JFrame("JScrollpane1");
Container contentPane=f.getContentPane();
JLabel label1=new JLabel(new ImageIcon(".//icons//flower.jpg"));
JPanel panel1=new JPanel();
panel1.add(label1);
/*新增一个JScrollPane对象,并将panel1放入JScrollPane中,若pane1的组件大小在于窗口大小
*大于窗口大小则会自动显示出ScrollBar.
*/
scrollPane=new JScrollPane(panel1);
JPanel panel2=new JPanel(new GridLayout(3,1));
JButton b=new JButton("显示水平滚动轴");
b.addActionListener(this);
panel2.add(b);
b=new JButton("不要显示水平滚动轴");
b.addActionListener(this);
panel2.add(b);
b=new JButton("适时显示水平滚动轴");
b.addActionListener(this);
panel2.add(b);
contentPane.add(panel2,BorderLayout.WEST);
contentPane.add(scrollPane,BorderLayout.CENTER);
f.setSize(new Dimension(350,220));
f.show();
f.addWindowListener(new WindowAdapter(){
public void WindowClosing(WindowEvent e){
System.exit(0);
}
});
}
/*实现ActionListener界面,当用户按下"显示水平滚动轴"按钮时,则设置水平滚动轴参数为
*JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS,若用户按下"不要显示水平滚动轴""按钮时,则设置
*水平滚动轴参数为JScrollPane.HORIZONTAL_SCROLLBAR_NEVER,若用户按下"适时显示水平滚动轴"
*时,则设置水平滚动轴参数为HORIZONTAL_SCROLLBAR_AS_NEEDED.
*/
public void actionPerformed(ActionEvent e){
if(e.getActionCommand().equals("显示水平滚动轴"))
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
if(e.getActionCommand().equals("不要显示水平滚动轴"))
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
if(e.getActionCommand().equals("适时显示水平滚动轴"))
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.revalidate();//重新显示JScrollPane形状。
}
public static void main(String[] args){
new JScrollpane1();
}
}
接下来我们再看看JScrollPane还有哪些常用的功能。JScrollPane除了可让你滚动轴外,它还可以设置表头(Header)名称、边角
(Corner)图案与ScrollPane外框。我们修改上面的例子。使JScrollPane更具有变化:JScrollpane2.JAVA
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class JScrollpane2 implements ActionListener{
JScrollPane scrollPane;
public JScrollpane2(){
JFrame f=new JFrame("JScrollPaneDemo");
Container contentPane=f.getContentPane();
JLabel label1=new JLabel(new ImageIcon(".//icons//flower.jpg"));
JPanel panel1=new JPanel();
panel1.add(label1);
scrollPane=new JScrollPane();
/*设置窗口显示组件为panel1
*/
scrollPane.setViewportView(panel1);
/*设置水平与垂直表头
*/
scrollPane.setColumnHeaderView(new JLabel("水平表头"));
scrollPane.setRowHeaderView(new JLabel("垂直表头"));
/*设置scrollPane的边框凹陷立体边框。边框(Border)部份我们将在以后介绍。
*/
scrollPane.setViewportBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
/*设置scrollPane的边角图案,由于JScrollPane为矩形形状,因此就有4个位置来摆放边角(Corner)
*组件,这4个地方分别是左上、左下、右上、右下,对应的参数分别如下:
*JScrollPane.UPPER_LEFT_CORNER
*JScrollPane.LOWER_LEFT_CORNER
*JScrollPane.UPPER_RIGHT_CORNER
*JScrollPane.LOWER_RIGHT_CORNER
*/
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,new JLabel(new ImageIcon(".//icons//glass.jpg")));
scrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER,new JLabel(new ImageIcon(".//icons//glass.jpg")));
JPanel panel2=new JPanel(new GridLayout(3,1));
JButton b=new JButton("显示水平滚动轴");
b.addActionListener(this);
panel2.add(b);
b=new JButton("不要显示水平滚动轴");
b.addActionListener(this);
panel2.add(b);
b=new JButton("适时显示水平滚动轴");
b.addActionListener(this);
panel2.add(b);
contentPane.add(panel2,BorderLayout.WEST);
contentPane.add(scrollPane,BorderLayout.CENTER);
f.setSize(new Dimension(350,220));
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
public void actionPerformed(ActionEvent e){
if(e.getActionCommand().equals("显示水平滚动轴"))
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
if(e.getActionCommand().equals("不要显示水平滚动轴"))
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
if(e.getActionCommand().equals("适时显示水平滚动轴"))
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.revalidate();//重新显示JScrollPane形状。
}
public static void main(String[] args){
new JScrollpane2();
}
}
6-1-2:JScrollBar的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JScrollBar
在上一节我们看到JScrollPane利用ScrollBar的功能使它可以利用滚动轴滚动窗口,乍看之下我们并不会直接使用到
JScrollBar的方法,因为JScrollPane都帮我们处理得好好的,但如果我们想对滚动轴做更细的设置,例如在拖曳时一次滚动多少
区域等,就必须了解JScrollBar所提供的功能了。JScrollBar在处理窗口的滚动并不像JScrollPane那么容易,看起来也比
JScrollPane简单得许多,因此通常在实现时我们会取一些JScrollBar所提供的功能,来补足我们对JScrollPane的需要,而不会直
接拿JScrollBar来做滚动操作。下面是构造函数:
JScrollBar构造函数:
JScrollBar():建立一个垂直的滚动轴,默认参数值分别为:minimum=0,maximum=100,value=0,extent=10.
JScrollBar(int orientation):建立一个指定方向的滚动轴,默认参数值分别是:
minimum=0,maximum=100,value=0,extent=10.
JScrollBar(int orientation,int value,int extent,int min,int max):建立一个指定方向的滚动轴,并设置value、extent、
mimimum与maximum四个参数值。
JScrollBar四个参数的意义如下:
value:JScrollBar一开始的起始位置,若设为0表示在滚动轴的最顶端。
extent:延伸区,限制滚动轴可滚动的范围。例如,若minimum值设为0,maximan值设为100,而extent值设为20,则滚动轴可滚动的
区域大小为100-20-0=80个刻度,滚动的范围从0~80。若minimum值设为20,maximan值设为100,而extent值设为30,则滚动轴可滚
动的区域大小为100-30-20=50个刻度,滚动的范围从20~70。因此可知,延伸区设得越大,可滚动的范围就起小。
minimum:设置最小刻度值。
maximum:设置最大刻度值。
JScrollBar最常用到的就是AdjustmentEvent事件,当用户拖曳滚动轴时就会触发此事件。因此若要处理这类事件,就必须实现
AdjustmentEvent界面。此界面定义了一个adjustmentValueChanged()方法,实现此方法就能够得到滚动轴的相关信息。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JScrollBar1 implements AdjustmentListener{
JScrollBar scrollBar1;
JScrollBar scrollBar2;
JPanel panel1;
JLabel label2=new JLabel("刻度:",JLabel.CENTER);
public JScrollBar1(){
JFrame f=new JFrame("JScrollBarDemo");
Container contentPane=f.getContentPane();
JLabel label1=new JLabel(new ImageIcon(".//icons//flower.jpg"));
panel1=new JPanel();
panel1.add(label1);
/*产生一个垂直滚动轴,默认滚动轴位置在10刻度的地方,extent值设10,minimum值为0,
*maximan值为100,因此滚动轴一开始在刻度10的位置上,可滚动的区域大小为100-10-0=90
*刻度,滚动范围在0~90中。
*/
scrollBar1=new JScrollBar(JScrollBar.VERTICAL,10,10,0,100);
scrollBar1.setUnitIncrement(1);//设置拖曳滚动轴时,滚动轴刻度一次的变化量。
scrollBar1.setBlockIncrement(10);//设置当鼠标在滚动轴列上按一下是,滚动轴一次所跳的区块大小
scrollBar1.addAdjustmentListener(this);
scrollBar2=new JScrollBar();//建立一个空的JScrollBar
scrollBar2.setOrientation(JScrollBar.HORIZONTAL);//设置滚动轴方向为水平方向
scrollBar2.setValue(0);//设置默认滚动轴位置在0刻度的地方。
scrollBar2.setVisibleAmount(20);//extent值设为20
scrollBar2.setMinimum(10);//minmum值设为10
scrollBar2.setMaximum(60);//maximan值设为60,因为minmum值设为10,可滚动的区域大小为60-20-10=30
//个刻度,滚动范围在10~40中。
scrollBar2.setBlockIncrement(5);//当鼠标在滚动轴列上按一下时,滚动轴一次所跳的区块大小为5个刻度
scrollBar2.addAdjustmentListener(this);
contentPane.add(panel1,BorderLayout.CENTER);
contentPane.add(scrollBar1,BorderLayout.EAST);
contentPane.add(scrollBar2,BorderLayout.SOUTH);
contentPane.add(label2,BorderLayout.NORTH);
f.setSize(new Dimension(200,200));
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
//实现adjustmentValueChanged方法。当用户改变转轴位置时,会将目前的滚动轴刻度写在labe2上。
public void adjustmentValueChanged(AdjustmentEvent e){
if ((JScrollBar)e.getSource()==scrollBar1)
label2.setText("垂直刻度"+e.getValue());//e.getValue()所得的值与scrollBar1.getValue()所得的值一样。
if ((JScrollBar)e.getSource()==scrollBar2)
label2.setText("水平刻度"+e.getValue());
}
public static void main(String[] args){
new JScrollBar1();
}
}
++ Swing读书笔记标签与按钮的使用与介绍
Border,Icon,JLabel,JButton,JToggleButton
6-1:Border的使用
Border类是应用在描绘组件的边界,Border本身是一个interface,里面定义了3个方法,为getBorderInsets()、isBorderOpaque()
、与isBorderOpaque()、与paintBorder().若您想使用Border类来绘制你的窗口边界,您必须先实现(implements)这3个方法,可说
是有点麻烦。还好,java本身提供了另一个类,它已经实现了Border类所有的方法,且提供许多不同的边界样式供用户使用,用户
只需要选择到底要用哪个样式即可,不需要理会如何去画出这个边界,因为这个类已经都帮您实现好了,这个类就是
BorderFactory,下面是borderFactory的类层次结构图。
BorderFactory的类层次结构图:
java.lang.Object
-----------javax.swing.BorderFactory
SimpleBorder.java
import javax.swing.border.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleBorder{
public static void main(String[] args){
JFrame f=new JFrame("SimpleBorder");
Container content=f.getContentPane();
JButton b=new JButton();
b.setBorder(BorderFactory.createLineBorder(Color.blue,10);//createLineBorder方法指定边界的颜色与宽度.
content.add(b);
f.setSize(200,150);
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
BorderFactory提供了以下方法:
-------------------------------------------------------
static Border creatBevelBorder(int type)建立一个立体的边界,并由参数type指定为凹陷或突起,type可为
BevelBorder.LOWERED表示凹陷,或是BevelBorder.RAISED表示突起。
static Border createBevelBorder(int type,Color highlight,Color shadow)建立一个立体的边界,并指定突边与阴
影的颜色。
static Border createBevelBorder(int type,Color highlightOuter,Color highlightInner,Color shadowOuter
,Color shadowInner)建立一个立体的边界,并指定内外部的突边与阴影的颜色。
static CompoundBorder createCompoundBorder()建立一个复合边界。
static CompoundBorder createCompoundBorder(Border outsideBorder,Border insideBorder)建立一个复合边界,并指定它
的内外边界。
static Border createEmptyBorder()建立一个空的边界。
static Border createEmptyBorder(int top,int left,int bottom,int right)建立一个空的边界,并指定上下左右
的宽度,在这些宽度中不能作绘图的效果。
static Border createEtchedBorder()建立一个四周有凹痕的边界。
static Border createEtchedBorder(Color highlight,Color shadow)建立一个四周有凹痕的边界,并指定突边与阴影
的颜色。
static Border createLineBorder(Color color)
建立一个线务边界,并指定线条的颜色。
static Border createLineBorder(Color color,int thicness)
建立一个线务边界,并指定线条的颜色与宽度。
static Border createLoweredBevelBorder()建立一个具有凹陷效果的边界,意义与
createBevelBorder(BevelBorder.LOWERED)相同。
static MatteBorder createMatteBorder(int top,int left,int bottom,int right,Color color)建立一个垫子边界,这跟
createEmptyBorder有点像,但可以指定边界颜色。
static MatteBorder createMatteBorder(int top,int left,int bottom,int right,Icon tileIcom)建立一个垫子边界,并
指定边界的花纹。
static Border createRaisedBevelBorder()建立一个具有突起效果的边界,意义与createBevelBorder(BevelBorder.
RAISED)相同。
static TitledBorder createTitledBorder(Border border)建立一个标题边界,但没有标题名称。
static TitledBorder createTitledBorder(Border border,String title)建立一个标题边界,并指定标题名称,标题默认位
置是TitledBorder.DEFAULT_JUSTIFICATION与TitledBorder.DEFAULT_POSITION,也就是左上方。
static TitledBorder createTitledBorder(Border border,String title,int titleJustification,int titlePosition)
建立一个标题边界,并指定标题名称与标题位置,参数titleJustification可为:
TitledBorder.LEFT
TitledBorder.CENTER
TitledBorder.RIGHT
TitledBorder.DEFAULT_JUSTIFICATION(leading)
参数titlePosition可为:
TitedBorder.ABOVE_TOP
TitledBorder.TOP(sittin on the top line)
TitledBorder.BELOW_TOP
TitledBorder.ABOVE_BOTTOM
TitledBorder.BOTTOM(sitting on the bottom line)
TitledBorder.BELOW_BOTTOM
TitledBorder.DEFAULT_POSITION(top)
static TitledBorder createTitledBorder(Border border,String title,int titleJustification,int titlePosition,
Font titleFont)建立一个标题边界,并指定标题名称,标题位置与字体。
static TitledBorder createTitledBorder(Border border,String title,int titleJustification,int titlePosition,
Font titleFont,Color titleColor)建立一个标题边界,并指定标题名称,标题位置、字体与标题颜
色。
static TitledBorder createTitledBorder(String title)建立一个标题边界,并指定标题名称,其他为默认值。
BorderDemo.java
import javax.swing.border.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class BorderDemo{
public static void main(String[] args){
JFrame f=new JFrame("BorderDemo");
Container content=f.getContentPane();
JLabel label=new JLabel();
//label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));//凹陷效果
//label.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));//突起效果
//凹陷效果,并设置突出与阴影的颜色
//label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED,Color.red,Color.blue));
//凹陷效果,并设置内外部突出与阴影的颜色
//label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED,Color.red,Color.blue,Color.yellow,Color.green));
/*EmptyBorder:建立一个空的边界,可指定边界的宽度,这在区隔组件之间的距离时可能用到。
*EtchedBorder:建立一个四周有凹痕的边界,也可以指定突边与阴影的颜色.
*/
//label.setBorder(BorderFactory.createEtchedBorder());
//设置四周有凹痕的边界,并指定内外部的突边与阴影的颜色
//label.setBorder(BorderFactory.createEtchedBorder(Color.red,Color.blue));
//LineBorder:建立一个线条边界,并可以指定线条的颜色与宽度。
//label.setBorder(BorderFactory.createLineBorder(Color.blue,5));
//MatteBorder:建立一个Matte边界,这个方法与createEmptyBorder()有点像,但可以指定边界颜色
//或利用Icon产生边界花纹.
//label.setBorder(BorderFactory.createMatteBorder(5,5,5,5,Color.green));
//label.setBorder(BorderFactory.createMatteBorder(25,25,25,25,new ImageIcon(".//icons//star.gif")));
/*CompoundBorder: 建立一个复合边界,并可以指定它的内外边界,例如我们可以指定它的外边界为LineBorder,
*它的内边界为MatteBorder。
*/
//label.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.blue,5),
// BorderFactory.createMatteBorder(20,20,18,18,new ImageIcon(".//icons//star.gif"))));
//TitleBorder:建立一个标题边界,我们可以指定边界的标题名称、标题位置、字体与标题颜色。
//label.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.blue,5),"Line Border"
// ,TitledBorder.LEFT,TitledBorder.TOP));
label.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.blue,5),"Line Border"
,TitledBorder.LEFT,TitledBorder.ABOVE_TOP,new Font("SansSerif",Font.ITA_LIC,14),Color.red));
content.add(label);
f.setSize(200,150);
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
6-2:Icon的使用:
ImageIcon的类层次结构图:
java.lang.Object
--javax.swing.ImageIcon
ImageIcon的结构函数:
ImageIcon():建立一个ImageIcon组件。
ImageIcon(byte[] imageData):建立一个ImageIcon组件,Image的数据放在byte array的数据可从GIF获释JPEG的文件读取面来
。
ImageIcon(byte[] imageData,String description)建立一个ImageIcon组件,Image的数据放在byte array中,而byte array
的数据可从GIF获释JPEG的文件读取而来,并多了一个此Icon的描述文字。
ImageIcon(Image image)利用Image组件,建立一个ImageIcon组件。
ImageIcon(Image image,String description)利用Image组件,建立一个ImageIcon组件,附加此Icon的描述文字。
ImageIcon(Staring filename)利用图文件建立一个ImageIcon组件。
ImageIcon(Staring filename,String description)利用图文件建立一个ImageIcon组件,附加此Icon的描述文字。
ImageIcon(URL location)利用网址建立一个ImageIcon组件。
ImageIcon(URL location)利用网址建立一个ImageIcon组件,附加此Icon的描述文字。
ImageIcon.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageIconDemo{
public static void main(String[] args){
JFrame f=new JFrame("ImageIconDemo");
Container contentPane=f.getContentPane();
Icon icon=new ImageIcon(".//icons//visa.gif");
JLabel label=new JLabel(icon,JLabel.CENTER);
contentPane.add(label);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
若您想利用读文件的功能,先将图文件转成byte array,再制作Icon组件,你可以用下面的程序帮你完成:
ImageIconDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
public class ImageIconDemo{
public static void main(String[] args){
byte[] image=null;
JFrame f=new JFrame("ImageIconDemo");
Container contentPane=f.getContentPane();
/*在打开文件读文件的过程中可能会发生IOException,因此在下面的程序中用
*try与catch将此区段包起来。
*/
try{
File file=new File(".//icons//visa.gif");//利用文件visa.gif建立一个File组件。
int size=(int)file.length();//并求出此文件的长度。
FileInputStream in=new FileInputStream(file);//将文件组件放入FileInputStream中。
image=new byte[size];
in.read(image);//将数据文件读进byte array中。
}catch(IOException e){
System.err.println("File open falure:"+e.getMessage());
}
Icon icon=new ImageIcon(image);
JLabel label=new JLabel(icon,JLabel.CENTER);
contentPane.add(label);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
Icon是一个Interface,里面包含3种空的抽象文法,分别是getIconHeight()、getIconWidth()与paintIcon();若你想使用Icon类
来制作Icon,你必须实现(implements)这3个方法,我们直接来看下面这个例子,你就能清楚如何实现Icon界面建立Icon组件了。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class IconDemo implements Icon{
int height=50;
int width=70;
public int getIconHeight(){
return height;
}
public int getIconWidth(){
return width;
}
public void paintIcon(Component c,Graphics g,int x,int y){
g.drawRect(x,y,width,height);
g.fillRect(x,y,width,height);
g.setColor(Color.blue);
}
public static void main(String[] args){
JFrame f=new JFrame("IconDemo");
Container contentPane=f.getContentPane();
Icon icon=new IconDemo();
JLabel label=new JLabel(icon,JLabel.CENTER);
contentPane.add(label);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
6-3:JLabel的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JLabel
在以前的许多范例,我们已经使用过JLabel这个组件,相信大家对此组件应该不会感到陌生,接下来我们来深入了解JLabel
的各种我特性。
一般而言:我们最常在JLabel上放置文字或图形,也因此我们常常需要调整JLabel上文字或图形。在JLabel实现了
SwingConstants这个interface,而这个interface主要是定义一些组件排列方式的参数:
TOP
LEFT
RIGHT
BOTTOM
CENTER
NORTH
EAST
WEST
SOUTH
NORTH_EAST
SOUTH_EAST
SOUTH_WEST
NORTH_WEST
HORIZONTAL
VERTICAL
LEADING 置于前端
TRAILING 置于后端。
在swing中,有相当多的类均实现了SwingConstants这个interface,如AbstractButton、JCheckBoxMenuItem、JLabel、
JProgressBar、JSeparator、JSlider、JTextField、JTabbedPane、JToolbar等等,因此当你使用到这些组件时,你就可以在适当
的时候,利用SwingConstants的参数来定义组件的位置了。
JLabel共有6种构造函数,如下:
JLabel构造函数:
JLabel():建立一个空白的JLabel组件。
JLabel(Icon image):建立一个含有Icon的JLabel组件,Icon的默认排列方式是CENTER.
JLabel(Icon image,int horizontalAlignment):建立一个含有Icon的JLabel组件,并指定其排列方式。
JLabel(String text):建立一个含有文字的JLabel组件,文字的默认排列方式是LEFT.
JLabel(String text,int horizontalAlignment):建立一个含有文字的JLabel组件,并指定其排列方式。
JLabel(String text,Icon icon,int horizontalAlignment):建立一个含有文字与Icon的JLabel组件,并指定其排列方式,
文字与Icon的间距,默认值是4个pixels.
在JLabel中,有几个方法可能是常用到的,例如setHorizontalAlignment(int alignment)与setVerticalAlignment(int
alignment),分别是设置标签内组件(文字或Icon)的水平或垂直位置,而setHorizontalTextPosition(int textPosition)与
setVerticalTextPosition(int textPosition)可设置文字相对于Icon的相对位置,另外,setIconTextGap(int iconTextGap)可设
置标签内文字与Icon间的间距、setText(String test)与setIcon(Icon icon)可分别设置标签内的文字与Icon。
JLabelDemo1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JLabelDemo1{
public static void main(String[] args){
JFrame f=new JFrame("JLabelDemo1");
Container contentPane=f.getContentPane();
JLabel label=new JLabel();
label.setText("Hello");
label.setHorizontalAlignment(JLabel.RIGHT);
label.setVerticalAlignment(JLabel.TOP);
contentPane.add(label);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
我们再来看一个有Icon的例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JLabelDemo2{
public static void main(String[] args){
JFrame f=new JFrame("JLabelDemo1");
Container contentPane=f.getContentPane();
Icon icon=new ImageIcon(".//icons//hello.jpg");
JLabel label=new JLabel("Hello",icon,JLabel.CENTER);//产生一个具有文字与Icon的JLabel组件,
//并将此文字与Icon置于JLabel的中间。
label.setHorizontalTextPosition(JLabel.CENTER);//将文字置于Icon的中间,若没有设置此项,默认
//值为文字在Icon的右边。
label.setVerticalTextPosition(JLabel.TOP);//将文字置于Icon的上面,若没有设置此项 ,默认值为中间排列
/*若你在此再加入一行label.setIconTextGap(10);将会加大文字"Hello"与Icon间的间距。
*/
contentPane.add(label);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
6-4:JButton的使用:
JButton的类层次结构图:
java.lang.Object
--java.awt.Component
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JButton
JButton是继承AbstractButton类而来,而AbstractButton本身是一个抽象类,里面定义了许多组件设置的方法与组件事件驱动
方法(Event handle),如addActionListener()、setText等,详情请看相关手册,所提供的方法不下50种,可说是非常重要的一个
类。事实上,AbstractButton类不公被JButton所继承,它同时还被JMenuItem、JToggleButton、JCheckBox、JRadioButton等类所
继承,提供给这些类强大且方便的功能,而且在使用上更能掌握这些组件的特性。我们此节先来了解JButton与JToggleButton的特
性,其余类在后面各节介绍。
JButton共有4个构造函数:
JButton():建立一个按钮。
JButton(Icon icon):建立一个有图像的按钮。
JButton(String icon):建立一个有文字的按钮。
JButton(String text,Icon icon):建立一个有图像与文字的按钮。
由JButton的构造函数可以看出:JButton与JLabel的使用相当类似,只是JButton少了排列方式的参数罢了。要是我们想设置
JButton内文字或图像的水平排列方式,我们可以利用AbstractButton抽象类所提供的setHorizontalAlignment()方法来达成。
JButton在使用上与JLabel相当类似,只是类的设计方式有所不同,JLabel类自行提供组件排列方式的方法,而JButton是继承
AbstractButton抽象类的方法来排列按钮内的内容。为什么JButton不自行提供排列方式等方法呢?主要是因为JButton与JMenuItem
、JToggleButton、JCheckBox、JRadioButton组件有许多共同的物性,例如它们都会有“按”的操作、都可以插入Icon与文字、
都可设置快捷键、都可呈现Enable或Disable状态等等,因此将AbstractButton类独立出来,实现这些共通的方法,再由其他类来继
承,将可增加程序结构对象化与模块化的特性,也让程序更容易维护.
JButton类所提供的方法非常少,大部份都会用到AbstractButton抽象类所提供的方法。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JButtonDemo1{
public static void main(String[] args){
JFrame f=new JFrame("JButtonDemo1");
Container contentPane=f.getContentPane();
/*你也可以用下面这个方式代替:
*JButton b=new JButton();
*b.setIcon(new ImageIcon(".//icons//hand.jpg"));
*b.setText("按我");
*/
JButton b=new JButton("按我",new ImageIcon(".//icons//hand.jpg"));
/*如果没有设置文字的位置,系统默认值会将文字置于图形的右边中间位置。
*/
b.setHorizontalTextPosition(JButton.CENTER);
b.setVerticalTextPosition(JButton.BOTTOM);
contentPane.add(b);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
6-4-1:在JButton上使用Rollover图像变化:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class RolloverDemo{
public static void main(String[] args){
JFrame f=new JFrame("RolloverDemo");
Container contentPane=f.getContentPane();
Icon rollover=new ImageIcon(".//icons//address1.jpg");
Icon general=new ImageIcon(".//icons//address2.jpg");
Icon press=new ImageIcon(".//icons//address3.jpg");
JButton b=new JButton();
b.setRolloverEnabled(true);//将Rollver功能打开。
b.setIcon(general);
b.setRolloverIcon(rollover);
b.setPressedIcon(press);
contentPane.add(b);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
6-4-2:在JButton上设置快捷键:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MnemonicButton implements ActionListener{
public MnemonicButton(){
JFrame f=new JFrame("MnemonicButton");
Container contentPane=f.getContentPane();
JButton b=new JButton("[o]打开新窗口");
b.setMnemonic('o');
/*将b加入事件处理模式,当我们按下按钮时,会产生一个事件(ActionEvent),此事件会被ActionListener
*所接收。而ActionListener是一个interface,里面只有actionPerformed()一个方法,因此我们必须实现
*actionPerformed()方法,处理我们所要的结果。
*/
b.addActionListener(this);
contentPane.add(b);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e){
JFrame newf=new JFrame("新窗口");
JLabel label=new JLabel("这是新窗口");
label.setHorizontalAlignment(JLabel.CENTER);
newf.getContentPane().add(label);
newf.setSize(100,100);
newf.show();
}
public static void main(String[] args){
new MnemonicButton();
}
}
6-4-3:设置默认按钮:
在java中要设置默认按钮可以使用JRootPane类所提供的setDefaultButton()方法,下面的例子我们将事件处理模式换成另
一种写法,也就是前面所提到的Inner Class匿名类写法,因此在类DefaultButton的右边就不用再写入implements ActionListener
了。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DefaultButton{
public DefaultButton(){
JFrame f=new JFrame("DefaultButton");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
JButton b1=new JButton("Open Text window");
JButton b2=new JButton("Open Image window");
b1.setMnemonic('T');
b2.setMnemonic('I');
f.getRootPane().setDefaultButton(b1);
b1.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
JFrame newf=new JFrame("新窗口");
JLabel label=new JLabel("这是文字窗口");
label.setHorizontalAlignment(JLabel.CENTER);
newf.getContentPane().add(label);
newf.setSize(200,200);
newf.show();
}
}
);
b2.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
JFrame newf=new JFrame("新窗口");
JLabel label=new JLabel(new ImageIcon(".//icons//address1.jpg"));
label.setHorizontalAlignment(JLabel.CENTER);
newf.getContentPane().add(label);
newf.setSize(200,200);
newf.show();
}
}
);
contentPane.add(b1);
contentPane.add(b2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new DefaultButton();
}
}
6-5:JToggleButton的使用.
JToggleButton类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JToggleButton
JToggleButton跟一般JButton其实很像,主要的差别在于一般的按钮按下去会自动弹回来,而JToggleButton按钮按下去会陷下
去,不会弹回来,除非你再按一次。由上面的类层次结构图可知JToggleButton也继承AbstractButton抽象类而来,因此
JToggleButton组件可以使用所有AbstractButton类所提供的方法。下面是JToggleButton所提供的构造函数:
JToggleButton构造函数:
JToggleButton():建立一个新的JToggleButton。
JToggleButton(Icon icon):建立一个有图像但没有文字的JToggleButton。
JToggleButton(Icon icon,boolean selected):建立一个有图像但没有文字的JToggleButton,且设置其初始状态(有无选取)。
JToggleButton(String text):建立一个有文字的JToggleButton。
JToggleButton(String text,boolean selected):建立一个有文字的JToggleButton,初始状态有无被选取。
JToggleButton(String text,Icon icon):建立一个有文字且有图像的JToggleButton,初始状态为有无被选取。
JToggleButton(String text,Icon icon,boolean selected):建立一个有文字且有图像的JToggleButton,且设置其初始状态(
有无选取).
例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToggleButton{
public static void main(String[] args){
JFrame f=new JFrame("ToggleButton");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(3,1));
JToggleButton b1=new JToggleButton("Button 1");
JToggleButton b2=new JToggleButton("Button 2");
JToggleButton b3=new JToggleButton("Button 3");
contentPane.add(b1);
contentPane.add(b2);
contentPane.add(b3);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
在5-5-1节中,我们曾介绍过JButton上使用Rollover的方法,且还有3种方法我们还没有使用过,那就是setDisableSelected
Icon()、setSelectedIcon()与setRolloverSelectedIcon().我们来介绍一下setSelectedIcon()与setRolloverSelectedIcon()方法
,而setDisableSelectedIcon方法就作为习题。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToggleRovllover{
public static void main(String[] args){
JFrame f=new JFrame("ToggleRollover");
Container contentPane=f.getContentPane();
JToggleButton b=new JToggleButton();
b.setRolloverEnabled(true);
b.setIcon(new ImageIcon(".//icons//rollover1.jpg"));
b.setRolloverSelectedIcon(new ImageIcon(".//icons//rollover2.jpg"));
b.setSelectedIcon(new ImageIcon(".//icons//rollover3.jpg"));
contentPane.add(b);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
}
++ Swing读书笔记[复选框、选项按钮、列表方框、下拉式列表的使用与介绍]
7-1:使用JCheckBox组件:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JToggleButton
--javax.swing.JCheckBox
JCheckBox与JRadioButton为JToggleButton的子类,因此它们可以使用AbstractButton抽象类里面许多好用的方法,如addItemLi
stener()、setText()、isSelected()等等。
构造函数:
JCheckBox():建立一个新的JChcekBox.
JCheckBox(Icon icon):建立一个有图像但没有文字的JCheckBox.
JCheckBox(Icon icon,boolean selected):建立一个有图像但没有文字的JCheckBox,且设置其初始状态(有无被选取)。
JCheckBox(String text):建立一个有文字的JCheckBox.
JCheckBox(String text,boolean selected):建立一个有文字的JCheckBox,且设置其初始状态(有无被选取)。
JCheckBox(String text,Icon icon):建立一个有文字且有图像的JCheckBox,初始状态为无被选取。
JCheckBox(String text,Icon icon,boolean selected):建立一个有文字且有图像的JCheckBox,且设置其初始状态(有无被选取
)。
7-1-1:构造JCheckBox组件:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JCheckBox1{
public static void main(String[] args){
JFrame f=new JFrame("JCheckBox1");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
JPanel p1=new JPanel();
p1.setLayout(new GridLayout(1,3));
p1.setBorder(BorderFactory.createTitledBorder("你最喜欢哪一家快餐店呢?"));
JCheckBox c1=new JCheckBox("麦当劳");
JCheckBox c2=new JCheckBox("肯德基");
JCheckBox c3=new JCheckBox("21世纪");
p1.add(c1);
p1.add(c2);
p1.add(c3);
JPanel p2=new JPanel();
p2.setLayout(new GridLayout(2,1));
p2.setBorder(BorderFactory.createTitledBorder("以下为JCheckBox的图形示范:"));
JCheckBox c4=new JCheckBox("图形1",new ImageIcon(".//icons//x.jpg"));
JCheckBox c5=new JCheckBox("图形2",new ImageIcon(".//icons//x.jpg"));
p2.add(c4);
p2.add(c5);
contentPane.add(p1);
contentPane.add(p2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
7-1-2:JCheckBox事件处理:
你可以在上面的选项中勾选你喜欢吃的快餐店,在勾选的过程中,你可以发现它是可以复选的。但在图形选项中,我们并无法
清楚用户是否选择此项目,因为选或不选图形都一样。为解决这个问题,我们要使用到事件处理方法。当JCheckBox中的选项被选取
或取消时,它会触发ItemEvent的事件,ItemEvent这个类共提供了4种方法可以使用,分别是getItem()、getItemSelectable()、
getStateChange()、paramString()。getItem()与paramString()方法会返回一些这个JCheckBox的状态值。一般我们较少用到这两
个方法。
getItemSelectable()相当于getSource()方法,一样都是返回触发事件的组件,用来判断是那个组件产生事件。在上一章中我
们曾经说过,getSource()方法是EventObject类所提供,而所有事件类都会继承这个类,因此所有的事件我们均能用getSource()
方法来判断到底是哪个组件触发了事件。
最后getStateChange()方法会返回此组件到底有没有被选取。这个方法会返回一个整数值。而我们可以用ItemEvent所提供的类
变量;若被选取则返回SELECTED,若没有被选取则返回DESELECTED.
下面这个范例我们即利用ItemListener来选取图形产生变化,ItemListener这个inteface只有定义一个方法,那就是
itemStateChange(ItemEvent e),因此我们只需实作这个方法.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JCheckBox2 implements ItemListener
{
JFrame f = null;
JCheckBox c4 = null;
JCheckBox c5 = null;
JCheckBox2(){
f = new JFrame("JCheckBox");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1,3));
p1.setBorder(BorderFactory.createTitledBorder("您最喜欢哪一家速食店呢?"));
JCheckBox c1 = new JCheckBox("麦当劳");
JCheckBox c2 = new JCheckBox("肯德鸡");
JCheckBox c3 = new JCheckBox("21世纪");
p1.add(c1);
p1.add(c2);
p1.add(c3);
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(2,1));
p2.setBorder(BorderFactory.createTitledBorder("您喜欢哪种程序语言,喜欢的请打勾:"));
c4 = new JCheckBox("JAVA",new ImageIcon(".//icons//x.jpg"));
c5 = new JCheckBox("C++",new ImageIcon(".//icons//x.jpg"));
c4.addItemListener(this);
c5.addItemListener(this);
p2.add(c4);
p2.add(c5);
contentPane.add(p1);
contentPane.add(p2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void itemStateChanged(ItemEvent e)
{
if (e.getStateChange() == e.SELECTED)
{
if(e.getSource() == c4)
c4.setIcon(new ImageIcon(".//icons//r.jpg"));
if(e.getSource() == c5)
c5.setIcon(new ImageIcon(".//icons//r.jpg"));
}
else
{
if(e.getSource() == c4)
c4.setIcon(new ImageIcon(".//icons//x.jpg"));
if(e.getSource() == c5)
c5.setIcon(new ImageIcon(".//icons//x.jpg"));
}
}
public static void main(String args[])
{
new JCheckBox2();
}
}
7-2:JRadioButton的使用:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.Abstractbutton
--javax.swing.JToggleButton
--javax.swing.JRadioButton
JRadioButtonBN J JToggleButton的一个了类,因此它也可以使用AbstractButton抽象类里的方法。如同前面所述,JChexkBox
主要用在多重选择时机,而JRadioButton则是运用在单一选择时机。
JRadioButton构造函数:
JRadioButton():建立一个新的JRadioButton.
JRadioButton(Icon icon):建立一个有图像但没有文字的JRadioButton.
JRadioButton(Icon icon,boolean selected):建立一个有图像但没有文字的JRadioButton,且设置其初始状态(有无被选取).
JRadioButton(String text):建立一个有文字的JRadioButton.
JRadioButton(String text,boolean selected):建立一个有文字的JRadioButton,且设置其初始状态(有无被选取)。
JRadioButton(String text,Icon icon):建立一个有文字且有图像的JRadioButton,初始状态为无被选取。
JRadioButton(String text,Icon icon,boolean selected):建立一个有文字且有图像的JRadioButton,且设置其初始状态(有无
被选取。
7-2-1:构造JRadioButton组件与事件处理:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JRadioButton1 implements ItemListener
{
JFrame f = null;
JRadioButton r4 = null;
JRadioButton r5 = null;
JRadioButton1(){
f = new JFrame("JRadioButton");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1,3));
p1.setBorder(BorderFactory.createTitledBorder("您最喜欢哪一家速食店呢?"));
JRadioButton r1 = new JRadioButton("麦当劳");
JRadioButton r2 = new JRadioButton("肯德鸡");
JRadioButton r3 = new JRadioButton("21世纪");
p1.add(r1);
p1.add(r2);
p1.add(r3);
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(2,1));
p2.setBorder(BorderFactory.createTitledBorder("您喜欢哪种程序语言? 喜欢的请打勾"));
r4 = new JRadioButton("JAVA",new ImageIcon(".//icons//x.jpg"));
r5 = new JRadioButton("C++",new ImageIcon(".//icons//x.jpg"));
r4.addItemListener(this);
r5.addItemListener(this);
p2.add(r4);
p2.add(r5);
contentPane.add(p1);
contentPane.add(p2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void itemStateChanged(ItemEvent e)
{
if (e.getStateChange() == e.SELECTED)
{
if(e.getSource() == r4)
r4.setIcon(new ImageIcon(".//icons//r.jpg"));
if(e.getSource() == r5)
r5.setIcon(new ImageIcon(".//icons//r.jpg"));
}
else
{
if(e.getSource() == r4)
r4.setIcon(new ImageIcon(".//icons//x.jpg"));
if(e.getSource() == r5)
r5.setIcon(new ImageIcon(".//icons//x.jpg"));
}
}
public static void main(String args[])
{
new JRadioButton1();
}
}
要将RadioButton改成单选,我们必须用到ButtonGroup这个类。这个类位于javax.swing这个package下面,ButtonGroup类的主
要功能是:同一时间内只会有一个组件的状态为"on",其他皆为"off",也就是同一时间只有一个组件会被选取。而ButtonGroup类可
被AbstractButton下面的子类所使用,最常被使用的就是JRadioButton、JradioButtonMenu、Item与JToggleButton这些组件。
下面是ButtonGroup的类层次结构图:
ButtonGroup的类层次结构图:
java.lang.Object
--javax.swing.ButtonGroup
我们更改上例,使RadioButton变成单选吧!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JRadioButton2 implements ItemListener{
JFrame f=null;
JRadioButton r4=null;
JRadioButton r5=null;
JRadioButton2(){
f=new JFrame("JRadioButton2");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
JPanel p1=new JPanel();
p1.setLayout(new GridLayout(1,3));
p1.setBorder(BorderFactory.createTitledBorder("你最喜欢哪一家快餐店呢?"));
JRadioButton r1=new JRadioButton("麦当劳");
JRadioButton r2=new JRadioButton("肯德基");
JRadioButton r3=new JRadioButton("21世纪");
p1.add(r1);
p1.add(r2);
p1.add(r3);
/*
将3个RadioButton对象放进ButtonGroup中,表示此3个RadioButton同一时间只有一个RadioButton的状态可以为"on";
*/
ButtonGroup bgroup1=new ButtonGroup();
bgroup1.add(r1);
bgroup1.add(r2);
bgroup1.add(r3);
JPanel p2=new JPanel();
p2.setLayout(new GridLayout(2,1));
p2.setBorder(BorderFactory.createTitledBorder("你最喜欢哪种程序语言,喜欢的请打勾:"));
r4=new JRadioButton("java",new ImageIcon(".//icons//x.jpg"));
r5=new JRadioButton("c++",new ImageIcon(".//icons//x.jpg"));
r4.addItemListener(this);
r5.addItemListener(this);
p2.add(r4);
p2.add(r5);
ButtonGroup bgroup2=new ButtonGroup();
bgroup2.add(r4);
bgroup2.add(r5);
contentPane.add(p1);
contentPane.add(p2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public void itemStateChanged(ItemEvent e){
if (e.getStateChange()==e.SELECTED){
if (e.getSource()==r4)
r4.setIcon(new ImageIcon(".//icons//r.jpg"));
if (e.getSource()==r5)
r5.setIcon(new ImageIcon(".//icons//r.jpg"));
}else{
if (e.getSource()==r4)
r4.setIcon(new ImageIcon(".//icons//x.jpg"));
if (e.getSource()==r5)
r5.setIcon(new ImageIcon(".//icons//x.jpg"));
}
}
public static void main(String[] args){
new JRadioButton2();
}
}
7-3:JList的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JList
JList与JCheckBox有点相似,都可以让你选择一到多个选项,较不同的是,JList的选项方式是整列选取。我们先来看看JList
所提供的构造函数,方便迅速建立JList对象,如下所示:
JList构造函数:
JList():建立一个新的JList组件。
JList(ListModel dataModel):利用ListModel建立一个新的JList组件.
JList(Object[] listData):利用Array对象建立一个新的JList组件。
JList(Vector listData):利用Vector对象建立一个新的JList组件。
7-3-1:建立一般的JList:
一般我们若不需要在JList中加入Icon图像,通常会用第3或第4个构造函数建立JList对象。而这两个最大的不同在于使用Array对
象建立JList组件就无法改变项目的数量。对于项目数量经常改变的环境来说,以Vector对象来建立JList组件当然比较适合。例如
一个卖手机的店家,可能动不动就会有新手机上市,此时若用Array对象就不是很适当了!
我们来看个范例看怎么构造一个简单的JList吧!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
public class JList1
{
public static void main(String args[])
{
JFrame f = new JFrame("JList");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
String[] s = {"美国","日本","大陆","英国","法国"};
Vector v = new Vector();
v.addElement("Nokia 8850");
v.addElement("Nokia 8250");
v.addElement("Motorola V8088");
v.addElement("Motorola V3688x");
v.addElement("Panasonic GD92");
v.addElement("其他");
JList list1 = new JList(s);
list1.setBorder(BorderFactory.createTitledBorder("您最喜欢到哪个国家玩呢?"));
JList list2 = new JList(v);
list2.setBorder(BorderFactory.createTitledBorder("您最喜欢哪一种手机?"));
contentPane.add(new JScrollPane(list1));
contentPane.add(new JScrollPane(list2));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
在这个范例中,当窗口变小时,JList并不会有滚动(ScrollBar)的效果,所以可能无法看到比较下面的选项。若我们要有滚动的
效果,必须将JList放入滚动面版中(JScrollPane),如我们在程序改为:
contentPane.add(new JScrollPane(list1));
contentPane.add(new JScrollPane(list2));
如此就有滚动的效果了,若我们要有多个选项呢?在JList中有3种选择模式(Selection Mode)可供我们使用,分别是单一选择、
连续区间选择、与多重选择。我们可以在ListSelectionModel这个interface中找到这3个常数值,如下:
static int SINGLE_SELECTION:一次只能选择一个项目。
static int SINGLE_INTERVAL_SELECTION:按住[shift]键,可以对某一边续的项目作选取。
static int MULTIPLE_INTERVAL_SELECTION:没有任何限制。可作单一选择,连续区间选择,或对不连续的项目作多重选择(按
住[Ctrl]键)。多得选择是java对JList的默认值,因此在上例中你可以在JList中作这3种模式的选择方式。
设置选择模式可以利用JList所提供的setSelectionMode(int selectionMode)方法。例如,若我们将上例改成如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
public class JList2
{
public static void main(String args[])
{
JFrame f = new JFrame("JList");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(1,3));
String[] s1 = {"美国","日本","大陆","英国","法国","意大利","澳洲","韩国"};
String[] s2 = {"范志毅","符兵","周宁","杨晨","高锋","南方","其他"};
Vector v = new Vector();
v.addElement("Nokia 3310");
v.addElement("Nokia 8850");
v.addElement("Nokia 8250");
v.addElement("Motorola V8088");
v.addElement("Motorola V3688x");
v.addElement("Panasonic GD92");
v.addElement("Panasonic GD93");
v.addElement("NEC DB2100");
v.addElement("Alcatel OT500");
v.addElement("Philips Xenium 9@9 ");
v.addElement("Ericsson T29sc");
v.addElement("其他");
JList list1 = new JList(s1);
list1.setBorder(BorderFactory.createTitledBorder("您最喜欢到哪个国家玩呢?"));
JList list2 = new JList(s2);
list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list2.setBorder(BorderFactory.createTitledBorder("您最喜欢哪个运动员呢?"));
JList list3 = new JList(v);
list3.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list3.setBorder(BorderFactory.createTitledBorder("您最喜欢哪一种手机?"));
contentPane.add(new JScrollPane(list1));
contentPane.add(new JScrollPane(list2));
contentPane.add(new JScrollPane(list3));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
7-3-2:利用ListModel构造JList:
ListModel是一个interface,主要的功能是定义一些方法,让JList或JComboBox这些组件取得每个项目的值,并可限定项目的显示
时机与方式,下面为ListModel这个interface所定义的方法:
ListModel interface定义的方法:
void addListDataListener(ListDataListener l):当data model的长度或内容值有任何改变时,利用此
方法就可以处理ListDataListener的事件。data model是vector或array的数据类型,里面存放List
中的值。
Object getElementAt(int index):返回在index位置的Item值。
int getSize():返回List的长度。
void removeListDataListener(ListDataListener l):删除ListDataListener.
还记得我们一开始在介绍JList时所提到的构造函数吗?其中有一个JList的构造函数是这样的:
JList(ListModel dataModel)
因此我们必须实作ListModel所有的方法,才能利用上面这个构造函数建立JList.不过要实现ListModel所有的方法有点麻烦,因
为一般我们不会用到addListDataListener()与removeListDataListener()这两个方法。因此java提供了AbstractListModel这个抽
象类,此抽象类实作了addListDataListener()与removeListDataListener()这两个方法。若我们继承AbstractListModel,就不需
实现这两个方法,只需要实作getElementAt()与getSize()方法即可,我们来看下面的范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JList3{
public JList3(){
JFrame f=new JFrame("JList");
Container contentPane=f.getContentPane();
/*由于我们在DataModelodel类中继承AbstractListModel,并实作了getElementAt()与getSize()方法,因此
*我们可以由DataModel类产生一个ListModel的实体来。
*/
ListModel mode=new DataModel();
JList list=new JList(mode);//利用ListModel建立一个JList.
list.setVisibleRowCount(5);//设置程序一打开时所能看到的数据项个数。
list.setBorder(BorderFactory.createTitledBorder("你最喜欢到哪个国家玩呢?"));
contentPane.add(new JScrollPane(list));
f.pack();
/*当程序要show出list时,系统会先自动调用getSize()方法,看看这个list长度有多少;然后再调 用setVisibleRowCount()方
法,看要一次输出几笔数据;最后调用getElementAt()方法,将list中的项目值(item)填入list中。读者若还不太清楚,可直接
在getSize()与getElementAt()方法中个别加入System.out.println("size");与System.out.println("element")叙述,就可以
在dos console清楚看出整个显示list调用的过程。
*/
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JList3();
}
}
/*由于我们在下面程序中继承AbstractListModel抽象类,因此我们分别在下面程序中实现了getElementAt()与getSize()方法。
*/
class DataModel extends AbstractListModel{
String[] s={"美国","越南","大陆","英国","法国","大陆","意大利","澳洲"};
public Object getElementAt(int index){//getxElementAt()方法中的参数index,系统会自动由0开始计算,不过要自己作累加
//的操作.
return (index+1)+"."+s[index++];
}
public int getSize(){
return s.length;
}
}
事实上,java本身还提供另一个类,DefaultListModel实体类。此类继承了AbstractListModel抽象类,并实现里面所有的抽象方
法,因此你不需要再自行实作任何的方法,可以说是相当的方便。不过既然所有的抽象都已经被实现,因此在设计的弹性上就会有
有所降低。若你是喜欢自行管理JList项目的设计者,你可以不要使用DefaultListModel这个类,只需要在AbstractListModel上多
下功夫即可。
下面的例子我们改写上面的例子,直接使用DefaultListModel类:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
public class JList4
{
public JList4()
{
JFrame f = new JFrame("JList");
Container contentPane = f.getContentPane();
ListModel mode = new DataModel();
JList list = new JList(mode);
list.setVisibleRowCount(5);
list.setBorder(BorderFactory.createTitledBorder("您最喜欢到哪个国家玩呢?"));
contentPane.add(new JScrollPane(list));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[])
{
new JList4();
}
}
/*使DataModel继承DefaultListModel实体类,因此就不需要再实作getSize()与getElementAt()两个方法,
*直接将所要的项目用addElementAt()方法加入即可。系统会自动将所加入的项目放入一个Vector对象中,
*并在输出JList时自动调用getSize()与getElementAt()方法。你可以在DefaultListModel类中找到getSize()与
*getElementAt()两个方法,你可以发现这两个方法已经被实作,不再是抽象方法了。
*/
class DataModel extends DefaultListModel
{
String[] s = {"美国"," 日本","大陆","英国","法国","意大利","澳洲","韩国"};
DataModel()
{
for(int i=0; i < s.length; i++)
addElement((i+1)+"."+s[i]);
}
}
程序运行结果与上个范例相同。
好奇怪,这不是跟我们使用Vector方式,利用JList(Vector v)构造函数来建立新的JList一样吗?如同JList1.java中的例子,为
什么还要多此一举呢?其实若读者去查看DefaultListModel类,可发现此类提供不少好用的方法,例如你可以随意的增加一个项目(
addElement())、或是删除一个项目(removeElement)、甚至你可以很方便地做到查询(getElementAt())与汇出(copyInto())项目的
操作。你可以发现,利用DefaultListModel可以直接动态地更改JList的项目值,而不需要自行产生一个Vecotr对象;相对于JList(
Vector v)这个构造函数,可说更方便且实用许多.
至于利用ListModel或AbstractListModel来构造JList有什么好处?读者只要这么想,ListModel中文就是“列出模式”,那么每
个老师都会有自己开课的学生成绩,老师应该可以看到每个同学的成绩,而深长应该只能看到自己的成绩,所以我们就会有两种不
同的“列出模式”。我们只需要去改写getElementAt()方法,就会有不同的列出模式产生,如下面的范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
public class JList5
{
public JList5()
{
JFrame f = new JFrame("JList");
Container contentPane = f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
ListModel mode = new DataModel(1);
JList list1 = new JList(mode);
list1.setVisibleRowCount(5);
list1.setBorder(BorderFactory.createTitledBorder("您玩过哪些软件?"));
mode = new DataModel(2);
JList list2 = new JList(mode);
list2.setBorder(BorderFactory.createTitledBorder("您玩过哪些数据库软件?"));
contentPane.add(new JScrollPane(list1));
contentPane.add(new JScrollPane(list2));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[])
{
new JList5();
}
}
class DataModel extends AbstractListModel
{
String[] s = {"MS SQL","MySQL","IBM DB2","ORACLE","Windows 2000","Linux","UNix","OS2"};
int flag;
DataModel(int flag)
{
this.flag = flag;
}
public Object getElementAt(int index)
{
String tmp = null;
if (flag == 1)
tmp = (index+1)+"."+s[index++];
if (flag == 2)
{
if(index < 4)
tmp = (index+1)+"."+s[index++];
}
return tmp;
}
public int getSize()
{
return s.length;
}
}
7-3-3:建立有图像的JList:
我们也可以在JList中加入Icon图像,不过JList加入图像比较麻烦一点,不像JLabel或JButton那样简单。要在JList上加入Icon,
要先了解ListCellRenderer interface.我们必须由这个interface所定义的方法,将图像画在JList中的每个项目。
ListCellRenderer interface里只定义了一个方法,那就是getListCellRendererComponent,不过这个参数有点多,我们把它列出来
看看:
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
list:即所要画上的图像的JList组件。
value:JList项目值,如list.getModel().getElementAt(index)所返回的值。
index:为JList项目的索引值,由0开始。
isSelected与cellHasFocus:判断JList中的项目是否有被选取或是有焦点置入。
上面这4个参数会在你设置JList的绘图样式(setCellRenderer())时自动的由JList组件提供,你只要关心怎么控制
getListCellRendererComponent()方法中的4个参数,而无需担心怎么参数传入。
要在JList中加入Icon图像的技巧就是将JList中的每一个项目当作是JLabel,因为JLabel在使用文字与图像上非常的方便,要设置
JList的图像,必须使用setCellRenderer(ListCellRenderer cellRenderer)这个方法。我们来看下面这个范例,你就能明白了!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
public class JList6
{
public JList6()
{
String[] s = {"西瓜","苹果","草莓","香蕉","葡萄"};
JFrame f = new JFrame("JList");
Container contentPane = f.getContentPane();
JList list1 = new JList(s);
list1.setBorder(BorderFactory.createTitledBorder("您喜欢吃哪些水果?"));
/*设置在JList中画上图像。在此参数中,我们产生一个CellRenderer对象,此对象实作了ListCellRenderer interface,
*因此可以返回一个ListCellRenderer对象当作setCellRenderer()方法的参数.
*/
list1.setCellRenderer(new CellRenderer());
contentPane.add(new JScrollPane(list1));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[])
{
new JList6();
}
}
class CellRenderer extends JLabel implements ListCellRenderer
{
/*类CellRenderer继承JLabel并实作ListCellRenderer.由于我们利用JLabel易于插图的特性,因此CellRenderer继承了JLabel
*可让JList中的每个项目都视为是一个JLabel.
*/
CellRenderer()
{
setOpaque(true);
}
/*从这里到结束:实作getListCellRendererComponent()方法*/
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
/*我们判断list.getModel().getElementAt(index)所返回的值是否为null,例如上个例子中,若JList的标题是"你玩过哪
*些数据库软件",则index>=4的项目值我们全都设为null.而在这个例子中,因为不会有null值,因此有没有加上这个判
*断并没有关系.
*/
if (value != null)
{
setText(value.toString());
setIcon(new ImageIcon(".//icons//fruit"+(index+1)+".jpg"));
}
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else {
//设置选取与取消选取的前景与背景颜色.
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}
7-3-4:JList的事件处理:
JList的事件处理一般可分为两种:一种是取得用户选取的项目;另一种是在JList的项目上双击鼠标两次,运行相对应的工作。我
们先来看第一种事件处理方式:
在JList类中有addListSelectionListener()方法,可以检测用户是否对JList的选取有任何的改变。ListSelectionListener
interface中只有定义一个方法,那就是valueChanged(ListSelectionEvent e),我们必须实作这个方法,才能在用户改变选取值时
取得用户最后的选取状态。我们来看一下的例子: 这个例子匀们抓取用户所选取的项目,并将所选的项目显示在JLabel上。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;//由于ListSelectionEvent是swing的事件,不是awt的事件,因此我们必须import
//javax.swing.event.*。
public class JList7 implements ListSelectionListener
{
JList list = null;
JLabel label = null;
String[] s = {"美国","日本","大陆","英国","法国","意大利","澳洲","韩国"};
public JList7()
{
JFrame f = new JFrame("JList");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
label = new JLabel();
list = new JList(s);
list.setVisibleRowCount(5);
list.setBorder(BorderFactory.createTitledBorder("您最喜欢到哪个国家玩呢?"));
list.addListSelectionListener(this);
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(new JScrollPane(list),BorderLayout.CENTER);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[])
{
new JList7();
}
public void valueChanged(ListSelectionEvent e)
{
int tmp = 0;
String stmp = "您目前选取:";
int[] index = list.getSelectedIndices();//利用JList类所提供的getSelectedIndices()方法可得到用户所选取的所有
for(int i=0; i < index.length ; i++)//index值,这些index值由一个int array返回.
{
tmp = index[i];
stmp = stmp+s[tmp]+" ";
}
label.setText(stmp);
}
}
接下来,我们来看如何处理在JList上双击鼠标的操作。由于JList本身并无提供这样的EventListener,因此我们必须利用
MouseListener来达到捕获双击鼠标的事件。至于要怎么知道我们到底在哪个项目上双击鼠标呢?我们可以利用JList类所提供的
LocatToindex()方法得知。以下为我们所举的范例:
这个例子一开始左边列有国这名称,当你在某个国家名称上双击鼠标,这个国家名称就会移到右边去,反之亦同。
1.这个范例我们应用DefaultListModel类,因主DefaultListModel类实作了Vector中的方法,使我们在处理动态的JList项目值
比较容易.
2.由于我们要处理鼠标事件,为了编写方便,在程序中我们继承MouseAdapte抽象类.
3.在程序中,我们建立两个DataModel,第一个JList,也就是list1一开始时会将String Array s中的所有值依次放入list1的项
目中,而list2一开始为空白。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JList8 extends MouseAdapter{
JList list1=null;
JList list2=null;
DefaultListModel mode1=null;
DefaultListModel mode2=null;
String[] s = {"美国","日本","大陆","英国","法国","意大利","澳洲","韩国"};
public JList8(){
JFrame f=new JFrame("JList");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
mode1=new DataModel(1);
list1=new JList(mode1);
list1.setBorder(BorderFactory.createTitledBorder("国家名称!"));
list1.addMouseListener(this);//一遇到鼠标事件立即执行.
mode2=new DataModel(2);
list2=new JList(mode2);
list2.setBorder(BorderFactory.createTitledBorder("你最喜欢到哪个国家玩呢!"));
list2.addMouseListener(this);//一遇到鼠标事件立即执行.
contentPane.add(new JScrollPane(list1));
contentPane.add(new JScrollPane(list2));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JList8();
}
//处理鼠标键击事件.
public void mouseClicked(MouseEvent e){
int index;
/*对list1而言,当鼠标在某个项目连续按两下时,我们利用JList所提供的locationToIndex()方法,找到所键击的项目,并
*由tmp取得此项目的项目值,然后将此项目值增加到mode2中[mode2.addElement(tmp)],用setModel重新设置list2的
*ListModel,使list2可显示出所增加的项目,将刚刚在list1双击的项目删除.
*/
if (e.getSource()==list1){
if (e.getClickCount()==2){
index=list1.locationToIndex(e.getPoint());
String tmp=(String)mode1.getElementAt(index);
mode2 .addElement(tmp);
list2.setModel(mode2);
mode1.removeElementAt(index);
list1.setModel(mode1);
}
}
if (e.getSource()==list2){
if (e.getClickCount()==2){
index=list2.locationToIndex(e.getPoint());
String tmp=(String)mode2.getElementAt(index);
mode1 .addElement(tmp);
list1.setModel(mode1);
mode2.removeElementAt(index);
list2.setModel(mode2);
}
}
}
class DataModel extends DefaultListModel{
DataModel(int flag){
if (flag==1){
for (int i=0;i
}
}
}
7-4:JComboBox的使用:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JComboBox
构造函数:
JComboBox():建立一个新的JComboBox组件。
JComboBox(ComboBoxModel aModel):用ListModel建立一个新的JComboBox组件。
JComboBox(Object[] items):利用Array对象建立一个新的JComboBox组件。
JComboBox(Vector items):利用Vector对象建立一个新的JComboBox组件。
7-4-1:建立一般的JComboBox:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
public class JComboBox1{
public static void main(String[] args){
JFrame f=new JFrame("JComboBox1");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(1,2));
String[] s = {"美国","日本","大陆","英国","法国","意大利","澳洲","韩国"};
Vector v=new Vector();
v.addElement("Nokia 8850");
v.addElement("Nokia 8250");
v.addElement("Motorola v8088");
v.addElement("Motorola v3850");
v.addElement("Panasonic 8850");
v.addElement("其它");
JComboBox combo1=new JComboBox(s);
combo1.addItem("中国");//利用JComboBox类所提供的addItem()方法,加入一个项目到此JComboBox中。
combo1.setBorder(BorderFactory.createTitledBorder("你最喜欢到哪个国家玩呢?"));
JComboBox combo2=new JComboBox(v);
combo2.setBorder(BorderFactory.createTitledBorder("你最喜欢哪一种手机呢?"));
contentPane.add(combo1);
contentPane.add(combo2);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
7-4-2:利用ComboModel构造JComboBox:
如同JList一般,在JComboBox中也有一个构造函数是利用某种Model来构造。如下所示:
JComboBox(COmboBoxModel aModel)
ComboBoxModel是一个interface,里面定义了两个方法,分别是setSelectedItem()与getSelectedItem().这两个方法目的是让用
户选取某个项目后,可正确地显示出用户所选取的项目。下面是这两个方法的详细定义:
ComboBoxModel interface定义的方法:
Object getSelectedItem():返回所选取的项目值。
Void setSelectedItem(Object anItem):设置所选取的项目值.
与JList不同的是,JComboBox是利用ComboBoxModel,而不是ListModel.不过ComboBoxModel interface是继承ListModel interface
,因此若我们要利用ComboBoxModel来构造JComboBox,除了要实作ComboBoxModel的两个方法外,还必须实作ListModel的所定义的4个
方法,这样的做法可说相当麻烦。
在介绍JList时我们曾经提到AbstractListModel这个抽象类。这个抽象类实作了ListModel interface中的addListDataListener
()、removeListDataListener()这两个方法。因此若我们继承AbstractListModel,则可少掉实作这两个方法,只需要实作
getElementAt()、getSize()、setSelectedItem()与getSelectedItem()这4个方法。这样的作法就显得比较简单一点.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox2{
String[] s= {"美国","日本","大陆","英国","法国","意大利","澳洲","韩国"};
public JComboBox2(){
JFrame f=new JFrame("JComboBox2");
Container contentPane=f.getContentPane();
ComboBoxModel mode=new UserDefineComboBoxModel();
JComboBox combo=new JComboBox(mode);
combo.setBorder(BorderFactory.createTitledBorder("你最喜欢到哪个国家去玩?"));
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JComboBox2();
}
class UserDefineComboBoxModel extends AbstractListModel implements ComboBoxModel{
String item=null;
public Object getElementAt(int index){
return s[index++];
}
//由于继承AbstractListModel抽象类。因此我们分别在程序中实作了getElementAt()与getSize()方法。
public int getSize(){
return s.length;
}
//由于我们实现了ComboBoxModel interface.因此我们必须在程序中实作setSelectedItem()与getSelectedItem()方法.
public void setSelectedItem(Object anItem){
item=(String)anItem;
}
public Object getSelectedItem(){
return item;
}
}
}
当程序要show出JComboBox时,系统会先自动调用getSize()方法,看看这个JComboBox长度有多少,然后再调用getElementAt()
方法,将String Array s中的值填入JComboBox中。当用户选择项目时,系统会调用getSelectedItem()方法,返回所选取的项目,并
利用setSelectedItem()方法,将选取项目放在JComboBox最前端。
getElementAt()方法中的“index”参数,系统会自动由0计算,不过要自己作累加的操作,如程序中:
return s[index++];
如同JList一般,java对于JComboBox也提供了另一个类,DefaultComboBoxModel实体类。此类继承了AbstractListModel抽象类,也
实作了ComboBoxModel interface.因此你不需要再实作getSize()、getElementAt()、setSelectedItem()与getSelectedItem()方法。
利用DefaultComboBoxModel这个类我们可以很方便地做到动态更改JComboBox的项目值。当你没有必要自己定义特殊的ComboBoxModel
时,使用DefaultComboBoxModel就显得非常的方便,我们来看下面的例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox3{
String[] s = {"美国","日本","大陆","英国","法国","意大利","澳洲","韩国"};
public JComboBox3(){
JFrame f=new JFrame("JComboBox3");
Container contentPane=f.getContentPane();
ComboBoxModel mode=new AModel();
JComboBox combo=new JComboBox(mode);
combo.setBorder(BorderFactory.createTitledBorder("您最喜欢到哪个国家玩呢?"));
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JComboBox3();
}
class AModel extends DefaultComboBoxModel{
AModel(){
for (int i=0;i
}
}
}
1.由于AModel继承DefaultComboBoxModel实体类,由AModel可得到一个ComboBoxModel实体对象。
2.我们使AModel继承DefaultComboBoxModel实体类,因此就不需要再实作getElementAt()、getSize()、setSelectedItem()与
getSelectedItem()这4个方法,直接将所要的项目用addElement()方法加入即可。系统会自动将所加入的项目放进一个Vector
中,并在输出JComboBox时自动调用getSize()与getElementAt()方法。
7-4-3:建立有图像的JComboBox:
在上一节中我们利用ListCellRenderer interface在JList中加入Icon图像,而要在JComboBox中加入图像的方法也是一样的。
我们必须实作ListCellRenderer interface所定义的方法getListCellRendererComponent.以下为这个方法的定义:
要先了解ListCellRenderer interface.我们必须由这个interface所定义的方法,将图像画在JComboBox中的每个项目。
ListCellRenderer interface里只定义了一个方法,那就是getListCellRendererComponent,不过这个参数有点多,我们把它列出来
看看:
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
list:即所要画上的图像的JComboBox组件。
value:JComboBox项目值,如JComboBox.getModel().getElementAt(index)所返回的值。
index:为JComboBox项目的索引值,由0开始。
isSelected与cellHasFocus:判断JComboBox中的项目是否有被选取或是有焦点置入。
上面这4个参数会在你设置JComboBox的绘图样式(setCellRenderer())时自动的由JComboBox组件提供,你只要关心怎么控制
getListCellRendererComponent()方法中的4个参数,而无需担心怎么参数传入。
要在JList中加入Icon图像的技巧就是将JComboBox中的每一个项目当作是JLabel,因为JLabel在使用文字与图像上非常的方便,要设置JComboBox的图像,
必须使用setRenderer(ListCellRenderer cellRenderer){注:我们在JList中画上图像是利用JList所提供的setCellRenderer(ListCellRenderer
cellRenderer)方法,读者请小心}这个方法。我们来看下面这个范例,你就能明白了!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox4{
String[] s={"西瓜","苹果","草莓","香蕉","葡萄"};
public JComboBox4(){
JFrame f=new JFrame("JComboBox");
Container contentPane=f.getContentPane();
JComboBox combo=new JComboBox(s);
combo.setBorder(BorderFactory.createTitledBorder("你最喜欢吃哪些水果?"));
combo.setRenderer(new ACellRenderer());
combo.setMaximumRowCount(3);
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JComboBox4();
}
}
class ACellRenderer extends JLabel implements ListCellRenderer{
ACellRenderer(){
setOpaque(true);
}
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus){
if (value!=null){
setText(value.toString());
setIcon(new ImageIcon(".//icons//fruit"+(index+1)+".jpg"));
}
if (isSelected){
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}else{
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}
各们读者在运行这个程序时会发现,即使JComboBox的选项中有图标,但在选后图标却不会显示在显示列中,原因是在上面程序中
我们以String Array s建立JComboBox:
JComboBox combo=new JComboBox(s);
String Array s里面放的只是水果名称,而并没有图标。当我们使用setRenderer()方法来JComboBox时,只会绘制JComboBox的
选项部份,而最后显示在JComboBox上的值还是以String Array s为依据。因此JComboBox显示列就只会显示文字而已,而不会显示出
图形。要解决这个问题,我们必须改变JComboBox所传入的参数内容,也就是将原来的String Array s更改成具有图形的数据项。在
此我们是利用JComboBox(Object[] items)来建立有图像的JComboBox,我们所传进去的Object Array不应该只有文字,而必须连图标一
并传入。我们修改上个范例修改如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox5
{
String[] s = {"西瓜","苹果","草莓","香蕉","葡萄"};
ImageIcon[] icons = new ImageIcon[5];;
public JComboBox5()
{
JFrame f = new JFrame("JComboBox");
Container contentPane = f.getContentPane();
ItemObj[] obj = new ItemObj[5];
for(int i=0; i < 5; i++)
{
icons[i] = new ImageIcon(".//icons//fruit"+(i+1)+".jpg");
obj[i] = new ItemObj(s[i],icons[i]);
}
JComboBox combo = new JComboBox(obj);//利用ItemObj Array obj当作是JComboBox的参数传入,构造出JComboBox.
combo.setBorder(BorderFactory.createTitledBorder("您喜欢吃哪些水果?"));
combo.setRenderer(new ACellRenderer());
combo.setMaximumRowCount(3);
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[])
{
new JComboBox5();
}
}
class ItemObj
{
String name;
ImageIcon icon;
public ItemObj(String name, ImageIcon icon){
this.name = name;
this.icon = icon;
}
}
class ACellRenderer extends JLabel implements ListCellRenderer
{
ACellRenderer()
{
setOpaque(true);
}
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
if (value != null)
{
setText(((ItemObj)value).name);
setIcon(((ItemObj)value).icon);
}
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}
你可以发现,第一栏显示有图标显示出来了。当然你也可以利用ComboBoxModel方式来构造出有图标的JComboBox.我们来看下面
的例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox6{
String[] s={"西瓜","苹果","草莓","香蕉","葡萄"};
ImageIcon[] icons=new ImageIcon[5];
public JComboBox6(){
JFrame f=new JFrame("JComboBox");
Container contentPane=f.getContentPane();
for(int i=0; i < 5; i++)
{
icons[i] = new ImageIcon(".//icons//fruit"+(i+1)+".jpg");
}
ComboBoxModel mode=new AModel();
JComboBox combo=new JComboBox(mode);
combo.setBorder(BorderFactory.createTitledBorder("您喜欢吃哪些水果?"));
combo.setRenderer(new ACellRenderer());
combo.setMaximumRowCount(3);
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args){
new JComboBox6();
}
/*我们用JComboBox(ComboBoxModel aModel)来构造图标的JComboBox,因此我们在程序中编写一个继承DefaultComboBoxModel的
ComboBoxModel.
*/
class AModel extends DefaultComboBoxModel{
AModel(){
for (int i=0;i
addElement(obj);
}
}
}
}
class ItemObj
{
String name;
ImageIcon icon;
public ItemObj(String name, ImageIcon icon){
this.name = name;
this.icon = icon;
}
}
class ACellRenderer extends JLabel implements ListCellRenderer
{
ACellRenderer()
{
setOpaque(true);
}
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
if (value != null)
{
setText(((ItemObj)value).name);
setIcon(((ItemObj)value).icon);
}
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}
我们用JComboBox(ComboBoxModel aModel)来构造图标的JComboBox,因此我们在程序中编写一个继承DefaultComboBoxModel的
ComboBoxModel.
7-4-4:建立可自行输入的JComboBox:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox7
{
String[] fontsize = {"12","14","16","18","20","22","24","26","28"};
String defaultMessage = "请选择或直接输入文字大小!";
public JComboBox7()
{
JFrame f = new JFrame("JComboBox");
Container contentPane = f.getContentPane();
JComboBox combo = new JComboBox(fontsize);
combo.setBorder(BorderFactory.createTitledBorder("请选择你要的文字大小"));
combo.setEditable(true);//将JComboBox设成是可编辑的.
ComboBoxEditor editor = combo.getEditor();//getEditor()方法返回ComboBoxEditor对象,如果你查看手册,你就会发
//现ComboBoxEditor是个接口(interface),因此你可以自行实作这个接口,制作自己想要的ComboBoxEditor组件。但通常
//我们不需要这么做,因为默认的ComboBoxEditor是使用JTextField,这已经足够应付大部份的情况了。
//configureEditor()方法会初始化JComboBox的显示项目。例如例子中一开始就出现:"请选择或直接输入文字大小!"这个
//字符串。
combo.configureEditor(editor, defaultMessage);
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[])
{
new JComboBox7();
}
}
7-4-5:JComboBox的事件处理:
JComboBox的事件处理亦可分为两种,一种是取得用户选取的项目;另一种是用户在JComboBox上自行输入完毕后按下[Enter]键,
运作相对应的工作。对于第一种事件的处理,我们使用ItemListener.对于第二种事件的处理,我们使用ActionListener.
这个范例用户可以选取所要的字号,字号的变化会呈现在JLabel上,并可让用户自行输入字体的大小。当用户按下[Enter]键后
,若用户输入的值不在选项上时,此输入值会增加至JComboBox中,并将输入字体的大小显示在JLabel上。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JComboBox8 implements ItemListener,ActionListener{
String[] fontsize={"12","14","16","18","20","22","24","26","28"};
String defaultMessage="请选择或直接输入文字大小!";
Font font=null;
JComboBox combo=null;
JLabel label=null;
public JComboBox8(){
JFrame f=new JFrame("JComboBox");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(2,1));
label=new JLabel("Swing",JLabel.CENTER);
font=new Font("SansSerif",Font.PLAIN,12);
label.setFont(font);
combo=new JComboBox(fontsize);
combo.setBorder(BorderFactory.createTitledBorder("请选择你要的文字大小:"));
combo.setEditable(true);
ComboBoxEditor editor=combo.getEditor();
combo.configureEditor(editor,defaultMessage);
combo.addItemListener(this);0
combo.addActionListener(this);
contentPane.add(label);
contentPane.add(combo);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JComboBox8();
}
public void actionPerformed(ActionEvent e){
boolean isaddItem=true;
int fontsize=0;
String tmp=(String)combo.getSelectedItem();
//判断用户所输入的项目是否有重复,若有重复则不增加到JComboBox中。
try{
fontsize=Integer.parseInt(tmp);
for(int i=0;i
isaddItem=false;
break;
}
}
if (isaddItem){
combo.insertItemAt(tmp,0);//插入项目tmp到0索引位置(第一列中).
}
font=new Font("SansSerif",Font.PLAIN,fontsize);
label.setFont(font);
}catch(NumberFormatException ne){
combo.getEditor().setItem("你输入的值不是整数值,请重新输入!");
}
}
public void itemStateChanged(ItemEvent e){//ItemListener界面只有itemStateChanged()一个方法,在此实作它。
if (e.getStateChange()==ItemEvent.SELECTED){//当用户的选择改变时,则在JLabel上会显示出Swing目前字形大小信息.
int fontsize=0;
try{
fontsize=Integer.parseInt((String)e.getItem());
label.setText("Swing 目前字形大小:"+fontsize);
}catch(NumberFormatException ne){//若所输入的值不是整数,则不作任何的操作.
}
}
}
}
++ Swing读书笔记表格(Table)的使用与介绍
8-1:使用JTable组件:
类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JTabel
在使用JTable以前,我们先看一下它的构造函数有哪些, 以及应该如何使用:
JTabel构造函数:
JTable():建立一个新的JTables,并使用系统默认的Model.
JTable(int numRows,int numColumns):建立一个具有numRows行,numColumns列的空表格,使用的是DefaultTableModel.
JTable(Object[][] rowData,Object[][] columnNames):建立一个显示二维数组数据的表格,且可以显示列的名称。
JTable(TableModel dm):建立一个JTable,有默认的字段模式以及选择模式,并设置数据模式。
JTable(TableModel dm,TableColumnModel cm):建立一个JTable,设置数据模式与字段模式,并有默认的选择模式。
JTable(TableModel dm,TableColumnModel cm,ListSelectionModel sm):建立一个JTable,设置数据模式、字段模式、与选择模式。
JTable(Vector rowData,Vector columnNames):建立一个以Vector为输入来源的数据表格,可显示行的名称。
我们先以Array构造方式,说明如何利用JTable来建立一个简单的表格:
1 import javax.swing.*;
2 import java.awt.*;
3 import java.awt.event.*;
4 import java.util.*;
5 public class SimpleTable{
6 public SimpleTable(){
7 JFrame f=new JFrame();
8 Object[][] playerInfo={
9 {"阿呆",new Integer(66),new Integer(32),new Integer(98),new Boolean(false)},
10 {"阿呆",new Integer(82),new Integer(69),new Integer(128),new Boolean(true)},
11 };
12 String[] Names={"姓名","语文","数学","总分","及格"};
13 JTable table=new JTable(playerInfo,Names);
14 table.setPreferredScrollableViewportSize(new Dimension(550,30));
15 JScrollPane scrollPane=new JScrollPane(table);
16 f.getContentPane().add(scrollPane,BorderLayout.CENTER);
17 f.setTitle("Simple Table");
18 f.pack();
19 f.show();
20 f.addWindowListener(new WindowAdapter() {
21 public void windowClosing(WindowEvent e) {
22 System.exit(0);
23 }
24 });
24 }
25 public static void main(String[] args){
26 SimpleTable b=new SimpleTable();
27 }
28 }
表格由两部份组成:分别是行标题(Column Header)与行对象(Column Object).利用JTable所提供的getTableHeader()方法取得
行标题。在这个例子中,我们将JTable放在JScrollPane中,这种做法可以将Column Header与Colmn Object完整的显示出来,因为
JScrollPane会自动取得Column Header.但如果文坛读者将上面第15行去掉并修改第16行:
f.getContentPane().add(table,BorderLayout.CENTER);
则运行结果你会发现Column Header不见了。
如果你不想用JScrollPane,要解决这个问题,你必须将程序修改如下:
JTable table=new JTable(p,n);
table.setPreferredScrollableViewportSize(new Dimension(550,30));
f.getContentPane().add(table.getTableHeader(),BorderLayout.NORTH);
f.getContentPane().add(table,BorderLayout.CENTER);
运行结果就会跟之前一样有行标题了.
上面的运行结果就会跟发现,每个字段的宽度都是一样的,除非你自行拉曳某个列宽。若我们想一开始就设置列宽的值,可以利
用TableColumn类所提供的setPreferredWidth()方法来设置,并可利用JTable类所提供的setAutoResizeMode()方法来设置调整某个
列宽时其他列宽的变化情况,我们看下面这个例子:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class SimpleTable2{
public SimpleTable2(){
JFrame f=new JFrame();
Object[][] p={
{"阿呆",new Integer(66),new Integer(32),new Integer(98),new Boolean(false),new Boolean(false)},
{"阿呆",new Integer(82),new Integer(69),new Integer(128),new Boolean(true),new Boolean(false)},
};
String[] n={"姓名","语文","数学","总分","及格","作弊"};
TableColumn column=null;
JTable table=new JTable(p,n);
table.setPreferredScrollableViewportSize(new Dimension(550,30));
table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
for (int i=0;i<6;i++){
//利用JTable中的getColumnModel()方法取得TableColumnModel对象;再利用TableColumnModel界面所定义的getColumn()方法取
//TableColumn对象,利用此对象的setPreferredWidth()方法就可以控制字段的宽度.
column=table.getColumnModel().getColumn(i);
if ((i%2)==0)
column.setPreferredWidth(150);
else
column.setPreferredWidth(50);
}
JScrollPane scrollPane=new JScrollPane(table);
f.getContentPane().add(scrollPane,BorderLayout.CENTER);
f.setTitle("Simple Table");
f.pack();
f.show();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args){
new SimpleTable2();
}
}
列可调整的5个参数:
AUTO_RESIZE_SUBSEQUENT_COLUMENS:当调整某一列宽时,此字段之后的所有字段列宽都会跟着一起变动。此为系统默认值。
AUTO_RESIZE_ALL_COLUMNS:当调整某一列宽时,此表格上所有字段的列宽都会跟着一起变动。
AUTO_RESIZE_OFF:当调整某一列宽时,此表格上所有字段列宽都不会跟着改变。
AUTO_RESIZE_NEXT_COLUMN:当调整某一列宽时,此字段的下一个字段的列宽会跟着改变,其余均不会变。
AUTO_RESIZE_LAST_COLUMN:当调整某一列宽时,最后一个字段的列宽会跟着改变,其余均不会改变。
由以上范例可知,利用Swing来构造一个表格其实很简单的,只要你利用Vector或Array来作为我们表格的数据输入,将Vector或Array的
内容填入JTable中,一个基本的表格就产生了。不过,虽然利用JTable(Object[][] rowData,Object[][] columnNames)以及
JTable(Vector rowData,Vector columnNames)构造函数来构造构造JTable很方便,但却有些缺点。例如上例中,我们表格中的每个字段
(cell)一开始都是默认为可修改的,用户因此可能修改到我们的数据;其次,表格中每个单元(cell)中的数据类型将会被视为同一种。在我
们的例子中,数据类型皆被显示为String的类型,因此,原来的数据类型声明为Boolean的数据会以String的形式出现而不是以检查框(
Check Box)出现。
除此之外,如果我们所要显示的数据是不固定的,或是随情况而变,例如同样是一份成绩单,老师与学生所看到的表格就不会一样,显
示的外观或操作模式也许也不相同。为了因应这些种种复杂情况,上面简单的构造方式已不宜使用,Swing提供各种Model(如:
TableModel、TableColumnModel与ListSelectionModel)来解决上述的不便,以增加我们设计表格的弹性。我们下面就先对TableModel来
做介绍:
8-2:TableModel
TableModel类本身是一个interface,在这个interface里面定义了若干的方法:包括了存取表格字段(cell)的内容、计算表格的列数等等
的基本存取操作,让设计者可以简单地利用TableModel来实作他所想要的表格。TableModel界面是放在javax.swing.table package中,这
个package定义了许多JTable会用到的各种Model,读者可利用java api文件找到这个package,并由此package找到各类或界面所定义的方法
。
TableModel方法:
void addTableModelListener(TableModelListener l):使表格具有处理TableModelEvent的能力。当表格的Table Model有所
变化时,会发出TableModel Event事件信息.
Class getColumnClass(int columnIndex):返回字段数据类型的类名称.
int getColumnCount():返回字段(行)数量.
String getColumnName(int columnIndex):返回字段名称.
int getRowCount():返回数据列数量.
Object getValueAt(int rowIndex,int columnIndex):返回数据某个cell中的值.
boolean isCellEditable(int rowIndex,int columnIndex):返回cell是否可编辑,true的话为可编辑.
void removeTableModelListener(TableModelListener l):从TableModelListener中移除一个listener.
void setValueAt(Object aValue,int rowIndex,int columnIndex):设置某个cell(rowIndex,columnIndex)的值;
由于TableModel本身是一个Interface,因此若要直接实现此界面来建立表格并不是件轻松的事.幸好java提供了两个类分别实现了这个
界面,一个是AbstractTableModel抽象类,一个是DefaultTableModel实体类.前者实现了大部份的TableModel方法,让用户可以很有弹性地构
造自己的表格模式;后者继承前者类,是java默认的表格模式.这三者的关系如下所示:
TableModel---implements--->AbstractTableModel-----extends--->DefaultTableModel
8-3:AbstractTableModel:
java提供的AbstractTableModel是一个抽象类,这个类帮我们实现大部份的TableModel方法,除了getRowCount(),getColumnCount(),
getValueAt()这三个方法外.因此我们的主要任务就是去实现这三个方法.利用这个抽象类就可以设计出不同格式的表格.我们来看看它所
提供的方法:
AbstractTableModel方法:
void addTableModelListener(TableModelListener l):使表格具有处理TableModelEvent的能力.当表格的Table Model有所变化时,会发
出TableModelEvent事件信息.
int findColumn(String columnName):寻找在行名称中是否含有columnName这个项目.若有,则返回其所在行的位置;反之则返回-1表示
未找到.
void fireTableCellUpdated(int row, int column):通知所有的Listener在这个表格中的(row,column)字段的内容已经改变了.
void fireTableChanged(TableModelEvent e):将所收的事件通知传送给所有在这个table model中注册过的TableModelListeners.
void fireTableDataChanged():通知所有的listener在这个表格中列的内容已经改变了.列的数目可能已经改变了,因此JTable可能需要
重新显示此表格的结构.
void fireTableRowsDeleted(int firstRow, int lastRow):通知所有的listener在这个表格中第firstrow行至lastrow列已经被删除了.
void fireTableRowsUpdated(int firstRow, int lastRow)
:通知所有的listener在这个表格中第firstrow行至lastrow列已经被修改了.
void fireTableRowsInserted(int firstRow, int lastRow):通知所有的listener在这个表格中第firstrow行至lastrow列已经被加入了
.
void fireTableStructureChanged():通知所有的listener在这个表格的结构已经改变了.行的数目,名称以及数据类型都可能已经改变了
.
Class getColumnClass(int columnIndex):返回字段数据类型的类名称.
String getColumnName(int column):若没有设置列标题则返回默认值,依次为A,B,C,...Z,AA,AB,..;若无此column,则返回一个空的String
.
Public EventListener[] getListeners(Class listenerType):返回所有在这个table model所建立的listener中符合listenerType的
listener,并以数组形式返回.
boolean isCellEditable(int rowIndex, int columnIndex)
:返回所有在这个table model所建立的listener中符合listenerType形式的
listener,并以数组形式返回.
void removeTableModelListener(TableModelListener l):从TableModelListener中移除一个listener.
void setValueAt(Object aValue, int rowIndex, int columnIndex)
:设置某个cell(rowIndex,columnIndex)的值.
若你仔细比较TableModel所定义的方法与上述AbstractTableModel所提供的方法,你可以发现,AbstractTableModel抽象类并没有实现
getRowCount(),getColumnCount(),getValueAt()这三个方法,这也就是为什么我们要去实现这三个方法的原因.下面我们来看如何使用
AbstractTableModel来实作出自己想要的表格模式.
范例:TableModel1.java
import javax.swing.table.AbstractTableModel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TableModel1{
public TableModel1() {
JFrame f = new JFrame();
MyTable mt=new MyTable();
JTable t=new JTable(mt);
t.setPreferredScrollableViewportSize(new Dimension(550, 30));
JScrollPane s = new JScrollPane(t);
f.getContentPane().add(s, BorderLayout.CENTER);
f.setTitle("JTable1");
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
new TableModel1();
}
}
class MyTable extends AbstractTableModel{
Object[][] p = {
{"阿呆", new Integer(66),
new Integer(32), new Integer(98), new Boolean(false),new Boolean(false)},
{"阿瓜", new Integer(85),
new Integer(69), new Integer(154), new Boolean(true),new Boolean(false)},
};
String[] n = {"姓名",
"语文",
"数学",
"总分",
"及格",
"作弊"};
public int getColumnCount() {
return n.length;
}
public int getRowCount() {
return p.length;
}
public String getColumnName(int col) {
return n[col];
}
public Object getValueAt(int row, int col) {
return p[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
}
上例中表格内的数据类型不论是String,int或是Boolean类型,都均以string的类型显示.例如在及格的字段中,原本的数据是以Boolean
类型来表示,但显示在JTable上时便转换成字符串形式,若想要使表格能显示出不同的数据类型,我们要在MyTable中Override写getColumnCl
ass()方法,这个方法可以让我们分辨出表格中每一行的数据类型,并将此类型作适当的显示:
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
这样"作弊"会以Check Box显示,数据类型一律靠右显示,String类型一律靠左显示.
TableModel2.java
import javax.swing.table.AbstractTableModel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TableModel2 implements ActionListener{
JTable t = null;
public TableModel2() {
JFrame f = new JFrame("DataModel");
JButton b1 = new JButton("数学老师");
b1.addActionListener(this);
JButton b2 = new JButton("学生阿呆");
b2.addActionListener(this);
JPanel panel = new JPanel();
panel.add(b1);
panel.add(b2);
t=new JTable(new MyTable(1));
t.setPreferredScrollableViewportSize(new Dimension(550, 30));
JScrollPane s = new JScrollPane(t);
f.getContentPane().add(panel, BorderLayout.NORTH);
f.getContentPane().add(s, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("学生阿呆"))
t.setModel(new MyTable(1));
if (e.getActionCommand().equals("数学老师"))
t.setModel(new MyTable(2));
t.revalidate();
}
public static void main(String args[]) {
new TableModel2();
}
}
class MyTable extends AbstractTableModel{
Object[][] p1 = {
{"阿呆", "1234",new Integer(66),
new Integer(50), new Integer(116), new Boolean(false),new Boolean(false)}};
String[] n1 = {"姓名","学号","语文","数学","总分","及格","作弊"};
Object[][] p2 = {
{"阿呆", "1234",new Integer(50), new Boolean(false),new Boolean(false),"01234"},
{"阿瓜", "1235",new Integer(75), new Boolean(true),new Boolean(false),"05678"}};
String[] n2 = {"姓名","学号","数学","及格","作弊","电话"};
int model = 1;
public MyTable(int i){
model = i;
}
public int getColumnCount() {
if(model ==1)
return n1.length;
else
return n2.length;
}
public int getRowCount() {
if(model ==1)
return p1.length;
else
return p2.length;
}
public String getColumnName(int col) {
if(model ==1)
return n1[col];
else
return n2[col];
}
public Object getValueAt(int row, int col) {
if(model == 1)
return p1[row][col];
else
return p2[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
}
8-4:TableColumnModel:
TableColumnModel本身是一个Interface,里面定义了许多与表格的"列(行)"有关的方法,例如增加列,删除列,设置与取得"列"的相关信
息.通常我们不会直接实现TableColumnModel界面,而是会利用JTable的getColumnModel()方法取得TableColumnModel对象,再利用此对象对
字段做设置.举例来说,如果我们想设计的表格是包括有下拉式列表的Combo Box,我们就能利用TableColumnModel来达到这样的效果.
我们先看看下面的例子:
import javax.swing.table.AbstractTableModel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ColumnModelTest{
public ColumnModelTest() {
JFrame f = new JFrame();
/*由于我们的MyTable类继承了AbstractTableModel并且实作了getColmunCount(),getRowCount(),getValueAt()方法.因此我们可以通
*过MyTable来产生TableModel的实体.
*/
MyTable mt=new MyTable();
JTable t=new JTable(mt);//我们利用MyTable来建立JTable.
JComboBox c = new JComboBox();//建立一个JComboBox的对象.
c.addItem("Taipei");//我们在新建立的JComboBox对象里新增三个项目.
c.addItem("ChiaYi");
c.addItem("HsinChu");
/*我们利用JTable所提供的getTableColumnModel()方法取得TableColumnModel对象,再由TableColumnModel类所提供的getColumn()方
*法取得TableColumn对象,TableColumn类可针对表格中的每一行做具体的设置,例如设置字段的宽度,某行的标头,设置输入较复杂的
*数据类型等等.在这里,我们利用TableColumn类所提供的setCellEditor()方法,将JComboBox作为第二行的默认编辑组件.
*/
t.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(c));
t.setPreferredScrollableViewportSize(new Dimension(550, 30));
JScrollPane s = new JScrollPane(t);
f.getContentPane().add(s, BorderLayout.CENTER);
f.setTitle("ColumnModelTest");
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
new ColumnModelTest();
}
}
class MyTable extends AbstractTableModel{
Object[][] p = {
{"阿呆", "Taipei",new Integer(66),
new Integer(32), new Integer(98), new Boolean(false),new Boolean(false)},
{"阿瓜", "ChiaYi",new Integer(85),
new Integer(69), new Integer(154), new Boolean(true),new Boolean(false)},
};
String[] n = {"姓名",
"居住地",
"语文",
"数学",
"总分",
"及格",
"作弊"};
public int getColumnCount() {
return n.length;
}
public int getRowCount() {
return p.length;
}
public String getColumnName(int col) {
return n[col];
}
public Object getValueAt(int row, int col) {
return p[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
public void setValueAt(Object value, int row, int col) {
p[row][col] = value;
fireTableCellUpdated(row, col);
}*/
}
读者运行此程序可以发现,利用继承AbstractTableModel抽象类所产生的JTable的内容是不能被修改的.那如果想要让用户可以修改表格
中的某一个字段,例如勾选Check Box或是直接修改某个字段的数字,该怎么做呢?很简单,只要我们在范例中的MyTable类中覆写AbstractTab
leModel抽象类中的isCellEditable()方法即可.下面即是isCellEditable()的实作:
public boolean isCellEditable(int rowIndex,int columnIndex){
return true;
}
在isCellEditable()中,我们只有一行简单的程序代码:return true,意思是将我们表格内的每个cell都变成可修改.但仅仅修改这个程
序代码还不行,你可以发现虽然表格现在变成了可以修改了,但更改完之后按下[Enter]键,内容马上恢复成原有的值!解决的方法是覆写
AbstractTableModel抽象类中的setValueAt()方法,这个方法主要是让我们将改过的值存入表格中,如下所示:
public void setValueAt(Object value,int row,int col){
p[row][col]=value;
fireTableCellUpdated(row,col);
}
其中value为我们所更改的值,我们将value存入p[row][col]中,并且调用firTableCellUpdated()函数来告诉我们的系统表格已经做了更
改了,关于这一部份,我们后面会再对事件处理作详细地介绍,在此范例中有没有加入fireTableCellUpdated()方法对运行结果不会造成影响
.
8-5:SelectionModel
表格的选择模式是依据我们前面所讲的ListSelectionModel而来,因此它的操作模式与事件处理跟JList没什么分别!我们稍微复习一
下ListSelectionModel这个Interface,它包含了3个常数值,如下:
static int SINGLE_SELECTION
static int SINGLE_INTERVAL_SELECTION
static int MULTIPLE_INTERVAL_SELECTION
分别可让用户作单一选择,连续区间选择与多重选择.当用户作后面两个模式的操作时,应配合[Shift]键或[Ctrl]键.
要使用ListSelectionModel可利用JTable的getSelectionModel()方法取得ListSelectionModel对象,再利用ListSelectionModel界面所
定义的setSelectionModel()来设置选择模式.
如同JList一般,当用户对表格作数据域位的选取时会产生ListSelectionEvent事件,要处理这个事件就必须实现ListSelectionListener
这个界面,此界面定义了一个方法,那就是valueChanged().
我们来看下面的例子,用户可在按钮上选择哪种选择模式,当用户选取表格数据时,程序会将用户选取的数据显示在表格下面的JLabel中.
SelectionModelDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class SelectionModelDemo implements ActionListener,ListSelectionListener{
JTable table=null;
ListSelectionModel selectionMode=null;
JLabel label=null;//显示用户选取表格之用
public SelectionModelDemo(){
JFrame f=new JFrame();
String[] name={"字段1","字段2","字段3","字段4","字段5"};
String[][] data=new String[5][5];
int value=1;
for(int i=0;i
}
}
table=new JTable(data,name);
table.setPreferredScrollableViewportSize(new Dimension(400,80));
table.setCellSelectionEnabled(true);//使得表格的选取是以cell为单位,而不是以列为单位.若你没有写此行,则在选取表格数
//据时以整列为单位.
selectionMode=table.getSelectionModel();//取得table的ListSelectionModel.
selectionMode.addListSelectionListener(this);
JScrollPane s=new JScrollPane(table);
JPanel panel=new JPanel();
JButton b=new JButton("单一选择");
panel.add(b);
b.addActionListener(this);
b=new JButton("连续区间选择");
panel.add(b);
b.addActionListener(this);
b=new JButton("多重选择");
panel.add(b);
b.addActionListener(this);
label=new JLabel("你选取:");
Container contentPane=f.getContentPane();
contentPane.add(panel,BorderLayout.NORTH);
contentPane.add(s,BorderLayout.CENTER);
contentPane.add(label,BorderLayout.SOUTH);
f.setTitle("SelectionModelDemo");
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
/*处理按钮事件,利用ListSelectionModel界面所定义的setSelectionMode()方法来设置表格选取模式.*/
public void actionPerformed(ActionEvent e){
if (e.getActionCommand().equals("单一选择"))
selectionMode.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
if (e.getActionCommand().equals("连续区间选择"))
selectionMode.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
if (e.getActionCommand().equals("多重选择"))
selectionMode.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.revalidate();
}
/*当用户选取表格数据时会触发ListSelectionEvent,我们实现ListSelectionListener界面来处理这一事件.ListSelectionListener界
*面只定义一个方法,那就是valueChanged().
*/
public void valueChanged(ListSelectionEvent el){
String tempString="";
//JTable的getSelectedRows()与getSelectedColumns()方法会返回已选取表格cell的index Array数据.
int[] rows=table.getSelectedRows();
int[] columns=table.getSelectedColumns();
//JTable的getValueAt()方法会返回某行的cell数据,返回值是Object数据类型,因此我们要自行转成String数据类型.
for (int i=0;i
}
label.setText("你选取:"+tempString);
}
public static void main(String[] args){
new SelectionModelDemo();
}
}
说明:
在此范例中,我们要处理ActionEvent与ListSelectionEvent,因此在程序中我们要实现ActionListenrer与ListSelectionListener界
面,而ListSelectionEvent是属于Swing事件,因此程序中我们要import javax.swing.event package进来.
8-6:DefaultTableModel
我们曾提到过DefaultTableModel类,并说明了此类是继承AbstractTableModel抽象类而来,且实现了getColumnCount(),getRowCount()
与getValueAt()3个方法.因此在实际的使用上,DefaultTableModel比AbstractTableModel要来得简单许多,也较常被拿来使用
.DefaultTableModel内部使用Vector来使用表格的数据,若佻所要显示的表格格式是比较单纯的变化,笔者建议使用DefaultTableModel类会
来得方便也简单许多.若佻所要显示的数据模式非常复杂,例如我们所举的成绩表格外加学生选课信息等,像这类的表格通常显示的信息会因
人面异,因此使用AbstractTableModel会比较容易设计些.
下面是DefaultTableModel的构造函数:
DefaultTableModel():建立一个DefaultTableModel,里面没有任何数据.
DefaultTableModel(int numRows,int numColumns):建立一个指定行列数的DefaultTableModel.
DefaultTableModel(Object[][] data,Object[] columnNames):建立一个DefaultTableModel,输入数据格式为Object Array.系统会
自动调用setDataVector()方法来设置数据。
DefaultTableModel(Object[] columnNames,int numRows):建立一个DefaultTableModel,并具有Column Header名称与行数信息。
DefaultTableModel(Vector columnNames,int numRows):建立一个DefaultTableModel,并具有column Header名称与行数信息。
DefaultTableModel(Vector data,Vector columnNames):建立一个DefaultTableModel,输入数据格式为Vector.系统会自动调用
setDataVector()方法来设置数据。
DefaultTableModel类提供相当多好用的方法,如之前我们谈论过的getColumnCount(),getRowCount(),getValueAt(),isCellEditable()
setValueAt()等方法,均可直接使用。且DefaultTableModel也提供了addColumn()与addRow()等方法,可让我们随时增加表格的数据。下
面我们就举一个动态增加表格字段的例子:
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class AddRemoveCells implements ActionListener
{
JTable table = null;
DefaultTableModel defaultModel = null;
public AddRemoveCells()
{
JFrame f = new JFrame();
String[] name = {"字段 1","字段 2","字段 3","字段 4","字段 5"};
String[][] data = new String[5][5];
int value =1;
for(int i=0; i
for(int j=0; j data[i][j] = String.valueOf(value++);
}
defaultModel = new DefaultTableModel(data,name);
table=new JTable(defaultModel);
table.setPreferredScrollableViewportSize(new Dimension(400, 80));
JScrollPane s = new JScrollPane(table);
JPanel panel = new JPanel();
JButton b = new JButton("增加行");
panel.add(b);
b.addActionListener(this);
b = new JButton("增加列");
panel.add(b);
b.addActionListener(this);
b = new JButton("删除行");
panel.add(b);
b.addActionListener(this);
b = new JButton("删除列");
panel.add(b);
b.addActionListener(this);
Container contentPane = f.getContentPane();
contentPane.add(panel, BorderLayout.NORTH);
contentPane.add(s, BorderLayout.CENTER);
f.setTitle("AddRemoveCells");
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
/*要删除列必须使用TableColumnModel界面定义的removeColumn()方法。因此我闪先由JTable类的getColumnModel()方法取得
*TableColumnModel对象,再由TableColumnModel的getColumn()方法取得要删除列的TableColumn.此TableColumn对象当作是
*removeColumn()的参数。删除此列完毕后必须重新设置列数,也就是使用DefaultTableModel的setColumnCount()方法来设置。
*/
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("增加列"))
defaultModel.addColumn("增加列");
if(e.getActionCommand().equals("增加行"))
defaultModel.addRow(new Vector());
if(e.getActionCommand().equals("删除列"))
{
int columncount = defaultModel.getColumnCount()-1;
if(columncount >= 0)//若columncount<0代表已经没有任何列了。
{
TableColumnModel columnModel = table.getColumnModel();
TableColumn tableColumn = columnModel.getColumn(columncount);
columnModel.removeColumn(tableColumn);
defaultModel.setColumnCount(columncount);
}
}
if(e.getActionCommand().equals("删除行"))
{
int rowcount = defaultModel.getRowCount()-1;//getRowCount返回行数,rowcount<0代表已经没有任何行了。
if(rowcount >= 0)
{
defaultModel.removeRow(rowcount);
defaultModel.setRowCount(rowcount);//删除行比较简单,只要用DefaultTableModel的removeRow()方法即可。删除
//行完毕后必须重新设置列数,也就是使用DefaultTableModel的setRowCount()方法来设置。
}
}
table.revalidate();
}
public static void main(String args[]) {
new AddRemoveCells();
}
}
++ JTable的事件处理
8-7:JTable的事件处理
在前面的介绍中,我们了解了数种在不同组件上的事件处理。同样,在JTable的事件大致均针对表格内容的异操作处理,包括字段内容改变,列数增加
或减少,行数增加或减少,或是表格的结构改变等等。这些事件我们称为TableModelEvent事件。要处理
TableModelEvent事件我们必须实现TableModelListener界面,此界面定义了一个方法,那就是tableChanged(),为了处理这些事件的种种
情况,在AbstractTableModel类中提供了下列方法来提示TableModelListener:表格内容已经改动了,如下所示:
1.fireTableCellUpdated():发出表格中的某一个字段已经更改的事件信息。
2.fireTableChanged():发出表格已经改动的事件信息。
3.fireTableDataChanged():发出表格中的某字段已经更改的事件信息。
4.fireTableRowsDeleted():发出表格中的某几行已经删除的事件信息。
5.fireTableRowsInserted():发出表格中的已经新增某几行的事件信息。
6.fireTableRowsUpdated():发出表格中的某几行已经修改的事件信息。
7.fireTableStructureChanged():发出表格结构已经改变的事件信息,这里指的结构改变可能包括表格的列数已经改变。
在知道在表格中可能发生的事件后,我们要如何拦截这些事件的信息呢?在AbstractTableModel类中提供了一个注册listener的方法
:addTableModelListener().在加入TableModelListener之后,我们就可以依照不同的事件做不同的处理了。
先来看看下面的例子吧,这个例子主要是更改本章的ColumnModelTest.java范例,再加上一些功能。在这个范例中,我们针对用户对
表格所做的修改加以处理,如果改的项目是数字,包括“语文”,“数学”字段,则我们直接将修改的值累加至"总分"字段,并检查其是
否及格且在“及格”字段作修改;而当我们勾起"作弊"列的Check Box选项时,若原本总分应为及格者,则设置为不及格,且总分改成119
分。
import javax.swing.table.AbstractTableModel;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class TableEventHandle implements TableModelListener
{
JTable table = null;
MyTable mt = null;
JLabel label = null; //显示修改字段位置
public TableEventHandle() {
JFrame f = new JFrame();
mt=new MyTable();
mt.addTableModelListener(this);
table=new JTable(mt);
JComboBox c = new JComboBox();
c.addItem("Taipei");
c.addItem("ChiaYi");
c.addItem("HsinChu");
table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(c));
table.setPreferredScrollableViewportSize(new Dimension(550, 30));
JScrollPane s = new JScrollPane(table);
label = new JLabel("修改字段位置:");
f.getContentPane().add(s, BorderLayout.CENTER);
f.getContentPane().add(label, BorderLayout.SOUTH);
f.setTitle("TableEventHandle");
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void tableChanged(TableModelEvent e)
{
int row = e.getFirstRow();
int column = e.getColumn();
label.setText("修改字段位置:"+(row+1)+" 行 "+(column+1)+" 列");
boolean cheat =((Boolean)(mt.getValueAt(row,6))).booleanValue();
int grade1=((Integer)(mt.getValueAt(row,2))).intValue();
int grade2=((Integer)(mt.getValueAt(row,3))).intValue();
int total = grade1+grade2;
if(cheat)
{
if(total > 120)
mt.mySetValueAt(new Integer(119),row,4);
else
mt.mySetValueAt(new Integer(total),row,4);
mt.mySetValueAt(new Boolean(false),row,5);
}
else
{
if(total > 120)
mt.mySetValueAt(new Boolean(true),row,5);
else
mt.mySetValueAt(new Boolean(false),row,5);
mt.mySetValueAt(new Integer(total),row,4);
}
table.repaint();
}
public static void main(String args[]) {
new TableEventHandle();
}
}
class MyTable extends AbstractTableModel {
Object[][] p = {
{"阿呆", "Taipei",new Integer(66), new Integer(32), new Integer(98),
new Boolean(false),new Boolean(false)},
{"阿瓜", "ChiaYi",new Integer(85), new Integer(69), new Integer(154),
new Boolean(true),new Boolean(false)}};
String[] n = {"姓名","居住地","语文","数学","总分","及格","作弊"};
public int getColumnCount() {
return n.length;
}
public int getRowCount() {
return p.length;
}
public String getColumnName(int col) {
return n[col];
}
public Object getValueAt(int row, int col) {
return p[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
public void setValueAt(Object value, int row, int col) {
p[row][col] = value;
fireTableCellUpdated(row, col);
}
public void mySetValueAt(Object value, int row, int col) {
p[row][col] = value;
}
}
++ 文字输入组件的使用与介绍
9-1:认识Swing的文字输入组件:
Swing与文字输入有关的组件分别是JTextField、JPasswordField、JTextArea、JEditorPane与JTextPane.JTextField与
JPasswordField为单行的文本编辑器;JTextArea为多行的文本编辑器;JEditorPane可显示多种文件格式;JTextPane可设置文件各种
样式。这些组件都继承了JTextComponent为类,它们之间的关系如下:
|--JTextField--JPasswordField
|
JTextComponent|
|--JTextArea
|
|--JEditorPane--JTextPane
JTextComponent提供了相当多实用的方法,可使处理输入组件更为方便,例如copy(),paste(),cut(),getText(),setText()等
相当直觉的方法:另外还有设置是否可编辑(setEditable()),setSelectionEnd(),setSelectionStart())、设置或取得光标位置
(getCaretPosition(),setCaretPosition())等等,这些相当常用的方法你都可以在JTextComponent类中找到.
Swing的文字输入组件均以Document来当作数据模式,当输入组件的内容有所改变时,均是更改此Document的内容。因此你可
以将同一个Document内容以不同的输入组件来显示,这就是MVC概念的一个基本应用。Document为一个interface,你可以实现此界
面或利用java提供的默认类来构造文字输入组件。
|---implements-->AbstractDocument---extends->PlainDocument
|
Document |
|
|--extends-->StyleDocument---implements--->DefaultStyleDocument---extends--->HTMLDocument
AbstractDocument----extends-->DefaultStyleDocument
PlainDocument是一个实体类,已经实现了AbstractDocument与Document中的所有抽象方法,你可以用此类直接构造出JTextField
、JPasswordField与JTextArea组件;相同的,你可以使用DefaultStyledDocument构造出JTextPane组件,这些关系我们均会在下面
各节中提到。下面我们开始介绍各种文字输入组件的使用:
9-2:使用JTextField组件:
JTextField继承JTextComponent类,因此它也可以使用JTextComponent抽象类里面许多好用的方法,如copy(),paste(),setText()
,isEditable()等等。我们可以在很多地方使用JTextField,JTextField是一个单行的输入组件,那么有没有多行的输入组件呢?有
的,就是JTextArea,我们将在后面介绍.
JTextField构造函数:
JTextField()
JTextField(Document doc,String text,int columns):使用指定的文件存储模式建立一个新的JTextField并设置其初始化字符串和
字段长度。
JTextField(int columns):建立一个新的JTextField并设置其初始字段长度。
JTextField(String text):建立一个新的JTextField并设置其初始字字符串。
JTextField(String text,int columns):建立一个新的JTextField并设置其初始字符串和字段长度.
9-2-1:构造一般的JTextField组件:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextField1{
public static void main(String args[]) {
JFrame f = new JFrame("JTextField1");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1 = new JPanel();
p1.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.WEST; //设定Layout的位置
gbc.insets = new Insets(2,2,2,2); //设定与边界的距离(上,左,下,右)
p1.setBorder(BorderFactory.createTitledBorder("您的基本数据"));
JLabel l1 = new JLabel("姓名:");
JLabel l2 = new JLabel("性别:");
JLabel l3 = new JLabel("身高:");
JLabel l4 = new JLabel("体重:");
JTextField t1 = new JTextField();
JTextField t2 = new JTextField(2);
JTextField t3 = new JTextField("175cm");
JTextField t4 = new JTextField("50kg太瘦了",10);
gbc.gridy=1;
gbc.gridx=0;
p1.add(l1,gbc);
gbc.gridx=1;
p1.add(t1,gbc);
gbc.gridy=2;
gbc.gridx=0;
p1.add(l2,gbc);
gbc.gridx=1;
p1.add(t2,gbc);
gbc.gridy=3;
gbc.gridx=0;
p1.add(l3,gbc);
gbc.gridx=1;
p1.add(t3,gbc);
gbc.gridy=4;
gbc.gridx=0;
p1.add(l4,gbc);
gbc.gridx=1;
p1.add(t4,gbc);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
9-2-2:利用Document构造JTextField:
Document是一个interface,主要的功能是定义一些方法,让我们在使用所有与Text相关的组件时,能够将输入文字的内容加以
结构化或规格化。将文字内容结构化又是什么呢?举例来说,就好像一本书的内容,它的结构一定会有各个大章,在各章中又会分
成许多小节,小节内会再有各个小重点等等,这样的树状组件结构就是结构化的一种。由于这个interface定义了10几个方法,但是
在这里我们所会用到的只有少数几个方法,为了不让大家混淆,因此我们先列出这个interface常被使用到的方法,有兴趣的可查阅
java api文件:
void addDocumentListener(DocumentListener listener):增加DocumentListener,使组件具有处理DocumentEvent功能。
void addUndoableEditListener(UndoableEditListener listener):增加UndoableEditListener,使组件具有处理UndoableEditEv
Ent功能,当文件中的内容被修改时自动记忆可以被复原的内容。
String getText(int offset,int length):取得document中的文字内容。
void insertString(int offset,String str,AttributeSet a):将字符串加入到Text组件的内容中。
void removeDocumentListener(DocumentListener listener):移除DocumentListener.
void removeUndoableEditListener(UndoableEditListener listener):移除UndoableEditListener,使复原功能失效。
还记得我们一开始在介绍JTextField时所提到的构造函数吗?其中有一个JTextField的构造函数是这样子的:
JTextField(Document doc,String text,int columns):使用指定的文件存储模式建立一个新的JTextField并设置其初始
化字符串和字段长度。
因此我们必须实作Document所有的方法,才能利用Document构造出JTextField,这样的做法有点麻烦,因为我们之前有提到Document
的方法有数十种,但是我们要用到的却只有其中几种,若是要将全部的方法实作那是相当费时的做法。大家还记行我们前几章介绍
JList时,利用继承AbstractListModel的抽象类来构造JList吗?由于抽象类已经了许多接口的方法,所以当我们继承这个抽象类后
便不需要实作这些方法。同样的java在这里也提供了一个AbstractDocument的抽象类来供我们使用。不过在这里我们并不是要使用
AbstractDocument,因为java在这部份已经提供了一个实体类:PlainDocument.这个实体类继承AbstractDocument,也就是具备了所
有AbstractDocument的方法,所以我们只要直接继承PlainDocument这个实体类就能利用Document来构造JTextField.这种概念跟
JList或是JTable的模式结构均是相同的。我们来看下面的范例:
JTextField3.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextField3{
public static void main(String args[]) {
JFrame f = new JFrame("JTextField3");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1 = new JPanel();
//p1.setLayout(new GridLayout(4,2));
p1.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.WEST; //设定Layout的位置
gbc.insets = new Insets(2,2,2,2); //设定与边界的距离(上,左,下,右)
p1.setBorder(BorderFactory.createTitledBorder("您的基本数据"));
JLabel l1 = new JLabel("姓名:");
JLabel l2 = new JLabel("性别:");
JLabel l3 = new JLabel("身高:");
JLabel l4 = new JLabel("体重:");
JTextField t1 = new JTextField(new JTextField3_FixedLengthDocument(10),"",10);
JTextField t2 = new JTextField(new JTextField3_FixedLengthDocument(1),"",2);
JTextField t3 = new JTextField(new JTextField3_FixedLengthDocument(5),"",5);
JTextField t4 = new JTextField(new JTextField3_FixedLengthDocument(5),"",5);
gbc.gridy=1;
gbc.gridx=0;
p1.add(l1,gbc);
gbc.gridx=1;
p1.add(t1,gbc);
gbc.gridy=2;
gbc.gridx=0;
p1.add(l2,gbc);
gbc.gridx=1;
p1.add(t2,gbc);
gbc.gridy=3;
gbc.gridx=0;
p1.add(l3,gbc);
gbc.gridx=1;
p1.add(t3,gbc);
gbc.gridy=4;
gbc.gridx=0;
p1.add(l4,gbc);
gbc.gridx=1;
p1.add(t4,gbc);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
JTextField3_FixedLengthDocument.java
import javax.swing.*;
import javax.swing.text.*;
import java.awt.Toolkit;
public class JTextField3_FixedLengthDocument extends PlainDocument{
private int maxLength;
public JTextField3_FixedLengthDocument(int maxLength){
this.maxLength = maxLength;
}
public void insertString(int offset,String str,AttributeSet att) throws BadLocationException
{
if ( getLength() + str.length() > maxLength ){
Toolkit.getDefaultToolkit().beep();
}else{
super.insertString(offset,str,att);
}
}
}
9-2-3:JTextField的事件处理:
在JTextField类中有addActionListener()方法,可以检测到用户是否在JTextField上按下Enter键,就如同前面所介绍JButton按
下按钮时所产生的事件(Event)一样,我们来看下面这个范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextField4{
public static void main(String[] args){
JFrame f=new JFrame("JTextField4");
Container contentPane=f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1=new JPanel();
p1.setLayout(new GridLayout(2,2));
p1.setBorder(BorderFactory.createTitledBorder("JTextField事件处理范例"));
JLabel l1=new JLabel("输入");
JLabel l2=new JLabel("输入后,按下Enter==>");
final JLabel l3=new JLabel("");
final JTextField t1=new JTextField();
t1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
l3.setText(t1.getText());
}
});
p1.add(l1);
p1.add(t1);
p1.add(l2);
p1.add(l3);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
9-3:使用JPasswordField组件:
JPasswordField的类层次结构图:
java.lang.Object
--java.awt.Component
--javax.swing.JComponent
--javax.swing.text.JTextComponent
--javax.swing.JTextField
--javax.swing.JPasswordField
一般我们在网络中填写登录密码时,密码都会显示"*"号代表用户输入的字段,这样可避免用户输入的密码信息被旁人所偷窥。
而Swing中的JPasswordField就可以提供这样的功能。JPasswordField继承JTextField类,因此它也可以使用JTextField类里面许多
好用的方法,如addActionListener()、removeActionListener()、setHorizontalAlignment()等等。如同JTextField一样
JPasswordField也是一个单行的输入组件,不同的是JPasswordField多了屏蔽(Mask)的功能,也就是说在JPasswordField中的字符
都会以单一种的字符类型表现出来。
在使用JPasswordField之前,我们先看看它的构造函数:
JPasswordField()
JPasswordField(Document doc,String text,int columns):使用指定的文件存储模式建立一个新的JPasswordField并设置其初始化
字符串和字段长度。
JPasswordField(int columns):建立一个新的JPasswordField并设置其初始字段长度。
JPasswordField(String text):建立一个新的JPasswordField并设置其初始字字符串。
JPasswordField(String text,int columns):建立一个新的JPasswordField并设置其初始字符串和字段长度.
9-3-1:构造一般的JPasswordField组件:
JPasswordField的构造函数和JTextField的构造函数几乎一模本样,唯一不同的是在JPasswordField输入时字符会以屏蔽字符的
类型表示。我们来看下面这个范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JPasswordField1{
public static void main(String args[]) {
JFrame f = new JFrame("JPasswordField1");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1 = new JPanel();
//p1.setLayout(new GridLayout(4,2));
p1.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.WEST; //设定Layout的位置
gbc.insets = new Insets(2,2,2,2); //设定与边界的距离(上,左,下,右)
p1.setBorder(BorderFactory.createTitledBorder("您的基本数据"));
JLabel l1 = new JLabel("姓名:");
JLabel l2 = new JLabel("性别:");
JLabel l3 = new JLabel("身高:");
JLabel l4 = new JLabel("体重:");
JPasswordField t1 = new JPasswordField();
JPasswordField t2 = new JPasswordField(2);
JPasswordField t3 = new JPasswordField(" 175cm");
JPasswordField t4 = new JPasswordField(" 50kg太瘦了",10);
t1.setPreferredSize(t1.getPreferredSize());
gbc.gridy=1;
gbc.gridx=0;
p1.add(l1,gbc);
gbc.gridx=1;
p1.add(t1,gbc);
gbc.gridy=2;
gbc.gridx=0;
p1.add(l2,gbc);
gbc.gridx=1;
p1.add(t2,gbc);
gbc.gridy=3;
gbc.gridx=0;
p1.add(l3,gbc);
gbc.gridx=1;
p1.add(t3,gbc);
gbc.gridy=4;
gbc.gridx=0;
p1.add(l4,gbc);
gbc.gridx=1;
p1.add(t4,gbc);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
我们可以看到默认的字符串都以屏蔽字符"*"来表示,"*"字符是JPasswordField默认的屏蔽字符,我们可以利用JPasswordField
提供的setEchoChar()方法来改用其他字符来作为屏蔽字符。我们来看下面的范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JPasswordField2{
public static void main(String args[]) {
JFrame f = new JFrame("JPasswordField2");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(4,2));
p1.setBorder(BorderFactory.createTitledBorder("您的基本数据"));
JLabel l1 = new JLabel("姓名:");
JLabel l2 = new JLabel("性别:");
JLabel l3 = new JLabel("身高:");
JLabel l4 = new JLabel("体重:");
JPasswordField t1 = new JPasswordField(10);
JPasswordField t2 = new JPasswordField(2);
JPasswordField t3 = new JPasswordField(" 175cm");
JPasswordField t4 = new JPasswordField(" 50kg太瘦了",10);
t1.setEchoChar('#');
t2.setEchoChar('%');
t3.setEchoChar('&');
t4.setEchoChar('M');
p1.add(l1);
p1.add(t1);
p1.add(l2);
p1.add(t2);
p1.add(l3);
p1.add(t3);
p1.add(l4);
p1.add(t4);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
9-3-2:利用Document构造JPasswordField:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JPasswordField3{
public static void main(String args[]) {
JFrame f = new JFrame("JPasswordField3");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1 = new JPanel();
//p1.setLayout(new GridLayout(4,2));
p1.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.WEST; //设定Layout的位置
gbc.insets = new Insets(2,2,2,2); //设定与边界的距离(上,左,下,右)
p1.setBorder(BorderFactory.createTitledBorder("您的基本数据"));
JLabel l1 = new JLabel("姓名:");
JLabel l2 = new JLabel("性别:");
JLabel l3 = new JLabel("身高:");
JLabel l4 = new JLabel("体重:");
JPasswordField t1 = new JPasswordField(new JPasswordField3_OnlyNumberDocument(10),"",10);
JPasswordField t2 = new JPasswordField(new JPasswordField3_OnlyNumberDocument(1),"",2);
JPasswordField t3 = new JPasswordField(new JPasswordField3_OnlyNumberDocument(5),"",5);
JPasswordField t4 = new JPasswordField(new JPasswordField3_OnlyNumberDocument(5),"",5);
gbc.gridy=1;
gbc.gridx=0;
p1.add(l1,gbc);
gbc.gridx=1;
p1.add(t1,gbc);
gbc.gridy=2;
gbc.gridx=0;
p1.add(l2,gbc);
gbc.gridx=1;
p1.add(t2,gbc);
gbc.gridy=3;
gbc.gridx=0;
p1.add(l3,gbc);
gbc.gridx=1;
p1.add(t3,gbc);
gbc.gridy=4;
gbc.gridx=0;
p1.add(l4,gbc);
gbc.gridx=1;
p1.add(t4,gbc);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
import javax.swing.*;
import javax.swing.text.*;
import java.awt.Toolkit;
public class JPasswordField3_OnlyNumberDocument extends PlainDocument{
private int maxLength;
int result;
public JPasswordField3_OnlyNumberDocument(int maxLength){
this.maxLength = maxLength;
}
public void insertString(int offset,String str,AttributeSet att) throws BadLocationException
{
for(int i=0;i<=9;i++){
result = Integer.toString(i).compareTo(str);
if (result == 0){ //是数字才处理
if ( getLength() + str.length() > maxLength ){
Toolkit.getDefaultToolkit().beep();
}else{
super.insertString(offset,str,att);
}
}
}
}
}
9-4:使用JTextArea组件:
JTextArea的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JCompontent
--javax.swing.text.JTextComponent
--javax.swing.JTextArea
JTextArea继承JTextComponent为类,因此它也可以使用JTextComponent抽象类里面许多好用的方法,如compy(),paste(),
setText(),isEditable()等等。我们在前面有提到JTextArea是一个多行的输入组件,在这个组件中可以利用Enter来做换行的操作
。
在使用JTextArea之前,我们先看看JTextArea有哪些构造函数可以使用:
JTextArea的构造函数:
JTextArea():建立一个新的JTextArea.
JTextArea(Document doc):使用指定的文件存储模式建立一个新的JTextArea.
JTextArea(Document doc,String text,int row ,int columns):使用指定的文件存储模式建立一个新的JTextArea并设置其初始
字符串和列、字段长度。
JTextArea(int row,int columns):建立一个新的JTextArea并设置其初始列、字段长度。
JTextArea(String text):建立一个新的JTextArea并设置其初始字符串.
JTextArea(String text,int row,int columns):建立一个新的JTextArea并设置其初始字符串和列、字段长度。
9-4-1:构造JTextArea组件:
我们可以发现到JTextArea的构造函数和JTextField及JPasswordField的构造函数是相同雷同,而JTextArea多了一个字段的参数
值是因为JTextArea是二维的输入组件,在构造时不仅要设置字段长度也要设置行数。我们来看下面这个范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextArea1{
public static void main(String[] args){
JFrame f=new JFrame("JTextArea1");
Container contentPane=f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1=new JPanel();
p1.setLayout(new GridBagLayout());
GridBagConstraints gbc=new GridBagConstraints();
gbc.anchor=GridBagConstraints.WEST;
gbc.insets=new Insets(2,2,2,2);
p1.setBorder(BorderFactory.createTitledBorder("构造一般的JTextArea"));
JLabel l1=new JLabel("一:");
JLabel l2=new JLabel("二:");
JLabel l3=new JLabel("三:");
JLabel l4=new JLabel("四:");
JTextArea t1=new JTextArea();
JTextArea t2=new JTextArea(2,8);
JTextArea t3=new JTextArea("JTextArea3");
JTextArea t4=new JTextArea("JTextArea4",5,10);
t1.setText("JTextArea1");//setText()方法会将原来的内容清除
t2.append("JTextArea2");//append()方法会将设置的字符串接在原来JTextArea内容文字之后.
t4.setLineWrap(true);//设置换行
gbc.gridy=1;
gbc.gridx=0;
p1.add(l1,gbc);
gbc.gridx=1;
p1.add(t1,gbc);
gbc.gridy=2;
gbc.gridx=0;
p1.add(l2,gbc);
gbc.gridx=1;
p1.add(t2,gbc);
gbc.gridy=3;
gbc.gridx=0;
p1.add(l3,gbc);
gbc.gridx=1;
p1.add(t3,gbc);
gbc.gridy=4;
gbc.gridx=0;
p1.add(l4,gbc);
gbc.gridx=1;
p1.add(t4,gbc);
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
在JTextArea中我们可以使用setTabSize()方法设置[Tab]键的跳离距离,或是setFont()方法设置字体。当我们输入的文字超过
JTextArea的右边界及下边界时,会看不到接下来打的内容,那该怎么办呢?你可以使用JScrollPane使JTextArea具备滚动的能力,
或是搭配setLineWrap()方法就能让文字自动换行。JTextArea还提供一个setWrapStyleWord()方法,可以让换行的时候不会造成断
字的现象,这在Word或使用OutLook写信时都可以看到这个效果。例如我们在行尾中输入“自动换行”四个字,但此行最多只能在容
纳两个字,因此JTextArea会将此四个字均移到下一行,不会造成“自动”在上行,"换行"在下行的情形。这在处理英文输入上较为
重要,因为setWrapStyleWord()是利用空白当作是一个字输入的结果。我们来看下面的范例:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextArea2{
public static void main(String[] args){
JFrame f=new JFrame("JTextArea2");
Container contentPane=f.getContentPane();
contentPane.setLayout(new BorderLayout());
JPanel p1=new JPanel();
p1.setLayout(new GridLayout(1,1));
p1.setBorder(BorderFactory.createTitledBorder("构造TextArea-使用GridLayout,加ScrollBar"));
JTextArea t1=new JTextArea(5,25);
t1.setTabSize(10);
t1.setFont(new Font("标楷体",Font.BOLD,16));
t1.setLineWrap(true);//激活自动换行功能
t1.setWrapStyleWord(true);//激活断行不断字功能
p1.add(new JScrollPane(t1));//将JTextArea放入JScrollPane中,这样就能利用滚动的效果看到输入超过JTextArea高度的
//文字.
contentPane.add(p1);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
我们再举一个例子,使JTextArea具有copy、paste、cut的功能:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextArea3 implements ActionListener{
JTextArea textarea=null;
JButton b1,b2,b3;
public JTextArea3(){
JFrame f=new JFrame("JTextArea3");
Container contentPane=f.getContentPane();
contentPane.setLayout(new BorderLayout());
textarea=new JTextArea(10,15);
JScrollPane scrollPane=new JScrollPane(textarea);
JPanel panel=new JPanel();
panel.setLayout(new GridLayout(1,3));
b1=new JButton("Copy");
b1.addActionListener(this);
b2=new JButton("Paste");
b2.addActionListener(this);
b3=new JButton("Cut");
b3.addActionListener(this);
panel.add(b1);
panel.add(b2);
panel.add(b3);
contentPane.add(scrollPane,BorderLayout.CENTER);
contentPane.add(panel,BorderLayout.SOUTH);
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new JTextArea3();
}
public void actionPerformed(ActionEvent e){
if (e.getSource()==b1){
textarea.copy();
}
if (e.getSource()==b2){
textarea.paste();
}
if (e.getSource()==b3){
textarea.cut();
}
}
}
9-4-2:JTextArea的事件处理:
由于JTextArea是一个二维的输入组件,因此[Enter]键在JTextArea中代表的意义只是单纯的换行字符而不再是一个事件驱动的
切入点。那么我们该 如何来处理JTextArea的事件呢?还记得我们在前面介绍过Listener的机制吗?相同的,我们一样需要使用
Listener的机制来处理发生在JTextArea中的事件,只是不再是以前提到的ActionListener了。在JTextArea中使用的Listener有两
种,一个是UndoableEditListener,另一个是DocumentListener.UndoableEditListener interface是负责纪录JTextArea中所有操作
发生的顺序并且可以运行还原上一步的功能。这个功能在目前的软件中应用相当广泛,如文书编辑软件Word中的复原功能、小画家
中的复原功能,相信大家都有使用过。DocumentListener interface则是纪录发生在JTextArea中所有的事件(如键入字符、删除
字符、剪下、贴上)并将所有的事件以树状的层次式结构组织起来;也就是说当JTextArea中的内容有任何变动时,会DocumentEvent
,此时必须使用DocumentListener接口中的方法来处理此事件。我们来看下面这个范例,使JTextArea具有复原的功能:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*由于会使用到复原和事件驱动功能,因此需要将javax.swing.undo和javax.swing.event两个package包含进来
*/
import javax.swing.undo.*;
import javax.swing.event.*;
/*JTextArea4类继承JFrame类并实作UndoableEditListener interface.实作UndoableEditListener interface就必须要编写其中的
*undoableEditHappened().
*/
public class JTextArea4 extends JFrame implements UndoableEditListener{
private UndoableEdit edit;
private JTextArea jta;
private JTextArea message;
private JMenuItem undoitem;
private JMenuItem redoitem;
public JTextArea4(){
super("JTextArea4");
jta = new JTextArea();
jta.getDocument().addUndoableEditListener(this);//将JTextArea加入UndoableEditListener.
message = new JTextArea();
message.setEditable(false);//利用setEditable()方法将另一个JTextArea设置为不可编辑.
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1,1));
p1.setBorder(BorderFactory.createTitledBorder("Edit Area"));
p1.add(new JScrollPane(jta));
//--begin:分别将两个JTextArea通过JPanel放到JFrame中。
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(1,1));
p2.setBorder(BorderFactory.createTitledBorder("Message"));
p2.add(new JScrollPane(message));
getContentPane().setLayout(new GridLayout(2,1));
getContentPane().add(p1);
getContentPane().add(p2);
//--end
//建立目录菜单并放置到JFrame中.
JMenuBar bar = new JMenuBar();
JMenu theMenu = new JMenu("Edit");
undoitem = new JMenuItem("Undo");
redoitem = new JMenuItem("Redo");
theMenu.add(undoitem);
theMenu.add(redoitem);
bar.add(theMenu);
updateMenuItem();//构造目录菜单
setJMenuBar(bar);
setSize(300,300);
//采用inner class方式,分别构造菜单选项被点选后的运行操作。分别调用undo(),redo()方法来完成.
undoitem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
edit.undo();
updateMenuItem();//运行undo功能
message.append("- Undo -/n");
}
});
redoitem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
edit.redo();
updateMenuItem();//运行redo功能
message.append("- Redo -/n");
}
});
}//end of JTextArea4()
public void undoableEditHappened(UndoableEditEvent ev){
StringBuffer buf = new StringBuffer(200);
/*当用户在Text Area中有所操作时,就可以用getEdit()方法取得UndoableEdit对象,此对象纪录着刚刚用户的操作,因
*此可由些对象的undo()或redo()达到取消或复原的功能.
*/
edit = ev.getEdit();
buf.append("undoableEdit:");
buf.append(edit.getPresentationName());
buf.append("/n");
message.append(buf.toString());
updateMenuItem();
}//end of undoableEditHappened()
//判断是否此时是否可以运行undo或redo的功能,并且改变目录菜单的状态值.
public void updateMenuItem(){
if (edit != null){
undoitem.setEnabled(edit.canUndo());
redoitem.setEnabled(edit.canRedo());
undoitem.setText(edit.getUndoPresentationName());
redoitem.setText(edit.getRedoPresentationName());
}else{
undoitem.setEnabled(false);
redoitem.setEnabled(false);
undoitem.setText("Undo");
redoitem.setText("Redo");
}
}//end of updateMenu()
public static void main(String args[]) {
JFrame f = new JTextArea4();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.show();
}//end of main()
}//end of class JTextArea4
我们在前面提到Enter键在JTextArea中不再是事件驱动的切入点,因此我们要利用Listener的机制来控制JTextArea的事件驱动
。但是,我们要怎么样知道在JTextArea中的数据内容呢?这就要了解JTextArea的存储模式了,JTextArea把输入区内的每一行当成
一个独立的单无(Element),并依照Document内规划的树状结构来存储,也就是说在JTextArea的第一行属于Element 0、第二行属于
Element 1、第三行属于Element 2等等。不论我们在费心的去处理。接下来我们来看看,Element和DocumentListener interface的
用法。我们改写JTextArea4.java加入DocumentListener,将程序存储为JTextArea5.java.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.undo.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class JTextArea5 extends JFrame implements UndoableEditListener,DocumentListener{
private UndoableEdit edit;
private JTextArea jta;
private JTextArea message;
private JMenuItem undoitem;
private JMenuItem redoitem;
public JTextArea5(){
super("JTextArea");
jta=new JTextArea();
jta.getDocument().addUndoableEditListener(this);
jta.getDocument().addDocumentListener(this);
message = new JTextArea();
message.setEditable(false);
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1,1));
p1.setBorder(BorderFactory.createTitledBorder("Edit Area"));
p1.add(new JScrollPane(jta));
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(1,1));
p2.setBorder(BorderFactory.createTitledBorder("Message"));
p2.add(new JScrollPane(message));
getContentPane().setLayout(new GridLayout(2,1));
getContentPane().add(p1);
getContentPane().add(p2);
JMenuBar bar = new JMenuBar();
JMenu theMenu = new JMenu("Edit");
undoitem = new JMenuItem("Undo");
redoitem = new JMenuItem("Redo");
theMenu.add(undoitem);
theMenu.add(redoitem);
bar.add(theMenu);
updateMenuItem();
setJMenuBar(bar);
setSize(300,300);
undoitem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
edit.undo();
updateMenuItem();
message.append("- Undo -/n");
}
});
redoitem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
edit.redo();
updateMenuItem();
message.append("- Redo -/n");
}
});
} //end of JTextArea5
public void undoableEditHappened(UndoableEditEvent ev){
StringBuffer buf = new StringBuffer(200);
edit = ev.getEdit();
buf.append("undoableEdit:");
buf.append(edit.getPresentationName());
buf.append("/n");
message.append(buf.toString());
updateMenuItem();
}//end of undoableEditHappened()
public void updateMenuItem(){
if (edit != null){
undoitem.setEnabled(edit.canUndo());
redoitem.setEnabled(edit.canRedo());
undoitem.setText(edit.getUndoPresentationName());
redoitem.setText(edit.getRedoPresentationName());
}else{
undoitem.setEnabled(false);
redoitem.setEnabled(false);
undoitem.setText("Undo");
redoitem.setText("Redo");
}
}//end of updateMenu()
public void showDE(DocumentEvent de){
StringBuffer debuf=new StringBuffer(100);
debuf.append(de.getType());
debuf.append("Offset:");
debuf.append(de.getOffset());
debuf.append("Length:");
debuf.append(de.getLength());
Element Eroot=jta.getDocument().getDefaultRootElement();
DocumentEvent.ElementChange Echange=de.getChange(Eroot);
if (Echange==null) {
debuf.append("(No Element Change)");
}else{
debuf.append("Element Change:index");
debuf.append("Echange.getIndex()");
}
debuf.append("/n");
message.append(debuf.toString());
}
public void changedUpdate(DocumentEvent de){
showDE(de);
}
public void insertUpdate(DocumentEvent de){
showDE(de);
}
public void removeUpdate(DocumentEvent de){
showDE(de);
}
public static void main(String[] args){
JFrame f=new JTextArea5() ;
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
f.show();
}
}
9-5:使用JEditorPane组件:
JEditorPane的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.text.JTextComponent
--javax.swing.JEditorPane
JEditorPane继承JTextComponent类,因此它也可以使用JTextComponent抽象类里面的方法。JEditorPane的最主要功能在于展
现不同类型的文件格式内容。JEditorPane支持的文件类型有三种:第一种是纯文本类型,其类型的表示法为"text/plain",这种类型
的文件就是我们最常使用的txt文件,这类型的文件可以用记事本或WordPad等文书编辑软件来编辑。第二种是RTF类型,其表示法
为"text/rtf",这种类型的文件特色是能对文字内容做字体缩放、变形、上色等特殊效果。第三类是HTML类型,也就是我们在网络上
所浏览的网页类型,其表示法为"text/html",这类文件的特色相信大家都非常的清楚,除了在对字体效果的表现之外还具有在文件
内加入图片、超级链接等相关功能。但是JEditorPane并不是一个全功能的Web Browser,它仅能支持简单的HTML语法.JEditorPane支
持HTML类型的文件最主要的用途是用来制作在线辅助说明文件。
JEditorPane构造函数:
JEditorPane():建立一个新的JEditorPane.
JEditorPane(String url):以详细的URL字符串为基础来建立一个JEditorPane。
JEditorPane(String type,String text):建立一个被指定字符串text并指定初始化JEditorPane的类型。
JEditorPane(URL initialPage):以详细的URL字符串当作输入值来建立一个JEditorPane.
9-5-1:构造JEditorPane组件:
我们将一个HTML文件放在构造完成的JEditPane中:
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.awt.event.*;
public class JEditorPane1{
public static void main(String[] args){
JEditorPane editPane=null;
try{
File file=new File("docs/JEditorPane_1.html");
String str=file.getAbsolutePath();//取得文件位置的绝对路径
str="file:"+str;//将绝对路径合成一完整的输入字符串
/*利用setPage()方法将字符串中路径所指的文件加载JEditorPane.
*在setPage()方法中,输入的数据是String类型的字符串,其实这样的构造方式等同于利用JEditorPane的另一个构造函数
*JEditorPane(String str)来构造。因此如果我们将下面两行程序改写如下行:
* editPane=new JEditorPane(str);
*会得到相同的效果,所以我们就不再对此种构造方式再多加说明.
*/
editPane=new JEditorPane();//构造一个空的JEditorPane
editPane.setPage(str);
}catch(IOException ioe){
ioe.printStackTrace(System.err);
System.exit(0);
}
/*利用setEditable()方法将JEditorPane设为不可编辑.请注意,这行是相当重要的,若是我们将这个方法设为true,我们将会
*失去HTML文件本身的特性,如超级链接的功能等等。因此我们在使用下面JEditorPane2的例子时,一般都会将编辑的功能取
*消(设置false).目前这个超级链接功能并没有作用,这部份将在JEditorPane的事件处理中介绍.
*/
editPane.setEditable(false);
JFrame f=new JFrame("JEditorPane1");
f.setContentPane(new JScrollPane(editPane));
f.setSize(200,200);
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
我们在前面提到JEditorPane支持三种类型的文件格式,在上面的例子里我们并没有看到设置文件格式的步骤,那是因为在上面
的构造方法中系统会依照输入文件名称来自动判别文件类型。若是我们想要自己设置文件类型可利用setContentType()方法,或是
直接在JEditorPane构造函数中设置。如下面这个范例:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
public class JEditorPane2{
public static void main(String[] args){
String str=new String("This is a test./nthis is Line2!/nThis is Line 3!");
JEditorPane editPane=new JEditorPane("text/plain",str);
editPane.setEditable(false);
JFrame f=new JFrame("JEditorPane2");
f.setContentPane(new JScrollPane(editPane));
f.pack();
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
以URL类当作JEditPane的参数来构造,但是要注意的地方是使用这种方式来构造里,计算机要连接上局域网络或网际网络不然
程序会找不到URL指定的位置而产生Exception使得程序无法动作.我们来看下面的范例吧!
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
public class JEditorPane3{
public static void main(String[] args){
JEditorPane editPane=null;
try{
URL address=new URL("http://www.sina.com.cn");
editPane=new JEditorPane(address);
}catch(MalformedURLException e){
System.out.println("Malformed URL:"+e);
}catch(IOException e){
System.out.println("IOException:"+e);
}
editPane.setEditable(false);
JFrame f=new JFrame("JEditorPane3");
f.setContentPane(new JScrollPane(editPane));
f.setSize(200,250);
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
9-5-2:JEditorPane的事件处理:
在JEditorPane文件中最常用到事件处理的部份就是HTML文件,那是因为HTML文件本身具有超级链接的功能来做文章链接的用途
。大家还记得我们这一节的第一个范例吗?我们不是加载了一份HTML文件到JEditorPane中吗?虽然画面上都有确实的将超级链接和
图片信息展现出来,可是你有没有发现当你想要点选超级链接的地方时却没有反应呢?那是因为我们并没有在JEditorPane中加入事
件处理机制的缘故。我们改写JEditorPane1.java加入事件处理机制,使JEditorPane具有正常的超链接功能。如下范例:
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.awt.event.*;
public class JEditorPane4{
public static void main(String[] args){
JEditorPane editPane = null;
try{
File thef = new File ("docs/JEditorPane_1.html");
String str = thef.getAbsolutePath();
str = "file:"+str;
editPane = new JEditorPane();
editPane.setPage(str);
}
catch(IOException ioe){
ioe.printStackTrace(System.err);
System.exit(0);
}
editPane.setEditable(false);
final JEditorPane thePane = editPane;
//采用inner class的方式编写触发超级链接事件时的对应操作类
editPane.addHyperlinkListener(new HyperlinkListener(){
public void hyperlinkUpdate(HyperlinkEvent hle){//覆写hyperlinkUpdate()方法,当超级链接事件触发时会进入这
//个区段运行.
try{
//判断是否为超级链接运行操作。若操作为真,则将新的HTML文件放到JEditorPane中,
//操作为(thePane.setPage(hle.getURL());)
if (hle.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
}
catch(IOException ioe){
ioe.printStackTrace(System.err);
}
}
});
JFrame f = new JFrame("JEditorPane4");
f.setContentPane(new JScrollPane(editPane));
f.setSize(200,250);
f.show();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}//end of main()
}//end of class JEditPane1
另外,若是我们是在纯文字模式(Plain Text)或RTF模式(RTF Text)下需要事件处理模式又该怎么办呢?你还记得我们在
JTextArea中是如何加入事件处理模式的吗?没错!在JEditorPane中也是相同的做法,也就是利用DocumentListener interface的
机制来处理,由于做法相当类似,因此我们就不在这里重复的说明.
9-6:使用JTextPane组件:
JTextPane的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.text.JTextComponent
--javax.swing.JEditorPane
--javax.swing.JTextPane
我们在前面有介绍过JTextArea类,虽然JTextArea在某些功能上已经能够满足我们的需求,但是当我们想再加入更多的变化时
(如文字加入色彩、插入图片...)就会发现JTextArea类根本无法做到。要做到这些功能,我们必须使用JEditorPane的子类:
JTextpane。JTextPane提供了许多对文字的处理,如改变颜色、字体缩放、文字风格、加入图片等。我们先来看看JTextPane的构
造方法:
JTextPane构造函数:
JTextPane():建立一个新的JTextPane.
JTextPane(StyledDocument doc):以指定的文件模式建立一个新的JTextPane.
9-6-1:JTextPane的特性:
相信大家都有用过Word来写过报告或文章,那么你一定会知道我们在Word中可以对文章中的文字做很多的变化,这些变化都是
属于文字的“属性”变化。由于在JTextPane中产生的效果几乎都是由属性的变化而来,所以改变属性的类组件在JTextpane中是少
不了的。因此在介绍如何构造JTextPane之前,我们要先介绍两个在JTextPane中常用到属性类:
SimpleAttributeSet和StyleConstant.
属性的变化原本是利用AttributeSet interface来处理的,但是这个interface中包含了太多的方法,若是我们直接实作
AttributeSet interface那就需要实作此interface里所有的方法,这对编写程序来说并不是一个很理想的做法;而java另外提供了
SimpleAttributeSet类,实作了AttributeSet interface.因此,只要我们直接使用SimpleAttributeSet类就能具备AttributeSet
interface的所有功能,而不用一个个的编写AttributeSet中的方法。另外StyleConstant类则是提供AttributeSet类许多常用的属
性键值(Attribute Key)和方法来设置或取得JTextPane内容的状态。在StyleConstant类中包含了许多的常用的属性设置,包括本文
与边界空白区段设置、文字字体/大小/类型设置、背景颜色设置等。利用这两个类来辅助设计JTextPane便使JTextPane有更丰富
的内容变化。
JTextPane是专为文字和版面处理设计的组件。JTextPane对可输入区域内容的设计概念是一个类似Word的设计概念,也就是说在
JTextPane中的文字结构是有段落概念的。“段落”的概念就是以[Enter]键为每一段落的分界点,每按一次[Enter]键就增加一个段
落。记得我们在JTextArea中提过的Element存储模式吗?在JTextPane中也是采用相同的做法,但是差别在于规划存储的方式不同。
在JTextArea中并没有分段落,只是单纯的以[Enter]键当作存储成两个Element的分界。而在JTextPane则是以整个编辑区哉为根节
点,每个段落为枝节点 ,每个字符为叶节点来存储文件。也因为JTextPane是采用这样的方式来存储数据,因此在JTextPane中也可
以像Word文件一样将各个段落设置成不同的属性,如第一段为斜体字、字体大小为14号字、粗体字,第二段为斜体字、字体颜色为
蓝色、向左边界缩排2厘米等;另外,我们还可以设置JTextPane编辑区内输入的文字与各个边界间的距离。由这些功能看来,对于一
个TextComponent来说JTextPane是一个具有相当多实用功能的组件。
9-6-2:构造JTextPane组件:
在了解JTextPane的各项特性之后,我们现在马上来看JTextPane可以呈现什么样的效果,在下面这个例子中我们将对JTextPane
区域内的文字设置颜色、粗斜体、与底线等相关属性。
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.awt.*;
public class JTextPane1{
private JTextPane textPane;
public JTextPane1(){
textPane=new JTextPane();
textPane.setBackground(Color.black);
textPane.setEditable(false);
}
public void setYellow_Bold_20(String str){
SimpleAttributeSet attrset=new SimpleAttributeSet();
StyleConstants.setForeground(attrset,Color.yellow);
StyleConstants.setBold(attrset,true);
insert(str,attrset);
}
public void setBlue_Italic_Bold_22(String str){
SimpleAttributeSet attrset=new SimpleAttributeSet();
StyleConstants.setForeground(attrset,Color.blue);
StyleConstants.setItalic(attrset,true);
StyleConstants.setFontSize(attrset,24);
insert(str,attrset);
}
public void setRed_UnderLine_Italic_24(String str){
SimpleAttributeSet attrset=new SimpleAttributeSet();
StyleConstants.setForeground(attrset,Color.red);
StyleConstants.setUnderline(attrset,true);
StyleConstants.setItalic(attrset,true);
StyleConstants.setFontSize(attrset,24);
insert(str,attrset);
}
//这个方法最主要的用途是将字符串插入到JTextPane中。
public void insert(String str,AttributeSet attrset){
Document docs=textPane.getDocument();//利用getDocument()方法取得JTextPane的Document instance.0
str=str+"/n";
try{
docs.insertString(docs.getLength(),str,attrset);
}catch(BadLocationException ble){
System.out.println("BadLocationException:"+ble);
}
}
public Component getComponent(){
return textPane;
}
public static void main(String[] args){
JTextPane1 pane=new JTextPane1();
pane.setYellow_Bold_20("This is Line 1,yellow,Bold,Size 20");
pane.setBlue_Italic_Bold_22("This is Line 2,blue,Italic,Bold,Size 22");
pane.setRed_UnderLine_Italic_24("This is Line 3,red,UnderLine,Italic,Size 24");
JFrame f=new JFrame("JTextPane1");
f.getContentPane().add(pane.getComponent());
f.setSize(450,180);
f.show();
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
}
若你想在JTextPane上置入图形或其他组件(如表格或按钮),你可以分别使用JTextPane所提供的insetIcon()与insertComponent()
方法来达到这个效果。
至于另外一种JTextPane的构造方式和JTextArea一样,差别在于JTextArea是采用Document interface而JTextPane是采用...
++ 树(Tree)的使用与介绍
10-1:使用JTree组件:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JTree
JTree构造函数:
JTree():建立一棵系统默认的树。
JTree(Hashtable value):利用Hashtable建立树,不显示root node(根节点).
JTree(Object[] value):利用Object Array建立树,不显示root node.
JTree(TreeModel newModel):利用TreeModel建立树。
JTree(TreeNode root):利用TreeNode建立树。
JTree(TreeNode root,boolean asksAllowsChildren):利用TreeNode建立树,并决定是否允许子节点的存在.
JTree(Vector value):利用Vector建立树,不显示root node.
范例:
InitalTree.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class InitalTree{
public InitalTree(){
JFrame f=new JFrame("TreeDemo");
Container contentPane=f.getContentPane();
JTree tree=new JTree();
JScrollPane scrollPane=new JScrollPane();
scrollPane.setViewportView(tree);
contentPane.add(scrollPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new InitalTree();
}
}
10-2:以Hashtable构造JTree:
上面的例子对我们并没有裨的帮助,因为各个节点的数据均是java的默认值,而非我们自己设置的。因此我们需利用其他JTree
构造函数来输入我们想要的节点数据。以下范例我们以Hashtable当作JTree的数据输入:
范例:TreeDemo1.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class TreeDemo1{
public TreeDemo1(){
JFrame f=new JFrame("TreeDemo1");
Container contentPane=f.getContentPane();
String[] s1={"公司文件","个人信件","私人文件"};
String[] s2={"本机磁盘(C:)","本机磁盘(D:)","本机磁盘(E:)"};
String[] s3={"奇摩站","职棒消息","网络书店"};
Hashtable hashtable1=new Hashtable();
Hashtable hashtable2=new Hashtable();
hashtable1.put("我的公文包",s1);
hashtable1.put("我的电脑",s2);
hashtable1.put("收藏夹",hashtable2);
hashtable2.put("网站列表",s3);
Font font = new Font("Dialog", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
/**定义widnows界面**/
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
try{
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
}catch(Exception el){
System.exit(0);
}
/**定义widnows界面**/
JTree tree=new JTree(hashtable1);
JScrollPane scrollPane=new JScrollPane();
scrollPane.setViewportView(tree);
contentPane.add(scrollPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new TreeDemo1();
}
}
纯XP界面的设置:
10-3:以TreeNode构造JTree:
JTree上的每一个节点就代表一个TreeNode对象,TreeNode本身是一个Interface,里面定义了7个有关节点的方法,例如判断是否
为树叶节点、有几个子节点(getChildCount())、父节点为何(getparent())等等、这些方法的定义你可以在javax.swing.tree的
package中找到,读者可自行查阅java api文件。在实际的应用上,一般我们不会直接实作此界面,而是采用java所提供的
DefaultMutableTreeMode类,此类是实作MutableTreeNode界面而来,并提供了其他许多实用的方法。MutableTreeNode本身也是一
个Interface,且继承了TreeNode界面此类主要是定义一些节点的处理方式,例如新增节点(insert())、删除节点(remove())、设置
节点(setUserObject())等。整个关系如下图:
TreeNode----extends--->MutableTreeNode---implements---DefaultMutableTreeNode
接下来我们来看如何利DefaultMutableTreeNode来建立JTree,我们先来看DefaultMutableTreeNode的构造函数:
DefaultMutableTreeNode构造函数:
DefaultMutableTreeNode():建立空的DefaultMutableTreeNode对象。
DefaultMutableTreeNode(Object userObject):建立DefaultMutableTreeNode对象,节点为userObject对象。
DefaultMutableTreeNode(Object userObject,Boolean allowsChildren):建立DefaultMutableTreeNode对象,节点为userObject对
象并决定此节点是否允许具有子节点。
以下为利用DefaultMutableTreeNode建立JTree的范例:TreeDemo2.java
此程序"资源管理器"为此棵树的根节点.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeDemo2{
public TreeDemo2(){
JFrame f=new JFrame("TreeDemo2");
Container contentPane=f.getContentPane();
DefaultMutableTreeNode root=new DefaultMutableTreeNode("资源管理器");
DefaultMutableTreeNode node1=new DefaultMutableTreeNode("我的公文包");
DefaultMutableTreeNode node2=new DefaultMutableTreeNode("我的电脑");
DefaultMutableTreeNode node3=new DefaultMutableTreeNode("收藏夹");
DefaultMutableTreeNode node4=new DefaultMutableTreeNode("Readme");
root.add(node1);
root.add(node2);
root.add(node3);
root.add(node4);
DefaultMutableTreeNode leafnode=new DefaultMutableTreeNode("公司文件");
node1.add(leafnode);
leafnode=new DefaultMutableTreeNode("私人文件");
node1.add(leafnode);
leafnode=new DefaultMutableTreeNode("个人信件");
leafnode=new DefaultMutableTreeNode("本机磁盘(C:)");
node2.add(leafnode);
leafnode=new DefaultMutableTreeNode("本机磁盘(D:)");
node2.add(leafnode);
leafnode=new DefaultMutableTreeNode("本机磁盘(E:)");
node2.add(leafnode);
DefaultMutableTreeNode node31=new DefaultMutableTreeNode("网站列表");
node3.add(node31);
leafnode=new DefaultMutableTreeNode("奇摩站");
node31.add(leafnode);
leafnode=new DefaultMutableTreeNode("职棒消息");
node31.add(leafnode);
leafnode=new DefaultMutableTreeNode("网络书店");
node31.add(leafnode);
JTree tree=new JTree(root);
JScrollPane scrollPane=new JScrollPane();
scrollPane.setViewportView(tree);
contentPane.add(scrollPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new TreeDemo2();
}
}
10-4:以TreeModel构造JTree.
除了以节点的观念(TreeNode)建立树之外,你可以用data model的模式建立树。树的data model称为TreeModel,用此模式的好处
是可以触发相关的树事件,来处理树可能产生的一些变动。TreeModel是一个interface,里面定义了8种方法;如果你是一个喜欢自己
动手做的人,或是你想显示的数据格式很复杂,你可以考虑直接实作TreeModel界面中所定义的方法来构造出JTree.TreeModel界面
的方法如下所示:
TreeModel方法:
void addTreeModelListener(TreeModelListener l):增加一个TreeModelListener来监控TreeModelEvent事件。
Object getChild(Object parent,int index):返回子节点。
int getChildCount(Object parent):返回子节点数量.
int getIndexOfChild(Object parent,Object child):返回子节点的索引值。
Object getRoot():返回根节点。
boolean isLeaf(Object node):判断是否为树叶节点。
void removeTreeModelListener(TreeModelListener l):删除TreeModelListener。
void valueForPathChanged(TreePath path,Object newValue):当用户改变Tree上的值时如何应对。
你可以实作出这8种方法,然后构造出自己想要的JTree,不过在大部份的情况下我们通常不会这样做,毕竟要实作出这8种方法不
是件很轻松的事,而且java本身也提供了一个默认模式,叫做DefaultTreeModel,这个类已经实作了TreeModel界面,也另外提供许
多实用的方法。利用这个默认模式,我们便能很方便的构造出JTree出来了。下面为DefaultTreeModel的构造函数与范例:
DefaultTreeModel构造函数:
DefaultTreeModel(TreeNode root):建立DefaultTreeModel对象,并定出根节点。
DefaultTreeModel(TreeNode root,Boolean asksAllowsChildren):建立具有根节点的DefaultTreeModel对象,并决定此节点是否允
许具有子节点。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;//组件的下载网址http://www.incors.com/lookandfeel/
/*将alloy.jar放在c:/j2sdk1.4.0/jre/lib/ext/目录下.
*/
public class TreeDemo3
{
public TreeDemo3()
{
JFrame f = new JFrame("TreeDemo");
Container contentPane = f.getContentPane();
DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器");
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的公文包");
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑");
DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹");
DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
DefaultTreeModel treeModel = new DefaultTreeModel(root);
/*DefaultTreeModel类所提供的insertNodeInto()方法加入节点到父节点的数量.
*利用DefaultMutableTreeNode类所提供的getChildCount()方法取得目前子节点的数量.
*/
treeModel.insertNodeInto(node1, root, root.getChildCount());
treeModel.insertNodeInto(node2, root, root.getChildCount());
treeModel.insertNodeInto(node3, root, root.getChildCount());
treeModel.insertNodeInto(node4, root, root.getChildCount());
DefaultMutableTreeNode leafnode = new
DefaultMutableTreeNode("公司文件");
//DefaultTreeModel类所提供的insertNodeInto()方法加入节点到父节点的数量.
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("个人信件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("私人文件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(C:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(D:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(E:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表");
treeModel.insertNodeInto(node31, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("奇摩站");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("职棒消息");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("网络书店");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
try {
LookAndFeel alloyLnF = new AlloyLookAndFeel();
UIManager.setLookAndFeel(alloyLnF);
} catch (UnsupportedLookAndFeelException ex) {
// You may handle the exception here
}
// this line needs to be implemented in order to make JWS work properly
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
//以TreeModel建立JTree。
JTree tree = new JTree(treeModel);
/*改变JTree的外观**/
tree.putClientProperty("JTree.lineStyle","Horizontal");
/*改变JTree的外观**/
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(tree);
contentPane.add(scrollPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
new TreeDemo3();
}
}
10-5:改变JTree的外观:
你可以使用JComponent所提供的putClientProperty(Object key,Object value)方法来设置java默认的JTree外观,设置方式共有
3种:
1.tree.putClientProperty("JTree.lineStyle","None"):java默认值。
2.tree.putClientProperty("JTree.lineStyle","Horizontal"):使JTree的文件夹间具有水平分隔线。
3.tree.putClientProperty("JTree.lineStyle","Angled"):使JTree具有类似Windows文件管理器的直角连接线。
具体怎样做,可看上例.
10-6:更换JTree节点图案:
JTree利用TreeCellRenderer界面来运行绘制节点的工作,同样的,你不需要直接支实作这个界面所定义的方法,因为java本身提
供一个已经实作好的类来给我们使用,此类就是DefaultTreeCellRenderer,你可以在javax.swing.tree package中找到此类所提供
的方法。下面为使用DefaultTreeCellRenderer更改节点图案的一个例子:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
public class TreeDemo4{
public TreeDemo4(){
JFrame f=new JFrame("TreeDemo");
Container contentPane=f.getContentPane();
DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器");
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的公文包");
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑");
DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹");
DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
DefaultTreeModel treeModel = new DefaultTreeModel(root);
treeModel.insertNodeInto(node1, root, root.getChildCount());
treeModel.insertNodeInto(node2, root, root.getChildCount());
treeModel.insertNodeInto(node3, root, root.getChildCount());
treeModel.insertNodeInto(node4, root, root.getChildCount());
DefaultMutableTreeNode leafnode = new
DefaultMutableTreeNode("公司文件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("个人信件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("私人文件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(C:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(D:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(E:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表");
treeModel.insertNodeInto(node31, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("奇摩站");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("职棒消息");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("网络书店");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
try {
LookAndFeel alloyLnF = new AlloyLookAndFeel();
UIManager.setLookAndFeel(alloyLnF);
} catch (UnsupportedLookAndFeelException ex) {
// You may handle the exception here
}
// this line needs to be implemented in order to make JWS work properly
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
JTree tree = new JTree(treeModel);
tree.setRowHeight(20);
DefaultTreeCellRenderer cellRenderer=(DefaultTreeCellRenderer)tree.getCellRenderer();
cellRenderer.setLeafIcon(new ImageIcon("..//icons//leaf.gif"));
cellRenderer.setOpenIcon(new ImageIcon("..//icons//open.gif"));
cellRenderer.setClosedIcon(new ImageIcon("..//icons//close.gif"));
cellRenderer.setFont(new Font("宋体",Font.PLAIN,12));//设置字体.
cellRenderer.setBackgroundNonSelectionColor(Color.white);
cellRenderer.setBackgroundSelectionColor(Color.yellow);
cellRenderer.setBorderSelectionColor(Color.red);
/*设置选时或不选时,文字的变化颜色
*/
cellRenderer.setTextNonSelectionColor(Color.black);
cellRenderer.setTextSelectionColor(Color.blue);
JScrollPane scrollPane=new JScrollPane();
scrollPane.setViewportView(tree);
contentPane.add(scrollPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
new TreeDemo4();
}
}
Window Xp界面:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
public class TreeDemo3
{
public TreeDemo3()
{
//设置成Alloy界面样式
try {
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
LookAndFeel alloyLnF = new AlloyLookAndFeel();
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel(alloyLnF);
} catch (UnsupportedLookAndFeelException ex) {
// You may handle the exception here
}
// this line needs to be implemented in order to make JWS work properly
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
//JDialog.setDefaultLookAndFeelDecorated(true);
JFrame f = new JFrame("firstTree");
Container contentPane = f.getContentPane();
// if (contentPane instanceof JComponent) {
// ((JComponent) contentPane).setMinimumSize(new Dimension(100, 100));
//}
// Container contentPane = f.getContentPane();
DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器");
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的公文包");
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑");
DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹");
DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
DefaultTreeModel treeModel = new DefaultTreeModel(root);
treeModel.insertNodeInto(node1, root, root.getChildCount());
treeModel.insertNodeInto(node2, root, root.getChildCount());
treeModel.insertNodeInto(node3, root, root.getChildCount());
treeModel.insertNodeInto(node4, root, root.getChildCount());
DefaultMutableTreeNode leafnode = new
DefaultMutableTreeNode("公司文件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("个人信件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("私人文件");
treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(C:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(D:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
leafnode = new DefaultMutableTreeNode("本机磁盘(E:)");
treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表");
treeModel.insertNodeInto(node31, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("奇摩站");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("职棒消息");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
leafnode = new DefaultMutableTreeNode("网络书店");
treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
JTree tree = new JTree(treeModel);
/*改变JTree的外观**/
// tree.putClientProperty("JTree.lineStyle","Horizontal");
/*改变JTree的外观**/
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(tree);
contentPane.add(scrollPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
new TreeDemo3();
}
}
10-7:JTree的事件处理模式:
在此节中,我们将详细介绍JTree两个常用的事件与处理,分别是TreeModeEvent与TreeSelectionEvent.
10-7-1:处理TreeModeEvent事件:
当树的结构上有任何改变时,例如节点值改变了、新增节点、删除节点等,都会TreeModelEvent事件,要处理这样的事件必须实
作TreeModelListener界面,此界面定义了4个方法,如下所示:
TreeModelListener方法:
Void treeNodesChanged(TreeModelEvent e):当节点改变时系统就会云调用这个方法。
Void treeNodesInserted(TreeModelEvent e):当新增节时系统就会去调用这个方法。
Void treeNodesRemoved(TreeModeEvent e):当删除节点时系统就会去调用这个方法。
Void treeStructureChanged(TreeModelEvent e):当树结构改变时系统就会去调用这个方法。
TreeModelEvent类本身提供了5个方法,帮我们取得事件的信息,如下所示:
TreeModelEvent方法:
int[] getChildIndices():返回子节点群的索引值。
Object[] getChildren():返回子节点群.
Object[] getPath():返回Tree中一条path上(从root nod到leaf node)的节点。
TreePath getTreePath():取得目前位置的Tree Path.
String toString():取得蝗字符串表示法.
由TreeModelEvent的getTreePath()方法就可以得到TreePath对象,此对象就能够让我们知道用户目前正选哪一个节点,
TreePath类最常用的方法为:
public Object getLastPathComponent():取得最深(内)层的节点。
public int getPathCount():取得此path上共有几个节点.
我们来看下面这个例子,用户可以在Tree上编辑节点,按下[Enter]键后就可以改变原有的值,并将改变的值显示在下面的
JLabel中:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.bedouin.*;
public class TreeDemo5 implements TreeModelListener
{
JLabel label = null;
String nodeName = null; //原有节点名称
public TreeDemo5()
{
try {
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new BedouinTheme();//设置界面的外观,手册中共有5种样式
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
} catch (UnsupportedLookAndFeelException ex) {
// You may handle the exception here
}
// this line needs to be implemented in order to make JWS work properly
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
JFrame f = new JFrame("TreeDemo");
Container contentPane = f.getContentPane();
DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器");
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("文件夹");
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑");
DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹");
DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
root.add(node1);
root.add(node2);
root.add(node3);
root.add(node4);
DefaultMutableTreeNode leafnode = new DefaultMutableTreeNode("公司文件");
node1.add(leafnode);
leafnode = new DefaultMutableTreeNode("个人信件");
node1.add(leafnode);
leafnode = new DefaultMutableTreeNode("私人文件");
node1.add(leafnode);
leafnode = new DefaultMutableTreeNode("本机磁盘(C:)");
node2.add(leafnode);
leafnode = new DefaultMutableTreeNode("本机磁盘(D:)");
node2.add(leafnode);
leafnode = new DefaultMutableTreeNode("本机磁盘(E:)");
node2.add(leafnode);
DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表");
node3.add(node31);
leafnode = new DefaultMutableTreeNode("天勤网站");
node31.add(leafnode);
leafnode = new DefaultMutableTreeNode("足球消息");
node31.add(leafnode);
leafnode = new DefaultMutableTreeNode("网络书店");
node31.add(leafnode);
JTree tree = new JTree(root);
tree.setEditable(true);//设置JTree为可编辑的
tree.addMouseListener(new MouseHandle());//使Tree加入检测Mouse事件,以便取得节点名称
//下面两行取得DefaultTreeModel,并检测是否有TreeModelEvent事件.
DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel();
treeModel.addTreeModelListener(this);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(tree);
label = new JLabel("更改数据为: ");
contentPane.add(scrollPane,BorderLayout.CENTER);
contentPane.add(label,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
/*本方法实作TreeModelListener接口,本接口共定义四个方法,分别是TreeNodesChanged()
*treeNodesInserted()、treeNodesRemoved()、treeNodesRemoved()、
*treeStructureChanged().在此范例中我们只针对更改节点值的部份,因此只实作
*treeNodesChanged()方法.
*/
public void treeNodesChanged(TreeModelEvent e) {
TreePath treePath = e.getTreePath();
System.out.println(treePath);
//下面这行由TreeModelEvent取得的DefaultMutableTreeNode为节点的父节点,而不是用户点选
//的节点,这点读者要特别注意。要取得真正的节点需要再加写下面6行代码.
DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent();
try {
//getChildIndices()方法会返回目前修改节点的索引值。由于我们只修改一个节点,因此节点索引值就放在index[0]
//的位置,若点选的节点为root node,则getChildIndices()的返回值为null,程序下面的第二行就在处理点选root
//node产生的NullPointerException问题.
int[] index = e.getChildIndices();
//由DefaultMutableTreeNode类的getChildAt()方法取得修改的节点对象.
node = (DefaultMutableTreeNode)node.getChildAt(index[0]);
} catch (NullPointerException exc) {}
//由DefaultMutableTreeNode类getUserObject()方法取得节点的内容,或是写成node.toString()亦相同.
label.setText(nodeName+"更改数据为: "+(String)node.getUserObject());
}
public void treeNodesInserted(TreeModelEvent e) {
}
public void treeNodesRemoved(TreeModelEvent e) {
}
public void treeStructureChanged(TreeModelEvent e) {
}
public static void main(String args[]) {
new TreeDemo5();
}
//处理Mouse点选事件
class MouseHandle extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
try{
JTree tree = (JTree)e.getSource();
//JTree的getRowForLocation()方法会返回节点的列索引值。例如本例中,“本机磁盘(D:)”的列索引值为4,此索引值
//会随着其他数据夹的打开或收起而变支,但“资源管理器”的列索引值恒为0.
int rowLocation = tree.getRowForLocation(e.getX(), e.getY());
/*JTree的getPathForRow()方法会取得从root node到点选节点的一条path,此path为一条直线,如程序运行的图示
*若你点选“本机磁盘(E:)”,则Tree Path为"资源管理器"-->"我的电脑"-->"本机磁盘(E:)",因此利用TreePath
*的getLastPathComponent()方法就可以取得所点选的节点.
*/
TreePath treepath = tree.getPathForRow(rowLocation);
TreeNode treenode = (TreeNode) treepath.getLastPathComponent();
nodeName = treenode.toString();
}catch(NullPointerException ne){}
}
}
}
注:上面的程序MouseHandle中:
int rowLocation = tree.getRowForLocation(e.getX(), e.getY());
TreePath treepath = tree.getPathForRow(rowLocation);
与:
TreePath treepath=tree.getSelectionPath();
等价,可互换。
我们将“我的电脑”改成“网上领居”:
我们再来看一个TreeModelEvent的例子,下面这个例子我们可以让用户自行增加、删除与修改节点:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.bedouin.*;
public class TreeDemo6 implements ActionListener,TreeModelListener{
JLabel label=null;
JTree tree=null;
DefaultTreeModel treeModel=null;
String nodeName=null;//原有节点名称
public TreeDemo6(){
try {
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new BedouinTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
} catch (UnsupportedLookAndFeelException ex) {
// You may handle the exception here
}
// this line needs to be implemented in order to make JWS work properly
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
JFrame f=new JFrame("TreeDemo6");
Container contentPane=f.getContentPane();
DefaultMutableTreeNode root=new DefaultMutableTreeNode("资源管理器");
tree=new JTree(root);
tree.setEditable(true);
tree.addMouseListener(new MouseHandle());
treeModel=(DefaultTreeModel)tree.getModel();
treeModel.addTreeModelListener(this);
JScrollPane scrollPane=new JScrollPane();
scrollPane.setViewportView(tree);
JPanel panel=new JPanel();
JButton b=new JButton("新增节点");
b.addActionListener(this);
panel.add(b);
b=new JButton("删除节点");
b.addActionListener(this);
panel.add(b);
b=new JButton("清除所有节点");
b.addActionListener(this);
panel.add(b);
label=new JLabel("Action");
contentPane.add(panel,BorderLayout.NORTH);
contentPane.add(scrollPane,BorderLayout.CENTER);
contentPane.add(label,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
//本方法运行新增、删除、清除所有节点的程序代码.
public void actionPerformed(ActionEvent ae){
if (ae.getActionCommand().equals("新增节点")){
DefaultMutableTreeNode parentNode=null;
DefaultMutableTreeNode newNode=new DefaultMutableTreeNode("新节点");
newNode.setAllowsChildren(true);
TreePath parentPath=tree.getSelectionPath();
//取得新节点的父节点
parentNode=(DefaultMutableTreeNode)(parentPath.getLastPathComponent());
//由DefaultTreeModel的insertNodeInto()方法增加新节点
treeModel.insertNodeInto(newNode,parentNode,parentNode.getChildCount());
//tree的scrollPathToVisible()方法在使Tree会自动展开文件夹以便显示所加入的新节点。若没加这行则加入的新节点
//会被 包在文件夹中,你必须自行展开文件夹才看得到。
tree.scrollPathToVisible(new TreePath(newNode.getPath()));
label.setText("新增节点成功");
}
if (ae.getActionCommand().equals("删除节点")){
TreePath treepath=tree.getSelectionPath();
if (treepath!=null){
//下面两行取得选取节点的父节点.
DefaultMutableTreeNode selectionNode=(DefaultMutableTreeNode)treepath.getLastPathComponent();
TreeNode parent=(TreeNode)selectionNode.getParent();
if (parent!=null) {
//由DefaultTreeModel的removeNodeFromParent()方法删除节点,包含它的子节点。
treeModel.removeNodeFromParent(selectionNode);
label.setText("删除节点成功");
}
}
}
if (ae.getActionCommand().equals("清除所有节点")){
//下面一行,由DefaultTreeModel的getRoot()方法取得根节点.
DefaultMutableTreeNode rootNode=(DefaultMutableTreeNode)treeModel.getRoot();
//下面一行删除所有子节点.
rootNode.removeAllChildren();
//删除完后务必运行DefaultTreeModel的reload()操作,整个Tree的节点才会真正被删除.
treeModel.reload();
label.setText("清除所有节点成功");
}
}
public void treeNodesChanged(TreeModelEvent e){
TreePath treePath=e.getTreePath();
DefaultMutableTreeNode node=(DefaultMutableTreeNode)treePath.getLastPathComponent();
try{
int[] index=e.getChildIndices();
node=(DefaultMutableTreeNode)node.getChildAt(index[0]);
}catch(NullPointerException exc){}
label.setText(nodeName+"更改数据为:"+(String)node.getUserObject());
}
public void treeNodesInserted(TreeModelEvent e){
System.out.println("new node insered");
}
public void treeNodesRemoved(TreeModelEvent e){
System.out.println("node deleted");
}
public void treeStructureChanged(TreeModelEvent e){
System.out.println("Structrue changed");
}
public static void main(String[] args){
new TreeDemo6();
}
class MouseHandle extends MouseAdapter{
public void mousePressed(MouseEvent e){
try{
JTree tree=(JTree)e.getSource();
int rowLocation=tree.getRowForLocation(e.getX(),e.getY());
TreePath treepath=tree.getPathForRow(rowLocation);
TreeNode treenode=(TreeNode)treepath.getLastPathComponent();
nodeName=treenode.toString();
}catch(NullPointerException ne){}
}
}
}
10-7-2:处理TreeSelectionEvent事件:
当我们在JTree上点选任何一个节点,都会触发TreeSelectionEvent事件,如果我们要处理这样的事件,必须实作
TreeSelectionListener界面,此界面只定义了一个方法,那就是valueChanged()方法。
TreeSelectionEvent最常用在处理显示节点的内容,例如你在文件图标中点两下就可以看到文件的内容。在JTree中选择节点
的方式共有3种,这3种情况跟选择JList上的项目是一模一样的,分别是:
DISCONTIGUOUS_TREE_SELECTION:可作单一选择,连续点选择(按住[Shift]键),不连续选择多个节点(按住[Ctrl]键),
这是java默认值.
CONTINUOUS_TREE_SELECTION:按住[Shift]键,可对某一连续的节点区间作选取。
SINGLE_TREE_SELECTION:一次只能选一个节点。
你可以自行实作TreeSelectionModel制作作更复杂的选择方式,但通常是没有必要的,因为java提供了默认的选择模式类供我们
使用,那就是DefaultTreeSelectionModel,利用这个类我们可以很方便的设置上面3种选择模式。
下面这个范例,当用户点选了一个文件名时,就会将文件的内容显示出来。
TreeDemo7.java
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class TreeDemo7 implements TreeSelectionListener
{
JEditorPane editorPane;
public TreeDemo7()
{
JFrame f = new JFrame("TreeDemo");
Container contentPane = f.getContentPane();
DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器");
DefaultMutableTreeNode node = new DefaultMutableTreeNode("TreeDemo1.java");
root.add(node);
node = new DefaultMutableTreeNode("TreeDemo2.java");
root.add(node);
node = new DefaultMutableTreeNode("TreeDemo3.java");
root.add(node);
node = new DefaultMutableTreeNode("TreeDemo4.java");
root.add(node);
JTree tree = new JTree(root);
//设置Tree的选择模式为一次只能选择一个节点
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
//检查是否有TreeSelectionEvent事件。
tree.addTreeSelectionListener(this);
//下面五行,JSplitPane中,左边是放含有JTree的JScrollPane,右边是放JEditorPane.
JScrollPane scrollPane1 = new JScrollPane(tree);
editorPane = new JEditorPane();
JScrollPane scrollPane2 = new JScrollPane(editorPane);
JSplitPane splitPane = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,true, scrollPane1, scrollPane2);
contentPane.add(splitPane);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
//本方法实作valueChanged()方法
public void valueChanged(TreeSelectionEvent e)
{
JTree tree = (JTree) e.getSource();
//利用JTree的getLastSelectedPathComponent()方法取得目前选取的节点.
DefaultMutableTreeNode selectionNode =
(DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
String nodeName = selectionNode.toString();
//判断是否为树叶节点,若是则显示文件内容,若不是则不做任何事。
if (selectionNode.isLeaf())
{
/*取得文件的位置路径,System.getProperty("user.dir")可以取得目前工作的路径,
*System.getProperty("file.separator")是取得文件分隔符,例如在window环境的
*文件分陋符是"/",而Unix环境的文件分隔符刚好相反,是"/".利用System.getProperty()
*方法你可以取得下列的信息:
java.version 显示java版本
java.endor 显示java制造商
java.endor.url 显示java制造商URL
java.home 显示java的安装路径
java.class.version 显示java类版本
java.class.path 显示java classpath
os.name 显示操作系统名称
os.arch 显示操作系统结构,如x86
os.version 显示操作系统版本
file.separator 取得文件分隔符
path.separator 取得路径分隔符,如Unix是以“:”表示
line.separator 取得换行符号,如Unix是以"/n"表示
user.name 取得用户名称
user.home 取得用户家目录(home directory),如Windows中Administrator的家目
录为c:/Documents and Settings/Administrator
user.dir 取得用户目前的工作目录.
*/
String filepath = "file:"+System.getProperty("user.dir") +
System.getProperty("file.separator") +
nodeName;
try {
//利用JEditorPane的setPage()方法将文件内容显示在editorPane中。若文件路径错误,则会产生IOException.
editorPane.setPage(filepath);
} catch(IOException ex) {
System.out.println("找不到此文件");
}
}
}
public static void main(String[] args) {
SwingUtil.setLookAndFeel();
new TreeDemo7();
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
10-8:JTree的其他操作:
我们在之前小节中曾说到Tree中的每一个节点都是一个TreeNode,并可利用JTree的setEditable()方法设置节点是否可编辑,
若要在Tree中找寻节点的父节点或子节点,或判断是否为树节点,皆可由实作TreeNode界面做到,但要编辑节点呢?java将编辑
节点的任务交给TreeCellEditor,TreeCellEditor本身是一个界面,里面只定义了getTreeCellEditor Component()方法,你可以实
作此方法使节点具有编辑的效果。不过你不用这么辛苦去实作这个方法,java本身提供了DefaultTreeCellEditor类来实作此方法
,亦提供了其他许多方法,例如取得节点内容(getCellEditorValue()) 、设置节点字体(setFont())、决定节点是否可编辑
(isCellEditable())等等。除非你觉得DefaultTreeCellEditor所提供的功能不够,你才需要去实作TreeCellEditor界面。你可以利
用JTree的getCellEditor()方法取得DefaultTreeCellEditor对象。当我们编辑节点时会触发ChangeEvent事件,你可以实作
CellEditorListener界面来处理此事件,CellEditorListener界面包括两个方法,分别是editingStopped(ChangeEvent e)与
editingCanceled(ChangeEvent e).若你没有实作TreeCellEditor界面,系统会以默认的DefaultTreeCellEdtior类来处理掉这两个
方法(你可以在DefaultTreeCellEditor中找到这两个方法),因此你无须再编写任何的程序。
另外,JTree还有一种事件处理模式,那就是TreeExpansionEvent事件。要处理这个事件你必须实作TreeExpansionListener
界面,此界面定义了两个方法,分别是treeCollapsed(TreeExpansionEvent e)与treeExpanded(TreeExpansionEvent e).当节点展
开时系统就会自动调用treeExpanded()方法,当节点合起来时,系统就会自动调用treeCollapsed()方法。你可以在这两个方法中编
写所要处理事情的程序代码。处理事件的过程我们已在上面举过多次,这里就不再重复了,可参考下面的网站:
http://javaalmanac.com/egs/index.html
++ Swing程序设计
++ 对话框(Option Pane与Dialog)的使用与介绍
11-1:使用JDialog组件:
JDialog的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--java.awt.Window
--java.awt.JDialog
--javax.swing.JDialog
如果你为公司设计一套“物品工具借用系统”,在这个系统中,借用物品的员工必须详细填员工编号、借用物品、借用器具、借
用日期、预计归还日期时间、借用原因等等,若没有详细填这此数据,就无法取得准许借用物品的证明文件。因此在设计这套系统
的过程中,你必须查看用户是否已经填妥相关数据,若员工忘记了填写某些重要字段,系统应该给予警示,提醒用户哪些字段必须
填写。这个情况也常发生在网络问卷或网络会员注册系统,用户必须填写相关数据,例如用户若没有填写E-Mail邮件地址,则系统
会提示你应当填写邮件地址,否则系统将不处理用户填写的信息。
为应付这种情况,java提供了JDialog与JOptionPane供我们使用,事实上,JOptionPane是阳春版的JDialog,当你在使用
JOptionPane时,系统会自动产生JDialog组件,并将JOptionPane的内容放入JDialog的ContentPane中,而这些均由系统在背后自动
运行,并不需要由我们介入。使用JOptionPane的好处是此组件已经默认了许多交互方式,你只用设置想要的显示模式,JOptionPane
就能轻易的显示出来,可说相当方便,若这些模式还是无法满足你的需求,你就可以使用JDialog来自行设计你的对话框。
我们先来看如何构造JDialog,JOptionPane将在后半段介绍:
JDialog构造函数:
JDialog():建立一个non-modal的对话框,没有title也不属于任何事件窗口组件。
JDialog(Dialog owner):建立一个属于Dialog组件的对话框,为non-modal形式,也没有title.
JDialog(Dialog owner,Boolean modal):建立一个属于Dialog组件的对话框,可决定modal形式,但没有title.
JDialog(Dialog owner,String title):建立一个属于Dialog组件的对话框,为non-modal形式,对话框上有title.
JDialog(Dialog owner,String title,Boolean modal):建立一个属于Dialog组件的对话框,可决定modal形式,且对话框上有
title.
JDialog(Frame owner):建立一个属于Frame组件的对话框,为non-modal形式,也没有title.
JDialog(Frame owner,Boolean modal):建立一个属于Frame组件的对话框,可决定modal形式,但没有title.
JDialog(Frame owner,String title):建立一个属于Frame组件的对话框,为non-modal形式,对话框上有title.
JDialog(Frame owner,String title,Boolean modal):建立一个属于Frame组件的对话框,可决定modal形式,且对话框上有title.
上面所说的modal是一种对话框操作模式,当modal为true时,代表用户必须结束对话框才能回到原来所属的窗口。当modal为
false时,代表对话框与所属窗口可以互相切换,彼此之间在操作上没有顺序性。
一般而言对话框都会依附在某个窗口上,例如JFrame或JDialog,原因在于对话框通常是一个程序运行的过程中与用户互动的中
间过程,在使用JDialog上跟JFrame非常相似,由上面的JDialog层次结构图中你可以发现,JDialog是继承AWT的Dialog类而来,因
此JDialog为一个Heavyweight组件。要加入组件到JDialog上与JFrame是一样的,你必须先取得JDialog的ContentPane,然后再把组
件加到此ContentPane中,JDialog默认的版面管理器是BorderLayout.
11-1-1:在JFrame上建立JDialog:
我们来看一个JDialog的例子,在这个例子中,用户在主窗口按下"借用物品"的按钮时,会跳出一个让用户填写窗体的JDialog
窗口,用户必须结束此JDialog窗口后才能返回主窗口.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class DialogDemo implements ActionListener{
JFrame f=null;
public void actionPerformed(ActionEvent e){
String cmd=e.getActionCommand();
if (cmd.equals("借用物品")){
new LendingSystem(f);
}else if (cmd.equals("离开系统")){
System.exit(0);
}
}
public DialogDemo(){
f=new JFrame("JDialog Example");
Container contentPane=f.getContentPane();
JPanel buttonPanel=new JPanel();
JButton b=new JButton("借用物品");
b.addActionListener(this);
buttonPanel.add(b);
b=new JButton("离开系统");
b.addActionListener(this);
buttonPanel.add(b);
buttonPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.blue,2),
"借用物品系统",TitledBorder.CENTER,TitledBorder.TOP));
contentPane.add(buttonPanel,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
SwingUtil.setLookAndFeel();
new DialogDemo();
}
}
class LendingSystem implements ActionListener{
JTextField staffField,objectField,borrowDateField,returnDateField,reasonField;
JDialog dialog;
public void actionPerformed(ActionEvent e){
String cmd=e.getActionCommand();
if (cmd.equals("确定")){
}else if (cmd.equals("取消")){
dialog.dispose();
}
}
LendingSystem(JFrame f){
dialog = new JDialog(f,"借用物品",true);
GridBagConstraints c;
int gridx,gridy,gridwidth,
gridheight,anchor,fill,ipadx,ipady;
double weightx,weighty;
Insets inset;
GridBagLayout gridbag = new GridBagLayout();
Container dialogPane = dialog.getContentPane();
dialogPane.setLayout(gridbag);
JLabel label = new JLabel("员工编号 : ");
gridx=0; //第0列
gridy=0; //第0行
gridwidth = 1; //占一单位宽度
gridheight = 1; //占一单位高度
weightx = 0; //窗口增大时组件宽度增大比率0
weighty = 0; //窗口增大时组件高度增大比率0
anchor = GridBagConstraints.CENTER; //容器大于组件size时将组件置于容器中央
fill = GridBagConstraints.BOTH; //窗口拉大时会填满水平与垂直空间
inset = new Insets(0,0,0,0); //组件间间距
ipadx = 0; //组件内水平宽度
ipady = 0; //组件内垂直高度
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(label,c);
dialogPane.add(label);
label = new JLabel("借用器具 : ");
gridx=3;
gridy=0;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(label,c);
dialogPane.add(label);
label = new JLabel("借用日期: ");
gridx=0;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(label,c);
dialogPane.add(label);
label = new JLabel("归还日期: ");
gridx=3;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(label,c);
dialogPane.add(label);
label = new JLabel("借用原因 : ");
gridx=0;
gridy=2;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(label,c);
dialogPane.add(label);
staffField = new JTextField();
gridx=1;
gridy=0;
gridwidth = 2;
gridheight = 1;
weightx = 1;
weighty = 0;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(staffField,c);
dialogPane.add(staffField);
objectField = new JTextField();
gridx=4;
gridy=0;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(objectField,c);
dialogPane.add(objectField);
borrowDateField = new JTextField();
gridx=1;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(borrowDateField,c);
dialogPane.add(borrowDateField);
returnDateField = new JTextField();
gridx=4;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(returnDateField,c);
dialogPane.add(returnDateField);
reasonField = new JTextField();
gridx=1;
gridy=2;
gridwidth = 5;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(reasonField,c);
dialogPane.add(reasonField);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,2));
JButton b = new JButton("确定");
panel.add(b);
b = new JButton("取消");
b.addActionListener(this);
panel.add(b);
gridx=0;
gridy=3;
gridwidth = 6;
weightx = 1;
weighty = 1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel,c);
dialogPane.add(panel);
dialog.setBounds(200,150,400,130);
dialog.show();
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
/*
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
UIManager.setLookAndFeel("com.stefankrause.xplookandfeel.XPLookAndFeel");
}catch(Exception e){
e.printStackTrace();
}*/
}
}
11-2:使用JOptionPane类的静态方法:
JOptionPane的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JOptionPane
以JDialog来制作对话框,你必须实作对话框中的每一个组件,但有时候我们的对话框只是要显示一段文字,或是一些简单的
选择(是或否),这时候可以利用JOptionPane类,它可以让你很简单的做出这样的效果,不仅大大的减少了程序代码的编写,也
让整个程序看起来清爽许多!
JOptionPane的构造函数:
JOptionPane():建立一个显示测试信息的JOptionPane组件。
JOptionPane(Object message):建立一个显示特定信息的JOptionPane组件。
JOptionPane(Object message,int messageType):建立一个显示特定信息的JOptionPane组件,并设置信息类型。
JOptionPane(Object message,int messageType,int optionType):建立一个显示特定信息的JOptionPane组件,并设置信息与选项.
JOptionPane(Object message,int messageType,int optionType,Icon icon):建立一个显示特定信息的JOptionPane组件,并设置
信息与选项,且可显示出图案.
JOptionPane(Object message,int messageType,int optionType,Icon icon,Object[] options):建立一个显示特定信息的
JOptionPane组件,并设置信息与选项,且可显示出图案.选项值是一个Object Array,可
用作更改按钮上的文字.
JOptionPane(Object message,int messageType,int optionType,Icon icon,Object[] options,Object initialValue):建立一个
显示特定信息的JOptionPane组件,并设置信息与选项类型,且可以显示出图案.选项值是
一个Object Array,可用作更改按钮上的文字,并设置默认按钮.
使用JOptionPane对象所得到的对话框是modal为true形式,也就是说我们必须先关闭对话框窗口才能回到产生对话框的母窗口上
.
要利用JOptionPane类来输出对话框,通常我们不会new一个JOptionPane对象出来,而是使用JOptionPane所提供的一些静态方法,
不用产生JOptionPane对象就可以直接使用,这些方法方法都是以showXxxxxDialog的形式出现,若你的对话框是出现在
InternaleFrame上,你可以用showInternalXxxxxDialog的各种方法产生对话框.以下我们整理出JOptionPane提供输出对话框的所有
静态方法:
Message Dialog
----------------------------------------------------------------------------------------------------------
方法: |void showMessageDialog(Component parentComponent,Object message)
|void showMessageDialog(Component parentComponent,Object message,String title,int messageType)
|void showMessageDialog(Component parentComponent,Object message,String title,int messageType,Icon
| icon)
|void showInternalMessageDialog(Component parentComponent,Object message)
|void showInternalMessageDialog(Component parentComponent,Object message,String title,int messageType)
|void showInternalMessageDialog(Component parentComponent,Object message,String title,int messageType
| ,Icon icon)
------------------------------------------------------------------------------------------------------------
说明: |显示信息对话框,对话框中只含有一个按钮,通常是"确定"按钮,例如安装完某个软件时通常会跳出一个对话框告知你
|安装已经成功.这类的方法有5种参数:
|parentComponent:是指产生对话框的组件为何,通常是指Frame或Dialog组件.
| message:是指要显示的组件,通常是String或Label类型
| title:对话框标题列上显示的文字.
| messageType:指定信息类型,共有5种类型,分别是ERROR_MESSAGE,INFORMATION_MESSAGE,WARING_MESSAGE,
| QUESTION_MESSAGE,PLAIN_MESSAGE(不显示图标).指定类型后对话框就会出现相对应的图标.
| icon:若你不喜欢java给的图标,你可以自己自定图标.
------------------------------------------------------------------------------------------------------------
Confirm Dialog
------------------------------------------------------------------------------------------------------------
方法: |int showConfirmDialog(Component parentComponent,Object message)
|int showConfirmDialog(Component parentComponent,Object message,String title,int optionType)
|int showConfirmDialog(Component parentComponent,Object message,String title,int optionType,
| int messageType)
|int showConfirmDialog(Component parentComponent,Object message,String title,int optionType,
| int messageType,Icon icon)
|int showInternalConfirmDialog(Component parentComponent,Object message)
|int showInternalConfirmDialog(Component parentComponent,Object message,String title,int optionType)
|int showInternalConfirmDialog(Component parentComponent,Object message,String title,int optionType
| ,int messageType)
|int showInternalConfirmDialog(Component parentComponent,Object message,String title,int optionType
| ,int messageType,Icon icon)
-----------------------------------------------------------------------------------------------------------
说明: |显示确认对话框,这类的对话框通常会问用户一个问题,然后用户回答是或不是,例如当我们修改了某个文件的内容
|却没存盘就要离开时,系统大部份都会跳出确认对话框.询问我们是否要存储修改过的内容.确认对话框方法有6种
|参数:
|parentComponent:是指产生对话框的组件为何,通常是指Frame或Dialog组件.
| message:是指要显示的组件,通常是String或Label类型
| title:对话框标题列上显示的文字.
| optionType:确定按钮的类型,有5种类型,分别是DEFAULT_OPTION,YES_NO_OPTION,YES_NO_CANCEL,与
| OK_CANCEL_OPTION.
| messageType:指定信息类型,共有5种类型,分别是ERROR_MESSAGE,INFORMATION_MESSAGE,WARING_MESSAGE,
| QUESTION_MESSAGE,PLAIN_MESSAGE(不显示图标).指定类型后对话框就会出现相对应的图标.
| icon:若你不喜欢java给的图标,你可以自己自定图标.
| 返回值为一整数值,依用户按下什么钮而定,YES_OPTION=0,NO_OPTION=1,CANCEL_OPTION=2,OK_OPTION=0
|,CLOSED_OPTION=-1(当用户都不选直接关掉对话框时)
----------------------------------------------------------------------------------------------------------
Input Dialog
-----------------------------------------------------------------------------------------------------------
方法: |String showInputDialog(Object message)
|String showInputDialog(Component parentComponent,Object message)
|String showInputDialog(Component parentComponent,Object message,String title,int messageType)
|Object showInputDailog(Component parentComponent,Object message,String title,int messageType,Icon icon
| ,Object[] selectionValues,Object initialSelectionValue)
|String showInternalInputDialog(Object message)
|String showInternalInputDialog(Component parentComponent,Object message)
|String showInternalInputDialog(Component parentComponent,Object message,String title,int messageType)
|Object showInternalInputDialog(Component parentComponent,Object message,String title,int messageType,
| Icon icon,Object[] selectionValues,Object initialSelectionValue)
-----------------------------------------------------------------------------------------------------------
说明: |显示输入对话框,这类的对话框可以让用户输入相关的信息,当用户按下确定钮后,系统会得到用户所输入的信息.输入
|对话框不仅可以让用户输入文字,也可以提供Combo Box组件让用户选择相关信息,避免用户输入错误.输入对话框方法
|有6种参数:
|parentComponent:是指产生对话框的组件为何,通常是指Frame或Dialog组件.
| message:是指要显示的组件,通常是String或Label类型
| title:对话框标题列上显示的文字.
| messageType:指定信息类型,共有5种类型,分别是ERROR_MESSAGE,INFORMATION_MESSAGE,WARING_MESSAGE,
| QUESTION_MESSAGE,PLAIN_MESSAGE(不显示图标).指定类型后对话框就会出现相对应的图标.
| icon:若你不喜欢java给的图标,你可以自己自定图标.
|selectionValues:给用户选择的可能值.Object Array中的数据会以ComboBox方式显示出来.
|initialSelectionValue:对话框初始化时所显示的值.
| 当用户按下确定按钮时会返回用户输入的信息,若按下取消按钮则返回null.
-------------------------------------------------------------------------------------------------------------
Option Dialog
-------------------------------------------------------------------------------------------------------------
方法: |int showOptionDialog(Component parentComponent,Object message,String title,int optionType,int
| messageType,Icon icon,Object[] options,Object initalValue)
|int showInternalOptionDialog(Component parentComponent,Object message,String title,int optionType,
| int messageType,Icon icon,Object[] options,Object initialValue)
-------------------------------------------------------------------------------------------------------------
说明: |显示选择对话框,这类的对话框可以让用户自定义对话类型,最大的好处是可以改变按钮上的文字.选择对话框方法有
|6种参数:
|parentComponent:是指产生对话框的组件为何,通常是指Frame或Dialog组件.
| message:是指要显示的组件,通常是String或Label类型
| title:对话框标题列上显示的文字.
| optionType:确定按钮的类型,有5种类型,分别是DEFAULT_OPTION,YES_NO_OPTION,YES_NO_CANCEL,与
| OK_CANCEL_OPTION.
| messageType:指定信息类型,共有5种类型,分别是ERROR_MESSAGE,INFORMATION_MESSAGE,WARING_MESSAGE,
| QUESTION_MESSAGE,PLAIN_MESSAGE(不显示图标).指定类型后对话框就会出现相对应的图标.
| icon:若你不喜欢java给的图标,你可以自己自定图标.
| options:给用户选择的按钮显示文字.
| initalValue:对话框初始化时按钮默认值.
| 返回值为一整数值,依用户按下什么钮而定,YES_OPTION=0,NO_OPTION=1,CANCEL_OPTION=2,OK_OPTION=0
|,CLOSED_OPTION=-1(当用户都不选直接关掉对话框时)
------------------------------------------------------------------------------------------------------------
上面表格看起来好像很多方法似的,但实际上只区分成四大类,你只需要选择要用哪类的对话框,再决定使用那类中的哪个方法即
可.我们慢慢来为你介绍这四个种类的对话框.
11-2-1:输出Message Dialog
Message Dialog是在对话框上显示出一段信息,目的在告知用户一些相关信息,因此Message Dialog只会有一个确定按钮,让用户
看完信息后就可以关闭这个对话框.下面这个例子我们使用Message对话框,我们来看看不同的MessageType会有什么样的图案产生.
MessageDialog.java
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class MessageDialog implements ActionListener{
JFrame f=null;
public MessageDialog(){
f=new JFrame("optionPane");
Container contentPane=f.getContentPane();
contentPane.setLayout(new GridLayout(2,3));
JButton b=new JButton("Show Error Icon");
b.addActionListener(this);
contentPane.add(b);
b=new JButton("Show Information Icon");
b.addActionListener(this);
contentPane.add(b);
b=new JButton("Show Waring Icon");
b.addActionListener(this);
contentPane.add(b);
b=new JButton("Show Question Icon");
b.addActionListener(this);
contentPane.add(b);
b=new JButton("Show Plain Icon");
b.addActionListener(this);
contentPane.add(b);
b=new JButton("Show User Define Icon");
b.addActionListener(this);
contentPane.add(b);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
SwingUtil.setLookAndFeel();
new MessageDialog();
}
public void actionPerformed(ActionEvent e){
String cmd=e.getActionCommand();
String title="Message Dialog";
String message="";
int type=JOptionPane.PLAIN_MESSAGE;
if (cmd.equals("Show Error Icon")){
type=JOptionPane.ERROR_MESSAGE;
message="Error Message";
}else if (cmd.equals("Show Information Icon")){
type=JOptionPane.INFORMATION_MESSAGE;
message="information Message";
}else if (cmd.equals("Show Waring Icon")){
type=JOptionPane.WARNING_MESSAGE;
message="Waring Message";
}else if (cmd.equals("Show Question Icon")){
type=JOptionPane.QUESTION_MESSAGE;
message="Question Message";
}else if (cmd.equals("Show Plain Icon")){
type=JOptionPane.PLAIN_MESSAGE;
message="Plain Message";
}else if (cmd.equals("Show User Define Icon")){
type=JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(f,message,title,type,new ImageIcon("..//icons//glass.jpg"));
return ;
}
JOptionPane.showMessageDialog(f,message,title,type);
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
11-2-2:输出Confirm Dialog:
看过了信息对话框,接着我们来看确认对话框到底怎样.Confirm Dialog目的在让用户对某个问题选择"Yes"或"No",可算是一种
相当简单的是非选择对话框.下面这个范例中,用户可选择不同按钮类型的确认对话框,为方便说明,在此我们将Message Type都默认
为JOptionPane.INFORMATION_MESSAGE.
ConfirmDialog.java
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class ConfirmDialog implements ActionListener
{
JFrame f = null;
JLabel label = null;
public ConfirmDialog()
{
f = new JFrame("OptionPane Demo");
Container contentPane = f.getContentPane();
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2,2));
JButton b = new JButton("Show DEFAULT_OPTION");
b.addActionListener(this);
panel.add(b);
b = new JButton("Show YES_NO_OPTION");
b.addActionListener(this);
panel.add(b);
b = new JButton("Show YES_NO_CANCEL_OPTION");
b.addActionListener(this);
panel.add(b);
b = new JButton("Show OK_CANCEL_OPTION");
b.addActionListener(this);
panel.add(b);
label = new JLabel(" ",JLabel.CENTER);
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(panel,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
SwingUtil.setLookAndFeel();
new ConfirmDialog();
}
public void actionPerformed(ActionEvent e)
{
//处理用户按钮事件,默认的messageType是JoptionPane.INFORMATION_MESSAGE.
String cmd = e.getActionCommand();
String title = "Confirm Dialog";
String message ="";
int messageType = JOptionPane.INFORMATION_MESSAGE;
int optionType = JOptionPane.YES_NO_OPTION;
if(cmd.equals("Show DEFAULT_OPTION")) {
optionType = JOptionPane.DEFAULT_OPTION;
message = "Show DEFAULT_OPTION Buttons";
} else if(cmd.equals("Show YES_NO_OPTION")) {
optionType = JOptionPane.YES_NO_OPTION;
message = "Show YES_NO_OPTION Buttons";
} else if(cmd.equals("Show YES_NO_CANCEL_OPTION")) {
optionType = JOptionPane.YES_NO_CANCEL_OPTION;
message = "Show YES_NO_CANCEL_OPTION Buttons";
} else if(cmd.equals("Show OK_CANCEL_OPTION")) {
optionType = JOptionPane.OK_CANCEL_OPTION;
message = "Show OK_CANCEL_OPTION Buttons";
}
int result = JOptionPane.showConfirmDialog(f, message,
title, optionType, messageType);
if (result == JOptionPane.YES_OPTION)
label.setText("您选择:Yes or OK");
if (result == JOptionPane.NO_OPTION)
label.setText("您选择:No");
if (result == JOptionPane.CANCEL_OPTION)
label.setText("您选择:Cancel");
if (result == JOptionPane.CLOSED_OPTION)
label.setText("您没做任何选择,并关闭了对话框");
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
11-2-3:输出Input Dialog:
Input Dialog可以让用户输入相关信息,当用户按下确定钮后,系统会得到用户所输入的信息.输入对话框不仅可以让用户自输入
文字,也可以显示出ComboBox组件让用户选择相关信息,避免用户输入错误,当用户输入完毕按下确定按钮时会返回用户输入的信息,
若按下取消则返回null值.下面为InputDialog的范例.
InputDialog.java
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class InputDialog implements ActionListener
{
JFrame f = null;
JLabel label = null;
public InputDialog()
{
f = new JFrame("OptionPane Demo");
Container contentPane = f.getContentPane();
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,2));
JButton b = new JButton("Show Text Input");
b.addActionListener(this);
panel.add(b);
b = new JButton("Show ComboBox Input");
b.addActionListener(this);
panel.add(b);
label = new JLabel(" ",JLabel.CENTER);
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(panel,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
SwingUtil.setLookAndFeel();
new InputDialog();
}
public void actionPerformed(ActionEvent e)
{
String cmd = e.getActionCommand();
String title = "Input Dialog";
String message ="您最熟悉哪一种程序语言?";
int messageType = JOptionPane.QUESTION_MESSAGE;
String[] values = {"JAVA","PHP","ASP","C++","VB"};
String result ="";
if(cmd.equals("Show Text Input")) {
result = JOptionPane.showInputDialog(f, message,
title, messageType);
} else if(cmd.equals("Show ComboBox Input")) {
result = (String)JOptionPane.showInputDialog(f, message,
title, messageType,null,values,values[0]);
}
if (result == null)
label.setText("您取消了对话框");
else{
label.setText("您输入:"+result);
}
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
11-2-3:输出Option Dialog:
Option Dialog可以让用户自定义对话框类型,比较具有弹性,最大的好处是可以改变按钮上的文字.我们来看下面的例子:
OptionDialog.java
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class OptionDialog implements ActionListener
{
JFrame f = null;
JLabel label = null;
public OptionDialog()
{
f = new JFrame("OptionPane Demo");
Container contentPane = f.getContentPane();
JButton b = new JButton("Show Option Dialog");
b.addActionListener(this);
label = new JLabel(" ",JLabel.CENTER);
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(b,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
SwingUtil.setLookAndFeel();
new OptionDialog();
}
public void actionPerformed(ActionEvent e)
{
String title = "Option Dialog";
String message ="您喜欢吃汉堡吗?";
int messageType = JOptionPane.QUESTION_MESSAGE;
//由于我们的optionType设置成JOptionPane.YES_NO_CANCEL_OPTION,因此对话框中会有三个按钮.我们在options
//的String Arrray中设置这三个按钮的名称,并以options[1]按钮为默认值,若将options参数设为null,系统会原来
//的按钮名称来显示.
int optionType = JOptionPane.YES_NO_CANCEL_OPTION;
String[] options = {"喜欢","不喜欢","取消"};
int result = JOptionPane.showOptionDialog(f, message, title,
optionType, messageType,null,options,options[1]);
if (result == JOptionPane.YES_OPTION)
label.setText("您选择:喜欢");
if (result == JOptionPane.NO_OPTION)
label.setText("您选择:不喜欢");
if (result == JOptionPane.CANCEL_OPTION)
label.setText("您选择:取消");
if (result == JOptionPane.CLOSED_OPTION)
label.setText("您没做任何选择,并关闭了对话框");
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
11-2-5:输出Internal Dialog:
我们之前曾经说过,JOptionPane也可以显示出Internal Dialog对话框,使用方法跟上面的范例一模一样,只是在方法名称上多
了Internal这个字眼,例如showInternalMessageDialog()等等,我们来看下面的范例:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class InternalDialog implements ActionListener
{
JInternalFrame internalFrame = null;
JLabel label = null;
public InternalDialog()
{
JFrame f = new JFrame("OptionPane Demo");
Container contentPane = f.getContentPane();
JDesktopPane desktopPane = new JDesktopPane();
internalFrame = new JInternalFrame(
"Internal Frame", true,
true,
true,
true);
internalFrame.setLocation( 20,20);
internalFrame.setSize(200,200);
internalFrame.setVisible(true);
Container icontentPane = internalFrame.getContentPane();
JButton b = new JButton("Show Internal Dialog");
b.addActionListener(this);
icontentPane.add(b,BorderLayout.CENTER);
label = new JLabel(" ",JLabel.CENTER);
icontentPane.add(label,BorderLayout.NORTH);
desktopPane.add(internalFrame);
contentPane.add(desktopPane,BorderLayout.CENTER);
f.setSize(350, 350);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
SwingUtil.setLookAndFeel();
new InternalDialog();
}
public void actionPerformed(ActionEvent e)
{
String title = "Option Dialog";
String message ="您喜欢吃汉堡吗?";
int messageType = JOptionPane.QUESTION_MESSAGE;
int optionType = JOptionPane.YES_NO_CANCEL_OPTION;
String[] options = {"喜欢","不喜欢","取消"};
int result = JOptionPane.showInternalOptionDialog(internalFrame, message,
title, optionType, messageType,null,options,options[1]);
if (result == JOptionPane.YES_OPTION)
label.setText("您选择:喜欢");
if (result == JOptionPane.NO_OPTION)
label.setText("您选择:不喜欢");
if (result == JOptionPane.CANCEL_OPTION)
label.setText("您选择:取消");
if (result == JOptionPane.CLOSED_OPTION)
label.setText("您没做任何选择,并关闭了对话框");
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
读者在使用Internal Dialog时要特别注意,一般我们利用JOptionPane所产生的对话框均是modal为true状态,可是当你使用
Internal Dialog时对话框会变成modal为false状态.因此你可以不用关闭之前的对话框,就可以再按一次按钮,再产生一个Internal
Dialog.你再运行上一例操作后就知道了.
若你想将JInternalFrame内的Internal Dialog model设为true,你可以有下面两种解决方法:
1.你可以建立JOptionPane对象,而非直接去调用JOptionPane的static方法来输出对话框.然后利用JOptionPane的createDialog()方
法,取得JDialog对象,再利用Dialog(JDialog继承Dialog)所提供的setModal()方法将modal设为true.
2.直接使用JDialog.
11-3:使用JOptionPane组件建立对话框:
我们在11-2节中已经介绍了JOptionPane的构造函数,虽然大部份的情况下我们只需要使用JOptionPane的静态方法来产生对话框
,但如果你想直接使用JOptionPane对象来产生对话框,当然也可以.下面我们就举一个以JOptionPane对象产生对话框的范例:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class OptionPaneDemo implements ActionListener
{
JFrame f = null;
JLabel label = null;
public OptionPaneDemo()
{
f = new JFrame("OptionPane Demo");
Container contentPane = f.getContentPane();
JButton b = new JButton("Show Text Input");
b.addActionListener(this);
label = new JLabel(" ",JLabel.CENTER);
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(b,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
SwingUtil.setLookAndFeel();
new OptionPaneDemo();
}
public void actionPerformed(ActionEvent e)
{
String title = "Input Dialog";
JLabel message =new JLabel("您最喜欢吃什么食物?",JLabel.CENTER);
int messageType = JOptionPane.QUESTION_MESSAGE;
int optionType = JOptionPane.OK_CANCEL_OPTION;
String result ="";
//利用message,messageType,optionType来建立JOptionPane对象
JOptionPane optionPane = new JOptionPane(message,messageType,optionType);
//利用JOptionPane的setWandtsInput()方法,使对话框有一个输入字段让用户输入信息
optionPane.setWantsInput(true);
//利用JOptionPane的setInitialSelectionValue()方法,使得输入字段上的初始值为"请输入";
optionPane.setInitialSelectionValue("请输入!");
//利用JOptionPane的setInputValue()方法,使得当用户按下"Cancel"键或关闭对话框时,result的默认字符串为
//"你没有输入";
optionPane.setInputValue("您没有输入!");
JDialog dialog = optionPane.createDialog(f, title);
dialog.show();
//JOptionPane的getInputValue()方法可以取得用户输入的信息.
result = (String)optionPane.getInputValue();
label.setText("您输入:"+result);
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
++ Swing程序设计
++ 菜单与工具栏的使用与介绍
12-1:使用JMenuBar组件:
JMenuBar的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JMenuBar
在介绍JMenu组件前,我们先介绍JMenuBar组件,JMenuBar组件的功能是用来摆入JMenu组件.当我们建立完许多的JMenu组件后,
需要通过JMenuBar组件来将JMenu组件加入到窗口中.虽然我们由下表中看出JMenuBar组件只有一种构造方式,但是它对于构造一个菜
单来说是个不可缺少的组件.
JMenuBar构造函数:
JMenuBar():建立一个新的JMenuBar;
由于构造一个空的JMenuBar然后设置到窗口上对于窗口来说是没有意义的,因此JMenuBar需要结合至少一个以上的JMenu组件才
会在画面上显现出视觉的效果,所以JMenuBar的构造方法及范例我们留到JMenu的第一个范例中再加以说明.
12-1:使用JMenu组件:
JMenu的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JMenuItem
--javax.swing.JMenu
JMenu组件是用来存放和整合JMenuItem的组件,这个组件也是在构成一个菜单中不可或缺的组件之一.JMenu可以是单一层次的结
构也可以是一个层次式的结构,要使用何种形式的结构取决于界面设计上的需要而定,如下表所示:
JMenu构造函数:
JMenu():建立一个新的JMenu.
JMenu(Action a):建立一个支持Action的新的JMenu.
JMenu(String s):以指定的字符串名称建立一个新的JMenu.
JMenu(String,Boolean b):以指定的字符串名称建立一个新的JMenu并决定这个菜单是否可以下拉式的属性.
12-1-2:构造JMenu组件:
在看过JMenu的构造函数之后,我们先来看一个具有图标菜单的范例:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class JMenu1 extends JFrame{
JTextArea theArea = null;
public JMenu1(){
super("JMenu1");
theArea = new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
//调用自行编写的buildFileMenu()方法来构造JMenu.
JMenu mfile = buildFileMenu();
MBar.add(mfile); //将JMenu加入JMenuBar中.
setJMenuBar(MBar);//将JMenuBar设置到窗口中.
}//end of JMenu1()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setIcon(new ImageIcon("icons/file.gif"));
return thefile;
}//end of buildFileMenu()
public static void main(String[] args){
SwingUtil.setLookAndFeel();
JFrame F = new JMenu1();
F.setSize(400,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
}//end of class JMenu1
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
12-3:使用JMenuItem组件:
JMenuItem组件的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JMenuItem
JMenuItem继承AbstractButton类,因此JMenuItem具有许多AbstractButton的特性,也可以说JMenuItem是一种特殊的Button,所
以JMenuItem支持许多在Button中好用的功能,例如加入图标文件或是当我们在菜单中选择某一项JMenuItem时就如同按下按钮的操作
一样触发ActionEvent,通过ActionEvent的机制我们就能针对不同的JMenuItem编写其对应的程序区段,我们来看看JMenuItem的构造
方式有哪些:
JMenuItem构造函数:
JMenuItem():建立一个新的JMenuItem.
JMenuItem(Action a):建立一个支持Action的新的JMenuItem.
JMenuItem(Icon icon):建立一个有图标的JMenuItem.
JMenuItem(String text):建立一个有文字的JMenuItem.
JMenuItem(String text,Icon icon):建立一个有图标和文字的JMenuItem.
JMenuItem(String text,int mnemonic):建立一个有文字和键盘设置快捷键的JMenuItem.
12-3-1:构造JMenuItem组件:
在看过JMenuItem的构造方式之后,我们来看一个例子了解JMenuItem是如何运作的.这个例子延伸自JMenu1.java,改写
buileFileMenu()方法部份.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class JMenuItem1 extends JFrame{
JTextArea theArea = null;
public JMenuItem1(){
super("JMenu1");
theArea = new JTextArea();
theArea.setEditable(true);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
JMenu mfile = buildFileMenu();
MBar.add(mfile);
setJMenuBar(MBar);
}//end of JMenu1()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("文件");
JMenuItem newf=new JMenuItem("新建");
JMenuItem open=new JMenuItem("打开");
JMenuItem close=new JMenuItem("关闭");
JMenuItem exit=new JMenuItem("退出");
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();//分隔线
thefile.add(exit);
return thefile;
}//end of buildFileMenu()
public static void main(String[] args){
SwingUtil.setLookAndFeel();
JFrame F = new JMenuItem1();
F.setSize(400,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
}//end of class JMenu1
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
我们在一开始就提到JMenuItem是一个特殊的Button组件,因此我们可以在JMenuItem中加入图标文件来美化界面的显示状态,我
们来看下面这个范例:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class JMenuItem2 extends JFrame{
JTextArea theArea = null;
public JMenuItem2(){
super("JMenuItem2");
theArea = new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
MBar.setOpaque(true);
JMenu mfile = buildFileMenu();
MBar.add(mfile);
setJMenuBar(MBar);
}//end of JMenuItem2()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
public static void main(String[] args){
SwingUtil.setLookAndFeel();
JFrame F = new JMenuItem2();
F.setSize(400,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
}//end of class JMenuItem2
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
运行程序我们可看到在文字左边出现了我们所指定的图标文件.这时我们又会有疑问了,图标文件一定要摆在文字的左边吗?答案
是不一定的!图标在这里会出现在文字左边是因为JMenuItem默认值的关系,我们可以利用setHorizontalTextPosition()方法改变文
字的位置.我们将上面程序的buildFileMenu()方法改写如下:
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
//定义文字位置
//在这里我们使用了SwingConstants这个interface,这个interface定义了许多在Swing中常用的数值,由于AbstractButton
//类实作了SwingConstants interface,所以我们可以直接使用SwingConstants.LEFT代表JMenuItem组件的最左边界值.
newf.setHorizontalTextPosition(SwingConstants.LEFT);
open.setHorizontalTextPosition(SwingConstants.LEFT);
close.setHorizontalTextPosition(SwingConstants.LEFT);
quit.setHorizontalTextPosition(SwingConstants.LEFT);
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
到目前为止我们已经能将一个菜单的外观构造起来,不过我们还少了一个小小的功能,那就是快捷键的设置.快捷键是让我们能使
用键盘来控制菜单并方便操作之用.那么怎么将它加入到菜单中呢?我们来看看下面的范例是怎么实现的.
在JMenuItem2.jav中修改buildFileMenu()方法:操作方式->:[Alt]+快捷键
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('C');
quit.setMnemonic('X');
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
上面的方法是以[Alt+快捷键]操作,一般的快捷键会设置为[Ctrl]加上某个字符,来直接运行某项功能,要在菜单中加入快捷键很
简单,只需要使用setAccelerator()方法即可,我们来看下面的范例:
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
说明:利用setAccelerator()方法,分别设置各个JMenuItem的快捷键值.在setAccelerator()方法中使用了KeyStroke类,这个类是
用来管理键盘上的各种信息,我们利用getKeyStroke()方法来指定快捷键的键值.getKeyStroke()方法的三个字段值分别代表键值,
屏蔽键值各放开按键时是否触发事件.在这个范例里我们设置[Ctrl+英文字符]来运行JMenuItem的选项功能.
当然,快捷键的屏蔽键值不一定要是[Ctrl],也可以是[Alt],[Shift].
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.SHIFT_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.SHIFT_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.SHIFT_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.SHIFT_MASK, false) );
现在我们已经能够完整的建立一个菜单了,但是我们现在看到的菜单都是单一层次的,如何来建立具有层次式的菜单呢?我们来看
下面的范例:
由于这支程序修改自JMenuItem3.java,由于只修改了bulidMenu()方法,所以在这里我们只列出bulidMenu()方法的程序部份:
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
JMenu prefMenu = new JMenu("Preferences..");
prefMenu.setMnemonic('P');
JMenuItem setPage = new JMenuItem("setPage",new ImageIcon("icons/setpage24.gif"));
JMenuItem setImport = new JMenuItem("Import",new ImageIcon("icons/import24.gif"));
JMenuItem setExport = new JMenuItem("Export",new ImageIcon("icons/export24.gif"));
setPage.setMnemonic('S');
setImport.setMnemonic('I');
setExport.setMnemonic('E');
setPage.setAccelerator( KeyStroke.getKeyStroke('S', java.awt.Event.CTRL_MASK, false) );
setImport.setAccelerator( KeyStroke.getKeyStroke('I', java.awt.Event.CTRL_MASK, false) );
setExport.setAccelerator( KeyStroke.getKeyStroke('E', java.awt.Event.CTRL_MASK, false) );
prefMenu.add(setPage);
prefMenu.add(setImport);
prefMenu.add(setExport);
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(prefMenu);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
12-3-2:JMenuItem的事件处理:
由于JMenuItem继承AbstractButton类,因此JMenuItem也具备了许多AbstractButton的特性,当然也包含了事件处理的机制.
JMenuItem的事件处理机制是类似JButton的事件处理模式,换名话说,当按下JMenuItem组件时就如同按下JButton组件一般,均会产生
ActionEvent事件,我们来看下面这一范例:
JMenuItem5.java
import javax.swing.*;
import java.awt.event.*;
public class JMenuItem5 extends JFrame{
JTextArea theArea=null;
public JMenuItem5(){
super("JMenuItem5");
theArea=new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar=new JMenuBar();
MBar.setOpaque(true);
JMenu mfile=buildFileMenu();
MBar.add(mfile);
setJMenuBar(MBar);
}
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
newf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem New Performed -/n");
}});
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem Open Performed -/n");
}});
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem Close Performed -/n");
}});
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
public static void main(String[] args){
JFrame F = new JMenuItem5();
F.setSize(400,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
}
12-4:使用JCheckBoxMenuItem:
JCheckBoxMenuItem的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JMenuItem
--javax.swing.JCheckBoxMenuItem
JCheckBoxMenuItem继承JMenuItem类,因此JCheckBoxMenuItem可以使用JMenuItem所提供的方法,而且JCheckBoxMenuItem也具有
AbstractButton的特性,而JChcekBoxMenuItem和JCheckBox的性质几乎是一样,两者间最大的差别在于JCheckBoxMenuItem是专用在
MenuItem上.我们来看看JCheckBoxMenuItem的构造方法:
JCheckBoxMenuItem构造函数:
JCheckBoxMenuItem():建立一个新的JCheckBoxMenuItem.
JCheckBoxMenuItem(Action a):建立一个支持Action的新的JCheckBoxMenuItem.
JCheckBoxMenuItem(Icon icon):建立一个有图标的JCheckBoxMenuItem.
JCheckBoxMenuItem(String text):建立一个有文字的JCheckBoxMenuItem.
JCheckBoxMenuItem(String text,Boolean b):建立一个有文字和设置选择状态的JCheckBoxMenuItem.
JCheckBoxMenuItem(String text,Icon icon):建立一个有文字和图标的JCheckBoxMenuItem.
JCheckBoxMenuItem(String text,Icon icon,Boolean b):建立一个有文字,图标和设置状态的JCheckBoxMenuItem.
12-4-1:构造JCheckBoxMenuItem组件:
由上表可以看出JCheckBoxMenuItem的构造方式与JMenuItem的构造方式几乎一模一样,唯一有差异的是JCheckBoxMenuItem的构
造方式中多了设置选择状况的构造方式,设置选择状态就是决定是否要将构造好的JCheckBoxMenuItem组件设置成默认值.我们来看下
面的范例:
JCheckBoxMenuItem1.java
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class JCheckBoxMenuItem1 extends JFrame implements ActionListener{//由于我们要处理ActionEvent事件,因此要实作
//ActionListener界面.
JTextArea theArea = null;
public JCheckBoxMenuItem1(){
super("JCheckBoxMenuItem1");
theArea = new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
MBar.setOpaque(true);
JMenu mfile = buildFileMenu();
JMenu mstyle = buildStyleMenu();//调用buildStyleMenu()方法来建立包含JCheckBoxMenuItem的JMenu.
MBar.add(mfile);
MBar.add(mstyle);
setJMenuBar(MBar);
}//end of JCheckBoxMenuItem1()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
//将File Menu内的三个JMenuItem对象加入事件处理模式.
newf.addActionListener(this);
open.addActionListener(this);
close.addActionListener(this);
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
public JMenu buildStyleMenu() {
//建立新的JMenu组件
JMenu style = new JMenu("Style");
//设置其快捷键
style.setMnemonic('S');
JCheckBoxMenuItem Left = new JCheckBoxMenuItem("Left",new ImageIcon("icons/left24.gif"));
JCheckBoxMenuItem Center = new JCheckBoxMenuItem("Center",new ImageIcon("icons/center24.gif"));
JCheckBoxMenuItem Right = new JCheckBoxMenuItem("Right",new ImageIcon("icons/right24.gif"));
JCheckBoxMenuItem Justify = new JCheckBoxMenuItem("Justify",new ImageIcon("icons/justify24.gif"));
Left.setMnemonic('L');
Center.setMnemonic('E');
Right.setMnemonic('R');
Justify.setMnemonic('J');
Left.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.SHIFT_MASK, false) );
Center.setAccelerator( KeyStroke.getKeyStroke('E', java.awt.Event.SHIFT_MASK, false) );
Right.setAccelerator( KeyStroke.getKeyStroke('R', java.awt.Event.SHIFT_MASK, false) );
Justify.setAccelerator( KeyStroke.getKeyStroke('J', java.awt.Event.SHIFT_MASK, false) );
//分别将四个JCheckBoxMenuItem加入事件处理模式.
Left.addActionListener(this);
Center.addActionListener(this);
Right.addActionListener(this);
Justify.addActionListener(this);
style.add(Left);
style.add(Center);
style.add(Right);
style.add(Justify);
return style;
}//end of buildStyleMenu()
public void actionPerformed(ActionEvent ae){
//为事件处理区段,在这里是将被点选的JMenuItem组件名称填入JTextArea中.
try{
theArea.append("* action '"+ae.getActionCommand()+"' performed. */n");
}catch(Exception e){
System.out.println("actionPerformed Exception:"+e);
}
}
public static void main(String[] args){
SwingUtil.setLookAndFeel();
JFrame F = new JCheckBoxMenuItem1();
F.setSize(400,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
}//end of class JCheckBoxMenuItem1
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
12-5:使用JRadioButtonMenuItem组件:
JRadioButtonMenuItem的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.AbstractButton
--javax.swing.JMenuItem
--javax.swing.JRadioButtonMenuItem
与JCheckBoxMenuItem相同,JRadioButtonItem也是继承JMenuItem,因此JRadioButtonMenuItem也具备JMenuItem的许多特性.而
JRadioButtonMenuItem和JCheckBoxMenuItem一样也是一种特殊的JMenuItem.我们在前面也介绍过JRadioButton组件,而
JRadioButtonMenuItem是专用在MenuItem上.我们来看看JRadioButtonMenuItem的构造方法,如下表:
JRadioButtonMenuItem的构造函数:
JRadioButtonMenuItem():建立一个新的JRadioButtonMenuItem.
JRadioButtonMenuItem(Action a):建立一个支持Action的新的JRadioButtonMenuItem.
JRadioButtonMenuItem(Icon icon):建立一个有图标的JRadioButtonMenuItem.
JRadioButtonMenuItem(Icon icon,Boolean selected):建立一个有图标和设置选择状态的JRadioButtonMenuItem.
JRadioButtonMenuItem(String text):建立一个有文字的JRadioButtonMenuItem.
JRadioButtonMenuItem(String text,Boolean selected):建立一个有文字和设置选择状态的JRadioButtonMenuItem.
JRadioButtonMenuItem(String text,Icon icon):建立一个有文字和图标的JRadioButtonMenuItem.
JRadioButtonMenuItem(String text,Icon icon,Boolean selected):建立一个有文字,图标和设置状态的JRadioButtonMenuItem.
12-5-1:构造JRadioButtonMenuItem组件:
由一表可以看出JRadioButtonMenuItem的构造方式与JCheckBoxMenuItem构造方式几乎相同,而且和JCheckBoxMenuItem的构造方
式一样都是比JMenuItem的构造方式多了设置选择状况的构造方式,设置选择状态就是决定是否要将构造好的JRadioButtonMenuItem
设置为默认值.我们来看下面这个范例:
import javax.swing.*;
import java.awt.event.*;
public class JRadioButtonMenuItem1 extends JFrame implements ActionListener{
JTextArea theArea = null;
public JRadioButtonMenuItem1(){
super("JRadioButtonMenuItem1");
theArea = new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
MBar.setOpaque(true);
JMenu mfile = buildFileMenu();
JMenu mstyle = buildStyleMenu();
MBar.add(mfile);
MBar.add(mstyle);
setJMenuBar(MBar);
}//end of JRadioButtonMenuItem1()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
newf.addActionListener(this);
open.addActionListener(this);
close.addActionListener(this);
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
public JMenu buildStyleMenu() {
JMenu style = new JMenu("Style");
style.setMnemonic('S');
JRadioButtonMenuItem Left = new JRadioButtonMenuItem("Left",new ImageIcon("icons/left24.gif"));
JRadioButtonMenuItem Center = new JRadioButtonMenuItem("Center",new ImageIcon("icons/center24.gif"));
JRadioButtonMenuItem Right = new JRadioButtonMenuItem("Right",new ImageIcon("icons/right24.gif"));
JRadioButtonMenuItem Justify = new JRadioButtonMenuItem("Justify",new ImageIcon("icons/justify24.gif"));
Left.setMnemonic('L');
Center.setMnemonic('E');
Right.setMnemonic('R');
Justify.setMnemonic('J');
Left.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.SHIFT_MASK, false) );
Center.setAccelerator( KeyStroke.getKeyStroke('E', java.awt.Event.SHIFT_MASK, false) );
Right.setAccelerator( KeyStroke.getKeyStroke('R', java.awt.Event.SHIFT_MASK, false) );
Justify.setAccelerator( KeyStroke.getKeyStroke('J', java.awt.Event.SHIFT_MASK, false) );
Left.addActionListener(this);
Center.addActionListener(this);
Right.addActionListener(this);
Justify.addActionListener(this);
style.add(Left);
style.add(Center);
style.add(Right);
style.add(Justify);
return style;
}//end of buildStyleMenu()
public void actionPerformed(ActionEvent ae){
try{
theArea.append("* action '"+ae.getActionCommand()+"' performed. */n");
}catch(Exception e){
System.out.println("actionPerformed Exception:"+e);
}
}
public static void main(String[] args){
JFrame F = new JRadioButtonMenuItem1();
F.setSize(400,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
}//end of class JRadioButtonMenuItem1
在这个范例中我们遇到了与JRadioButton同样的问题,那就是选项的单、复选的问题.一般来说RadioButton组件是用来做单选
的情况时使用,而CheckBox则是多为复选情况时使用.那么我们该怎么来解决这个问题呢?还记得我们介绍JRadioButton时的解决方式
吗?没错,就是要利用ButtonGroup类来处理.我们在JRadioButtonMenuItem1.java的buildStyleMenu()方法中加下下列五行:
ButtonGroup bg=new ButtonGroup();
bg.add(Left);
bg.add(Center);
bg.add(Right);
bg.add(Justify);
运行程序我们可看到加入ButtonGroup后的JRadioButtonMenuItem变成只能被单选的菜单.
12-6:使用JToolBar组件:
JToolBar的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JToolBar
ToolBar的功能是用来放置各种常用的功能或控制组件,这个功能在各类软件中都可以很轻易的看到.一般我们在设计软件时,会将
所有功能依类放置在菜单中(JMenu),但当功能数量相当多时,可能造成用户操作一个简单的操作就必须繁复的寻找菜单中相关的功能
,这将造成用户操作上的负担.若我们能将一般常用的功能以工具栏方式呈现在菜单下,让用户很快得到他想要的功能,不仅增加用户
使用软件的意愿,也加速工作的运行效率.这就是使用ToolBar的好处.我们现在来看看JTooBar的构造方式.
JToolBar构造函数:
JToolBar():建立一个新的JToolBar,位置为默认的水平方向.
JToolBar(int orientation):建立一个指定的JToolBar.
JToolBar(String name):建立一个指定名称的JToolBar.
JToolBar(String name,int orientation):建立一个指定名称和位置的JToolBar.
12-6-1:构造JToolBar组件:
在使用JToolBar时一般都采用水平方向的位置,因此我们在构造时多是采用上表中的第一种构造方式来建立JToolBar.如果需要
改变方向时再用JToolBar内的setOrientation()方法来改变设置,或是以鼠标拉动的方式来改变JToolBar的位置.我们来看下面的例
子:
JToolBar1.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class JToolBar1 extends JFrame{
JTextArea theArea = null;
static final String ComboStr[] = {"Times New Roman","Dialog","宋体","黑体","楷体"};
public JToolBar1(){
super("JToolBar1");
theArea = new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
MBar.setOpaque(true);
JMenu mfile = buildFileMenu();
JToolBar theBar = buildToolBar();
this.getContentPane().add(theBar,BorderLayout.NORTH);//将构造好的JToolBar放置到窗口上.
MBar.add(mfile);//将JMenu加入到JMenuBar中
setJMenuBar(MBar);//将JMenuBar设置到窗口中.
}//end of JToolBar1()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
newf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem New Performed -/n");
}});
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem Open Performed -/n");
}});
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem Close Performed -/n");
}});
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
public JToolBar buildToolBar() {
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(true);//设置JToolBar可否浮动.
//分别构造三个ToolBarAction的类组件,准备将这三个组件设置到JToolBar中.ToolBaarAction类是我们自己编写的inner
// class,这个inner class在程序后半部份,这个类继承AbstractAction,AbstractAction是一个抽象类,实现Action
//interface,而Action interface又继承ActionListener interface又继承AActionListener interface,因此可直接在
//AbstractAction中覆写actionPerformed()方法,处理ActionEvent事件.在JToolBar中有一个add(Action a)方法,只要传入
//Action参数就可以得到一个JButton对象,因此在程序中下面的98,100,102就是以这样的方式来构造出JToolBar上的按钮组
//件.
ToolBarAction tba_new = new ToolBarAction("new",new ImageIcon("icons/new24.gif"));
ToolBarAction tba_open = new ToolBarAction("open",new ImageIcon("icons/open24.gif"));
ToolBarAction tba_close = new ToolBarAction("close",new ImageIcon("icons/close24.gif"));
//99,101,103利用setActionCommand()方法分别设置各个组件被触发事件后所返回的字符串信息.
JButton JB;
98 JB = toolBar.add(tba_new);//将ToolBarAction组件加入JToolBar中.
99 JB.setActionCommand("#TooBar_NEW performed!");
100 JB = toolBar.add(tba_open);//将ToolBarAction组件加入JToolBar中.
101 JB.setActionCommand("#ToolBar_OPEN performed!");
102 JB = toolBar.add(tba_close);//将ToolBarAction组件加入JToolBar中.
103 JB.setActionCommand("#ToolBar_CLOSE performed!");
toolBar.addSeparator();//在JToolBar加上分隔线,如同在JMenu上利用addSeparator()方法加上分隔线一样,不同的是在
//JMenu中分隔线是以灰色直线的样式表现,而在JToolBar中则是以一小段空来表示.
ToolBarAction tba_B = new ToolBarAction("bold",new ImageIcon("icons/bold24.gif"));
ToolBarAction tba_I = new ToolBarAction("italic",new ImageIcon("icons/italic24.gif"));
ToolBarAction tba_U = new ToolBarAction("underline",new ImageIcon("icons/underline24.gif"));
JB = toolBar.add(tba_B);//重复上面的操作
JB.setActionCommand("#ToolBar_Bold performed!");
JB = toolBar.add(tba_I);
JB.setActionCommand("#ToolBar_Italic performed!");
JB = toolBar.add(tba_U);
JB.setActionCommand("#ToolBar_Underline performed!");
toolBar.addSeparator();
//在JToolBar中加入一个JLabel组件.
JLabel JLfont = new JLabel("Font Type");
toolBar.add(JLfont);
toolBar.addSeparator();
//利用上面定义的ComboStr数建立一个JComboBox组件.
JComboBox jcb = new JComboBox(ComboStr);
//将JComboBar加入事件处理模式.这里是将所选到的组件名称填入JTextArea中.
jcb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("*Combobox "+((JComboBox)e.getSource()).getSelectedItem()+"
performed!/n");
}});
//在JToolBar中加入一个JComboBox组件.
toolBar.add(jcb);
return toolBar;
}//end of buildToolBar()
public static void main(String[] args){
SwingUtil.setLookAndFeel();
JFrame F = new JToolBar1();
F.setSize(430,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
class ToolBarAction extends AbstractAction{
public ToolBarAction(String name,Icon icon){
super(name,icon);
}
//对于JToolBar上按钮的事件处理是将组件的ActionCommand返回值字符串加入JTextArea中.
public void actionPerformed(ActionEvent e){
try{
theArea.append(e.getActionCommand()+"/n");
}catch(Exception ex){}
}
}//end of inner class ToolBarAction
}//end of class JToolBar1
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
在上面这个程序中,我们利用AbstractAction抽象类来构造JToolBar上的JButton组件,这个做法看起来较为陌生,下面我们详细
探讨其中隐含的意义.我们曾提到AbstractAction是一个抽象类,实现Action界面,而Action界面又继承ActionListener界面,因此
AbstractAction类具有侦听ActionEvent的功能,我们可以覆写actionPerformed()方法来处理ActionEvent事件.然而使用
AbstractAction抽象类有什么好处呢?通常一个软件在设计时会因用户习惯,产生不同的操作方式却能达到相同的功能,例如文书编辑
器中,copy功能可能在菜单中出现,也可能在工具栏上出现,甚至在快显菜单(Popup Menu)中出现,虽然出现的方式不一样,但均能达到
copy的功能.若以我们之前的事件处理方法,我们必须为每种出现方式实现copy功能,造成程序代码重复性太高,不易阅读也不美观,
相反的,若我们以AbstractAction抽象类来覆写actionPerformed()方法,我们只需要为每一种功能编写一次程序代码即可,因为
JToolBar,JMenu,JPopupMenu类均有add(Action a)方法,可利用相同的AbstractAction类构造出个别不同的组件.下面范例我们利用
这个概念让用户"按我"选项时,均使用同一个actionPerformed()方法:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JToolBar2 extends JFrame{
JTextArea theArea = null;
ToolBarAction pushAction = null;
public JToolBar2(){
super("JToolBar2");
theArea = new JTextArea();
theArea.setEditable(false);
getContentPane().add(new JScrollPane(theArea));
JMenuBar MBar = new JMenuBar();
MBar.setOpaque(true);
pushAction = new ToolBarAction("按我",null);
JMenu mfile = buildFileMenu();
JToolBar theBar = buildToolBar();
this.getContentPane().add(theBar,BorderLayout.NORTH);
MBar.add(mfile);
setJMenuBar(MBar);
}//end of JToolBar2()
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
thefile.add(pushAction);
return thefile;
}//end of buildFileMenu()
public JToolBar buildToolBar() {
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(true);
toolBar.add(pushAction);
return toolBar;
}//end of buildToolBar()
public static void main(String[] args){
JFrame F = new JToolBar2();
F.setSize(430,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
class ToolBarAction extends AbstractAction{
public ToolBarAction(String name,Icon icon){
super(name,icon);
}
public void actionPerformed(ActionEvent e){
try{
theArea.append("不管用哪种方式执行/"按我/",都会出现这句!!"+"/n");
}catch(Exception ex){}
}
}//end of inner class ToolBarAction
}//end of class JToolBar2
说明:
1.利用ToolBarAction类分别建立JToolBar上的JButton与JMenu上的JMenuItem组件,ToolBarAction类继承AbstractAction抽象
类,并覆写actionPerformed()方法.读者在读完JPopupMenu小节后,可将JPopupMenu的功能加入此范例中.
2. 从上面程序中可看出,一般事件处理方式:先产生个别组件,再利用addActionListener()方法侦听ActionEvent事件,最后覆写
actionPerformed()方法.然而以继承AbstractAction抽象类方式处理相同的事件,可以看出程序代码精简许多.读者可比较之间的差
异性.
12-6-2:在JToolBar组件中加入ToolTip:
相信大多数人都有使用过Word文书编辑软件的经验,当我们在使用Word的工具栏时会发现到有一些功能是比较不常用的,而且光
看工具栏上的图标文件也无法立刻得知该图标文件代表什么功能.这时候,我们通常会把鼠标指针移到该图标文件上,稍等待1-2秒后
就会出现一个小提示让我们知道这个图标文件是代表什么意义.这个小提示就是ToolTip.
那么我们在JToolBar中该如何使用这种功能呢?我们来看下面这个范例.这个范例延伸自JToolBar1.java.因此我们只列出
buildToolBar()方法的部份,其他部份的程序都没有改变.
public JToolBar buildToolBar() {
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(true);
ToolBarAction tba_new = new ToolBarAction("new",new ImageIcon("icons/new24.gif"));
ToolBarAction tba_open = new ToolBarAction("open",new ImageIcon("icons/open24.gif"));
ToolBarAction tba_close = new ToolBarAction("close",new ImageIcon("icons/close24.gif"));
JButton JB;
JB = toolBar.add(tba_new);
//只需要利用setToolTipText()这个方法即可,利用getValue()方法取得各个ToolBarAction类的名称来当作ToolTip显示的字
//符串.
JB.setActionCommand("#TooBar_NEW performed!");
JB.setToolTipText((String)tba_new.getValue(Action.NAME));
JB = toolBar.add(tba_open);
JB.setActionCommand("#ToolBar_OPEN performed!");
JB.setToolTipText((String)tba_open.getValue(Action.NAME));
JB = toolBar.add(tba_close);
JB.setActionCommand("#ToolBar_CLOSE performed!");
JB.setToolTipText((String)tba_close.getValue(Action.NAME));
toolBar.addSeparator();
ToolBarAction tba_B = new ToolBarAction("bold",new ImageIcon("icons/bold24.gif"));
ToolBarAction tba_I = new ToolBarAction("italic",new ImageIcon("icons/italic24.gif"));
ToolBarAction tba_U = new ToolBarAction("underline",new ImageIcon("icons/underline24.gif"));
JB = toolBar.add(tba_B);
JB.setActionCommand("#ToolBar_Bold performed!");
JB.setToolTipText((String)tba_B.getValue(Action.NAME));
JB = toolBar.add(tba_I);
JB.setActionCommand("#ToolBar_Italic performed!");
JB.setToolTipText((String)tba_I.getValue(Action.NAME));
JB = toolBar.add(tba_U);
JB.setActionCommand("#ToolBar_Underline performed!");
JB.setToolTipText((String)tba_U.getValue(Action.NAME));
toolBar.addSeparator();
JLabel JLfont = new JLabel("Font Type");
toolBar.add(JLfont);
toolBar.addSeparator();
JComboBox jcb = new JComboBox(ComboStr);
jcb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("*Combobox "+((JComboBox)e.getSource()).getSelectedItem()+" performed!
/n");
}});
toolBar.add(jcb);
return toolBar;
}//end of buildToolBar()
12-7:使用JPopupMenu组件.
JPopupMenu的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JPopupMenu
JPopupMenu是一种特别形式的Menu,其性质与Menu几乎完全相同,但是PopupMenu并不固定在窗口的任何一个位置,而是由鼠标指
针和系统判断决定PopupMenu要出现在哪里.相信大家在使用许多软件时都有用过Popupmenu的功能,例如在使用Word文书编辑器软件
时,当我们在编辑区域的任一处按下鼠标右键,就会跳出一个PopupMenu菜单.
JPopupMenu构造函数:
JPopupMenu():建立一个新的JPopupMenu;
JPopupMenu(String label):建立一个指定标题的JPopupMenu.
12-7-1:构造JPopupMenu组件:
由一表中我们可以知道JPopupMenu的构造方法并不复杂,两种构造方法的差异只在于是否赋予JPopupMenu一个标题文字.我们马上来
看下面这个范例,了解如何应用JPopupMenu.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class JPopupMenu1 extends JFrame{
JTextArea theArea = null;
static final String ComboStr[] = {"Times New Roman","Dialog","宋体","黑体","楷体"};
JPopupMenu Popup = null;//声明一个全局(Global)并设置初始值为null的JPopupMenu组件.
public JPopupMenu1(){
super("JPopupMenu1");
theArea = new JTextArea();
theArea.setEditable(false);
this.getContentPane().add(new JScrollPane(theArea),BorderLayout.CENTER);
JMenuBar MBar = new JMenuBar();
MBar.setOpaque(true);
JMenu mfile = buildFileMenu();
JToolBar theBar = buildToolBar();
this.getContentPane().add(theBar,BorderLayout.NORTH);
PopupPanel pp = new PopupPanel();//new一个PopupPanel组件来放置JPopupMenu.
this.getContentPane().add(pp,BorderLayout.SOUTH); //将PopupPanel组件放置到窗口中.
MBar.add(mfile);
setJMenuBar(MBar);
}//end of JPopupMenu1()
/*****************begin**********************
分别建立程序中菜单,工具栏和事件处理模式的部份,我们在此不再加以说明.
****************************************/
public JMenu buildFileMenu() {
JMenu thefile = new JMenu("File");
thefile.setMnemonic('F');
JMenuItem newf = new JMenuItem("New",new ImageIcon("icons/new24.gif"));
JMenuItem open = new JMenuItem("Open",new ImageIcon("icons/open24.gif"));
JMenuItem close= new JMenuItem("Close",new ImageIcon("icons/close24.gif"));
JMenuItem quit = new JMenuItem("Exit",new ImageIcon("icons/exit24.gif"));
newf.setMnemonic('N');
open.setMnemonic('O');
close.setMnemonic('L');
quit.setMnemonic('X');
newf.setAccelerator( KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false) );
open.setAccelerator( KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false) );
close.setAccelerator( KeyStroke.getKeyStroke('L', java.awt.Event.CTRL_MASK, false) );
quit.setAccelerator( KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false) );
newf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem New Performed -/n");
}});
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem Open Performed -/n");
}});
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("- MenuItem Close Performed -/n");
}});
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}});
thefile.add(newf);
thefile.add(open);
thefile.add(close);
thefile.addSeparator();
thefile.add(quit);
return thefile;
}//end of buildFileMenu()
public JToolBar buildToolBar() {
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(true);
ToolBarAction tba_new = new ToolBarAction("new",new ImageIcon("icons/new24.gif"));
ToolBarAction tba_open = new ToolBarAction("open",new ImageIcon("icons/open24.gif"));
ToolBarAction tba_close = new ToolBarAction("close",new ImageIcon("icons/close24.gif"));
JButton JB;
JB = toolBar.add(tba_new);
JB.setActionCommand("#TooBar_NEW performed!");
JB.setToolTipText((String)tba_new.getValue(Action.NAME));
JB = toolBar.add(tba_open);
JB.setActionCommand("#ToolBar_OPEN performed!");
JB.setToolTipText((String)tba_open.getValue(Action.NAME));
JB = toolBar.add(tba_close);
JB.setActionCommand("#ToolBar_CLOSE performed!");
JB.setToolTipText((String)tba_close.getValue(Action.NAME));
toolBar.addSeparator();
ToolBarAction tba_B = new ToolBarAction("bold",new ImageIcon("icons/bold24.gif"));
ToolBarAction tba_I = new ToolBarAction("italic",new ImageIcon("icons/italic24.gif"));
ToolBarAction tba_U = new ToolBarAction("underline",new ImageIcon("icons/underline24.gif"));
JB = toolBar.add(tba_B);
JB.setActionCommand("#ToolBar_Bold performed!");
JB.setToolTipText((String)tba_B.getValue(Action.NAME));
JB = toolBar.add(tba_I);
JB.setActionCommand("#ToolBar_Italic performed!");
JB.setToolTipText((String)tba_I.getValue(Action.NAME));
JB = toolBar.add(tba_U);
JB.setActionCommand("#ToolBar_Underline performed!");
JB.setToolTipText((String)tba_U.getValue(Action.NAME));
toolBar.addSeparator();
JLabel JLfont = new JLabel("Font Type");
toolBar.add(JLfont);
toolBar.addSeparator();
JComboBox jcb = new JComboBox(ComboStr);
jcb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
theArea.append("*Combobox "+((JComboBox)e.getSource()).getSelectedItem()+"
performed!/n");
}});
toolBar.add(jcb);
return toolBar;
}//end of buildToolBar()
/*****************End**********************
分别建立程序中菜单,工具栏和事件处理模式的部份,我们在此不再加以说明.
****************************************/
public static void main(String[] args){
SwingUtil.setLookAndFeel();
JFrame F = new JPopupMenu1();
F.setSize(430,200);
F.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});//end of addWindowListener
F.setVisible(true);
} // end of main
class ToolBarAction extends AbstractAction{
public ToolBarAction(String name,Icon icon){
super(name,icon);
}
public void actionPerformed(ActionEvent e){
try{
theArea.append(e.getActionCommand()+"/n");
}catch(Exception ex){}
}
}//end of inner class ToolBarAction
/*本方法建立inner class PopupPanel.这个类继承JPanel并实作MouseListener,PopupMenuListener,ActionListener和
*ActionListener等3个Listener.MouseListener为处理鼠标事件的Listener,PopupMenuListener为Popup菜单事件的Listener,
*ActionListener则是大家最熟悉用来处理JMenuItem事件的Listener.
*/
class PopupPanel extends JPanel implements MouseListener,PopupMenuListener,ActionListener{
public PopupPanel(){
Popup = new JPopupMenu();//new 一个新的JPopupMenu.
JMenuItem theItem;
//分别建立四个JMenuItem和其事件处理模式将将JMenuItem加入JPopupMenu中.
Popup.add(theItem = new JMenuItem("Cut",new ImageIcon("icons/cut24.gif")));//建立JMenuItem组件.
theItem.addActionListener(this);//将JMenuItem组件加入事件处理模式.
Popup.add(theItem = new JMenuItem("Copy",new ImageIcon("icons/copy24.gif")));
theItem.addActionListener(this);
Popup.add(theItem = new JMenuItem("Paste",new ImageIcon("icons/paste24.gif")));
theItem.addActionListener(this);
Popup.addSeparator();//在JPopupMenu中加入分隔线,我们在前面有提到JPopupMenu和Menu大致上的性质是一样的,所以
//在JPopupMenu中一样是以JMenuItem来当作选项的组件.
Popup.add(theItem = new JMenuItem("Page Setup..."));
theItem.addActionListener(this);
//利用setBorder()方法将BevelBorder类当作参数传入,使JPopupMenu产生立体边框浮起的效果.我们也可以将参数设置改
//为BevelBorder.LOWERED使得JPopupMenu产生立体边框凹陷的效果.
Popup.setBorder(new BevelBorder(BevelBorder.RAISED));
Popup.addPopupMenuListener(this); //将JPopupMenu组件加入PopupMenu事件处理模式中.
addMouseListener(this);//将PopupPanel类加入Mouse事件处理模式中.
theArea.addMouseListener(this);//后面有说明
}//end of PopupPanel()
/*由于PopupPanel这个inner class中实作了MouseListener,因此需要覆写mouseClicked(),mousePressed(),
*mouseReleased(),mouseEntered()和mouseExited()等5个方法.在这个范例里当mouseClicked(),mousePressed()
*和mouseReleased()等3个方法被触发时会调用checkPopup()方法来判断是否要将PopupMenu输出来.
*/
public void mouseClicked(MouseEvent me){ checkPopup(me);}
public void mousePressed(MouseEvent me){ checkPopup(me);}
public void mouseReleased(MouseEvent me){ checkPopup(me);}
public void mouseEntered(MouseEvent me){}
public void mouseExited(MouseEvent me){}
/*checkPopup()方法.其中,在程序中利用isPopupTrigger()方法判断PopupMenu是否已经输出.若没有,则在程序中利用
*show()方法将PopupMenu输出目前鼠标指针(利用getX()和getY()方法得知)的位置上.
*/
private void checkPopup(MouseEvent me){
if(me.isPopupTrigger()){
Popup.show(me.getComponent(), me.getX(), me.getY());
}
}//end of checkPopup()
/*由于PopupPanel这个inner class实作了PopupMenuListener,因此需要覆写popupMenuWillBecomeVisible(),
*popupMenuWillBecomeInvisible()方法和popupMenuCanceled()等3个方法.在这个范例里当这3个方法被触
*发后会在JTextArea中加入一个信息.
*/
public void popupMenuWillBecomeVisible(PopupMenuEvent pme){
theArea.append("-PopupMenu Visibel!/n");
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent pme){
theArea.append("-PopupMenu Invisibel!/n");
}
public void popupMenuCanceled(PopupMenuEvent pme){
theArea.append("-PopupMenu Hidden!/n");
}
//当某个JMenuItem被触发后会在JTextArea中加入一个信息.
public void actionPerformed(ActionEvent ae){
theArea.append("+Popup "+ae.getActionCommand()+" performed!/n");
}
}//end of inner class PopupPanel
}//end of class JPopupMenu1
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
说明:(1):由于JPopupMenu只是一种Menu的组件,因此在使用JPopupMenu时我们都需要一个Container来放置JPopupMenu,在这里这们
选择使用JPanel组件来作为JPopupMenu的Container.
(2):这个程序的运行结果可发现JPopupMenu只有在JTextArea下缘,也就是JPanel的部份才有作用,因为我们并没有在JTextArea
中加入addMouseListener()方法,你可以在PopupPanel()构造函数中加入:
theArea.addMouseListener(this);
这行,就能够解决在JTextArea上无法显示JPopupMenu的问题.
++ Swing程序设计
++ JFileChoose,JColorChooer,JSeparator
文件选择对话框,颜色选择对话框,分隔线的使用与介绍.
13-1:使用JFileChooser组件.
JFileChooser的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JFileChooser
当我们在处理窗口上的一些操作,特别是文本处理的部份,例如一个文本编辑器上打了一段文字,我们可能希望将此段文字存储起来
,供以后方便使用,此时系统应当提供一个存储文件的对话框,将此段文字存到一个自定义或内定的文件名中.同样,当我们要叫出某个
文件时,系统也应当提供打开文件的功能,让我们选择所欲打开的文件.在java中这些操作都可以由JFileChoose组件来达成.这个组件
提供了打开文件存盘的窗口功能,也提供了显示特定类型文件图标的功能,亦能针对某些文件类型做过滤的操作.如果你的系统需要对
某些文件或文件做操作,JFileChooser组件可以让你轻松地做出漂亮的用户界面.在这边读者要注意的是,JFileChooser本身不提供读
文件或存盘的功能,这些功能必须你自行实作.事实上,JFileChooser本身只是一个对话框模型,它也是依附在JDialog的结构上,因此
它只是一个针对文件操作的对话框,当然本身也就不会有读文件或存盘的功能!以下我们来看JFileChooser的构造函数:
JFileChooser构造函数:
JFileChooser():建立一个JFileChooser对象,默认的文件对话框路径是用户的家目录(Home Directory),例如在windows 2000中的
Administrator的家目录是在C:/Documents and Settings/Administrator中.
JFileChooser(File currentDirectory):建立一个JFileChooser对象,并以File所在位置文件为文件对话框的打开路径.
JFileChooser(File currentDirectory,FileSystemView fsv):建立一个JFileChooser对象,以File所在位置为文件对话框的打开路
径并设置文件图标查看方式.
JFileChooser(FileSystemView fsv):建立一个JFileChooser对象,并设置文件图标查看方式.
JFileChooser(String currentDirectoryPath):建立一个JFileChooser对象,并设置文件对话框的打开路径.
JFileChooser(String currentDirectoryPath,FileSystemView fsv): 建立一个JFileChooser对象,并设置文件对话框的打开路径与
文件图标查看方式.
13-1-1:建立一个简单的JFileChooser对话框:
介绍完JFileChooser构造函数后,我们来实作一个简单的范例.这个范例可以让用户在JTextArea上输入文字,输入完后按下"存储
文件"按钮就可以打开JFileChooser存储文件对话框,用户可以输入欲存储的文件名,按下"Save"按钮就可以存储文件.若用户要打开
某个文件内容,只需要按下"打开文件"按钮,就会出现JFileChooser打开文件对话框,用户选择好所欲打开的文件就可以将数据读入
JTextArea中.
在这个范例中,我们使用JFileChooser的showOpenDialog()或showSaveDialog()方法来打开文件对话框,此两个方法在用户按下
按钮或关闭对话框时会返回一个整数值,这个整数值的类型有3种,分别是:
JFileChooser.CANCEL_OPTION:表示用户按下取消按钮.
JFileChooser.APPROVE_OPTION:表示用户按下确定按钮.
JFileChooser.ERROR_OPEION:表示有错误产生或是对话框不正常关闭.
利用这3个整数值我们就能判断用户到底在对话框中做了什么操作,并加以处理,例如当用户选择了文件并按下确定键后,我们就可
以利用getSelectedFile()方法取得文件对象,利用这个文件对象我们就能够取得文件名称(getName())与文件路径(getPath());
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
class FileChooserDemo1 implements ActionListener
{
JFrame f = null;
JLabel label = null;
JTextArea textarea = null;
JFileChooser fileChooser = null;
public FileChooserDemo1()
{
f = new JFrame("FileChooser Example");
Container contentPane = f.getContentPane();
textarea = new JTextArea();
JScrollPane scrollPane = new JScrollPane(textarea);
scrollPane.setPreferredSize(new Dimension(350,300));
JPanel panel = new JPanel();
JButton b1 = new JButton("新建文件");
b1.addActionListener(this);
JButton b2 = new JButton("存储文件");
b2.addActionListener(this);
panel.add(b1);
panel.add(b2);
label = new JLabel(" ",JLabel.CENTER);
fileChooser = new JFileChooser("D://");//建立一个FileChooser对象,并指定D:的目录为默认文件对话框路径.
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(scrollPane,BorderLayout.CENTER);
contentPane.add(panel,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
new FileChooserDemo1();
}
public void actionPerformed(ActionEvent e)
{
File file = null;
int result;
/*当用户按下"打开文件"按钮时,JFileChooser的showOpenDialog()方法会输出文件对话框,并利用
*setApproveButtonText()方法取代按钮上"Open"文字;以setDialogTitle()方法设置打开文件对话框Title名称.
*当使用选择完后,会将选择结果存到result变量中.
*/
if (e.getActionCommand().equals("新建文件"))
{
fileChooser.setApproveButtonText("确定");
fileChooser.setDialogTitle("打开文件");
result = fileChooser.showOpenDialog(f);
textarea.setText("");
/*当用户按下打开文件对话框的"确定"钮后,我们就可以利用getSelectedFile()方法取得文件对象.若是用户按下打
*开文件对话框的"Cancel"钮,则将在label上显示"你没有选择任何文件"字样.
*/
if (result == JFileChooser.APPROVE_OPTION)
{
file = fileChooser.getSelectedFile();
label.setText("您选择打开的文件名称为:"+file.getName());
}
else if(result == JFileChooser.CANCEL_OPTION)
{
label.setText("您没有选择任何文件");
}
FileInputStream fileInStream = null;
if(file != null)
{
try{
//利用FileInputStream将文件内容放入此数据流中以便读取.
fileInStream = new FileInputStream(file);
}catch(FileNotFoundException fe){
label.setText("File Not Found");
return;
}
int readbyte;
try{
//以read()方法读取FileInputStream对象内容,当返回值为-1时代表读完此数据流.将所读到的字符显示
//在textarea中.
while( (readbyte = fileInStream.read()) != -1)
{
textarea.append(String.valueOf((char)readbyte));
}
}catch(IOException ioe){
label.setText("读取文件错误");
}
finally{//回收FileInputStream对象,避免资源的浪费.
try{
if(fileInStream != null)
fileInStream.close();
}catch(IOException ioe2){}
}
}
}
//实作写入文件的功能.
if (e.getActionCommand().equals("存储文件"))
{
result = fileChooser.showSaveDialog(f);
file = null;
String fileName;
//当用户没有选择文件,而是自己键入文件名称时,系统会自动以此文件名建立新文件.
if (result == JFileChooser.APPROVE_OPTION)
{
file = fileChooser.getSelectedFile();
label.setText("您选择存储的文件名称为:"+file.getName());
}
else if(result == JFileChooser.CANCEL_OPTION)
{
label.setText("您没有选择任何文件");
}
//写入文件我们使用FileOutputStream,在这个范例中,我们写入文件的方式是将之前内容清除并重新写入.若你想把
//新增的内容加在原有的文件内容后面,你可以使用FileOutputStream(String name,Boolean append)这个构造函数.
FileOutputStream fileOutStream = null;
if(file != null)
{
try{
fileOutStream = new FileOutputStream(file);
}catch(FileNotFoundException fe){
label.setText("File Not Found");
return;
}
String content = textarea.getText();
try{
fileOutStream.write(content.getBytes());
}catch(IOException ioe){
label.setText("写入文件错误");
}
finally{
try{
if(fileOutStream != null)
fileOutStream.close();
}catch(IOException ioe2){}
}
}
}
}
}
13-1-2:建立可选择文件类型的JFileChooser对话框:
当你专为某种文件类型设计一套软件时,为了用户打开文件存盘方便,我们通常会在文件对话框中过滤掉无关的文件类型,让用户
很快速选择出想要的文件数据.例如在Word软件中,当我们按下"另存新文件"选项时,所出现的文件对话框将会以".doc"扩展名当作默
认的文件存储类型.
如果你所设计的软件可以支持多种类型的文件操作,你应该设计让用户可以选择使用哪一种类型的文件.
若你想在java的文件对话框中做到这样的功能,你必须实现FileFilter这个抽象类.此抽象类里面定义了两个空的方法,分别是
accept(File f)与getDescripton().当目录里的文件与设置的文件类型相符时,accept()方法就会返回true,并将此文件显示在文件
对话框中.而getDescription()方法则是对此文件类型的描述,可由程序设计者自定义,如"*.java"等等.要设置选择文件类型对话框
你可以使用JFileChooser的addChoosableFileFilter()方法或是setFileFilter()方法.下面这个例子我们实现FileFilter的功能,让
用户打开文件时可以选择显示所有文件,或是*.java文件,亦或是*.class文件.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.File;//由于我们在程序中要使用到File与FileFilter对象,因此要import File与FileFilter这两个类.
import javax.swing.filechooser.FileFilter;
public class FileFilterDemo implements ActionListener{
JFrame f=null;
JLabel label=null;
JFileChooser fileChooser=null;
public FileFilterDemo(){
f=new JFrame("FileFilterDemo");
Container contentPane=f.getContentPane();
JButton b=new JButton("打开文件");
b.addActionListener(this);
label=new JLabel(" ",JLabel.CENTER);
label.setPreferredSize(new Dimension(150,30));
contentPane.add(label,BorderLayout.CENTER);
contentPane.add(b,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
public static void main(String[] args){
new FileFilterDemo();
}
//处理用户按下"打开旧文件"按钮事件.
public void actionPerformed(ActionEvent e){
fileChooser=new JFileChooser("C://winnt");//以c://winnt为打开文件为对话框的默认路径
//利用addChoosableFileFilter()方法加入欲过滤的文件类型,使用addChoosableFileFilter()可以加入多种文件类型,
//若你只需要过滤出一种文件类型,可使用setFileFilter()方法.
fileChooser.addChoosableFileFilter(new JAVAFileFilter("class"));
fileChooser.addChoosableFileFilter(new JAVAFileFilter("java"));
int result=fileChooser.showOpenDialog(f);
if (result==JFileChooser.APPROVE_OPTION){
File file=fileChooser.getSelectedFile();
label.setText("你选择了:"+file.getName()+"文件");
}else if (result==fileChooser.CANCEL_OPTION){
label.setText("你没有选取文件");
}
}
}
//以JAVAFileFilter类继承FileFilter抽象类,并实现accept()与getDescription()方法.
class JAVAFileFilter extends FileFilter{
String ext;
public JAVAFileFilter(String ext){
this.ext=ext;
}
/*在accept()方法中,当程序所抓到的是一个目录而不是文件时,我们返回true值,表示将此目录显示出来.*/
public boolean accept(File file){
if (file.isDirectory()){
return true;
}
String fileName=file.getName();
int index=fileName.lastIndexOf('.');
if (index>0 && index
String extension=fileName.substring(index+1).toLowerCase();
//若所抓到的文件扩展名等于我们所设置要显示的扩展名(即变量ext值),则返回true,表示将此文件显示出来,否则返回
//true.
if (extension.equals(ext))
return true;
}
return false;
}
//实现getDescription()方法,返回描述文件的说明字符串!!!
public String getDescription(){
if (ext.equals("java"))
return "JAVA Source File(*.java)";
if (ext.equals("class"))
return "JAVA Class File(*.class)";
return "";
}
}
13-1-3:建立具有特殊文件类型的图标的JFileChooser:
在上个范例中,读者可以发现若你选择显示所有文件时,文件类型图标不会因扩展名的不同而有所区别,这样可能造成用户混淆
或是使用上的不方便.
要解决这个问题,你必须再实现FileView这个抽象类,此抽象类定义了5个空的方法,如下表所示:
FileView方法:
String getDescription(File f):返回对这个文件的描述,如这是一张风景图片等.
Icon getIcon(File f):返回文件Icon图标.
String getName(File f):返回文件名.
String getTypeDescription(File f):返回文件类型描述,如:"JAVA Source File"等等.
Boolean isTraversable(File f):返回目录是否可浏览.
当你实现好这5个方法后,就可以利用JFileChooser的setFileView()方法来设置文件类型图标.我们来看下面的范例:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.File;
import javax.swing.filechooser.*;
public class FileIconFilterDemo implements ActionListener
{
JFrame f = null;
JLabel label = null;
JFileChooser fileChooser = null;
public FileIconFilterDemo()
{
f = new JFrame("FileIconFilter Demo");
Container contentPane = f.getContentPane();
JButton b = new JButton("打开文件");
b.addActionListener(this);
label = new JLabel(" ",JLabel.CENTER);
label.setPreferredSize(new Dimension(150,30));
contentPane.add(label,BorderLayout.CENTER);
contentPane.add(b,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
new FileIconFilterDemo();
}
public void actionPerformed(ActionEvent e)
{
fileChooser = new JFileChooser("c://winnt");
fileChooser.addChoosableFileFilter(new JAVAFileFilter("class"));
fileChooser.addChoosableFileFilter(new JAVAFileFilter("java"));
fileChooser.setFileView(new FileIcon());
int result = fileChooser.showOpenDialog(f);
if(result == JFileChooser.APPROVE_OPTION)
{
File file = fileChooser.getSelectedFile();
label.setText("您选择了:"+file.getName()+"文件");
}else if (result == fileChooser.CANCEL_OPTION){
label.setText("您没有选择任何文件");
}
}
}
class JAVAFileFilter extends FileFilter
{
String ext;
public JAVAFileFilter(String ext)
{
this.ext = ext;
}
public boolean accept(File file)
{
if (file.isDirectory())
return true;
String fileName = file.getName();
int index = fileName.lastIndexOf('.');
if (index > 0 && index < fileName.length()-1) {
String extension = fileName.substring(index+1).toLowerCase();
if (extension.equals(ext))
return true;
}
return false;
}
public String getDescription(){
if (ext.equals("java"))
return "JAVA Source File (*.java)";
if (ext.equals("class"))
return "JAVA Class File (*.class)";
return "";
}
}
class FileIcon extends FileView
{
public String getName(File f) {
return null; //返回值为null的话,java look and feel功能会处理掉这个项目,并取得相关值来加以设置.
//一般而言可以使用f.getName()当返回值.
}
public String getDescription(File f) {
return null; //返回值为null的话,java look and feel功能会处理掉这个项目,并取得相关值来加以设置.
//你也可以自己设置对此图片的描素,如这是一张风景图片等等.
}
public String getTypeDescription(File f)
{
String extension = getExtensionName(f);
if(extension.equals("java"))
return "JAVA Source File";
if(extension.equals("class"))
return "JAVA Class File";
return "";
}
public Icon getIcon(File f)
{
String extension = getExtensionName(f);
if(extension.equals("java"))
return new ImageIcon("java.gif");
if(extension.equals("class"))
return new ImageIcon("class.gif");
return null;
}
public Boolean isTraversable(File f) {
return null; //返回值为null的话,java look and feel功能会处理掉这个项目,并取得相关值来加以设置.
//若佻不希望某个目录被浏览,则返回值可以设为Boolean.FALSE.
}
public String getExtensionName(File f)//在FileIcon类中我们增加一个getExtensionName()方法,用来返回文件的扩展名
{ //名称.
String extension ="";
String fileName = f.getName();
int index = fileName.lastIndexOf('.');
if (index > 0 && index < fileName.length()-1) {
extension = fileName.substring(index+1).toLowerCase();
}
return extension;
}
}
13-2:建立颜色选择对话框(JColorChooer):
JColorChooer的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JColorChooser
Color Chooser可以让你选择所想要的颜色,并更改某个组件的颜色.例如在小画家中,你可以在画板上画上图案,并选择各式各样
的颜色来加以装饰;至于颜色的选择上,你可以在小画家中找到颜色选择对话框.
JColorChooser构造函数:
JColorChooser():建立一个JColorChooer对象,默认颜色为白色.
JColorChooser(Color initialColor):建立一个JColorChooer对象,并设置初始颜色.
JColorChooser(ColorSelectionModel modal):以ColorSelectionModel构造JColorChooser对象.
13-2-1:轻松输出颜色选择对话框:
最常使用JColorChooser的方式是使用JColorChooser的静态方法showDialog().也就是说在大部份的情况下,我们不会new一个
JColorChooser对象,而是直接使用JColorChooser的静态方法(showDialog())来输出颜色选择对话框.利用这个方法我们亦可以得到
用户所选择的颜色,若用户没有选择则返回null值.
另外还有一个使用JColorChooser常用的方式,那就是使用createDialog()静态方法.使用这个静态方法后会得到一个JDialog对
象,我们可以利用这个JDialog对象对颜色选择对话框做更多的设置.不过利用这个方法必须配合JColorChooser对象才行,也就是必须
new出一个JColorChooser对象来.下面范例我们先介绍第一种最简单的也是最实用的JColorChooser选择颜色完毕后就能更改JLabel
上的背景颜色.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;
public class ColorChooserDemo1 extends MouseAdapter
{
JFrame f = null;
JLabel label = null;
JLabel label1 = null;
JLabel label2 = null;
Rectangle rec1 = null;
Rectangle rec2 = null;
public ColorChooserDemo1()
{
f = new JFrame("ColorChooser Example");
Container contentPane = f.getContentPane();
contentPane.addMouseListener(this);
label = new JLabel(" ",JLabel.CENTER);
label.setPreferredSize(new Dimension(300,20));
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,2));
label1 = new JLabel("左Label",JLabel.CENTER);
label1.setBackground(Color.red);
label1.setForeground(Color.black);
label1.setOpaque(true);
label1.setBounds(0, 0, 150, 150);
panel.add(label1);
label2 = new JLabel("右Label",JLabel.CENTER);
label2.setBackground(Color.green);
label2.setForeground(Color.black);
label2.setOpaque(true);
label2.setBounds(150, 0, 150, 150);
panel.add(label2);
rec1 = label1.getBounds();
rec2 = label2.getBounds();
contentPane.add(panel,BorderLayout.CENTER);
contentPane.add(label,BorderLayout.SOUTH);
f.setSize(new Dimension(300,150));
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] arg)
{
SwingUtil.setLookAndFeel();
new ColorChooserDemo1();
}
//实现MouseAdapter中的mousePressed()与mouseClicked()方法.当按下鼠标时,就能知道鼠标光标目前的位置.当连续键击鼠标
//两次时,若光标所在位置在label中,就会出现颜色选择对话框,用户可选择任一颜色更改label的颜色.
public void mousePressed(MouseEvent e) {
label.setText("目前鼠标坐标(X,Y)为:("+e.getX()+","+e.getY()+")");
}
public void mouseClicked(MouseEvent e)
{
Point point = e.getPoint();
if (e.getClickCount() ==2)
{
if(rec1.contains(point))
{ /*利用JColorChooser的showDialog()静态方法输出颜色选择对话框,showDialog()中的3个参数依次是:
*对话框的父组件,颜色选择对话框标题,与对话框默认颜色.当用户选择完颜色之后,按下"OK"按钮则返回
*Color对象,若按下"Cancel"按钮则返回null值.
*/
Color color = JColorChooser.showDialog(
f,"Change label1 Color",Color.white);
if (color != null) //若为null值表示用户按下Cancel按钮
label1.setBackground(color);
}
if(rec2.contains(point))
{
Color color = JColorChooser.showDialog(
f,"Change label2 Color",Color.yellow);
if (color != null) //若为null值表示用户按下Cancel按钮
label2.setBackground(color);
}
}
}
}
class SwingUtil{
public static final void setLookAndFeel() {
try{
Font font = new Font("JFrame", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (UIManager.get(key) instanceof Font) {
UIManager.put(key, font);
}
}
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
AlloyTheme theme = new GlassTheme();
LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
UIManager.setLookAndFeel(alloyLnF);
}catch(UnsupportedLookAndFeelException ex){
ex.printStackTrace();
}
}
}
13-2-2:建立JColorChooser对象输出颜色选择对话框:
接下来我们介绍刚刚所提到使用JColorChooser的第二种方式,也就是使用createDialog()静态方法来输出颜色选择对话框.使
用这种方式的好处是颜色选择对话框可以做出多样性的变化,例如你可以使用JDialog中的setMenuBar()方法在颜色选择对话框中加
入菜单栏,或是利用JDialog的getContentPane()方法取得JDialog的ContentPane,然后对此ContentPane来做处理.下面范例我们修改
上个范例程序,并利用createDialog()方式来输出JColorChooser:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorChooserDemo2 extends MouseAdapter implements ActionListener
{
JFrame f = null;
JLabel label = null;
JLabel label1 = null;
JLabel label2 = null;
Rectangle rec1 = null;
Rectangle rec2 = null;
JDialog dialog = null;
JColorChooser colorChooser = null;
public ColorChooserDemo2()
{
f = new JFrame("ColorChooser Example");
Container contentPane = f.getContentPane();
contentPane.addMouseListener(this);
label = new JLabel(" ",JLabel.CENTER);
label.setPreferredSize(new Dimension(300,20));
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1,2));
label1 = new JLabel("左Label",JLabel.CENTER);
label1.setBackground(Color.red);
label1.setForeground(Color.black);
label1.setOpaque(true);
label1.setBounds(0, 0, 150, 150);
panel.add(label1);
label2 = new JLabel("右Label",JLabel.CENTER);
label2.setBackground(Color.green);
label2.setForeground(Color.black);
label2.setOpaque(true);
label2.setBounds(150, 0, 150, 150);
panel.add(label2);
rec1 = label1.getBounds();
rec2 = label2.getBounds();
contentPane.add(panel,BorderLayout.CENTER);
contentPane.add(label,BorderLayout.SOUTH);
//建立一个新的JColorChooser对象,默认颜色为白色.
colorChooser = new JColorChooser();
/*利用JColorChooser的createDialog()静态方法取得JDialog对象,createDialog()方法的最后两个参数是用来处理颜色
*选择对话框的"OK"与"Cancel"键的ActionEvent事件.读者可发现,这边并没有对颜色选择对话框的"Reset"做处理,因为
*内部系统会自动处理此事件,如此可减轻程序设计师的负担.
*/
dialog = colorChooser.createDialog(f, //parent component
"Change Color", //title
true, //modal
colorChooser, //JColorChooser
this,//okListenr
this);//cancelListener
f.setSize(new Dimension(300,150));
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] arg)
{
new ColorChooserDemo2();
}
public void mousePressed(MouseEvent e) {
label.setText("目前鼠标坐标(X,Y)为:("+e.getX()+","+e.getY()+")");
}
boolean flag = true;
public void mouseClicked(MouseEvent e)
{
Point point = e.getPoint();
//判断Double Click鼠标时的所在位置,若在label1或label2上则设置对话框的Title,并用show()方法将此对话框显示出来.
if (e.getClickCount() ==2)
{
if(rec1.contains(point))
{
flag = true;
dialog.setTitle("Change label1 Color");
dialog.show();
}
if(rec2.contains(point))
{
flag = false;
dialog.setTitle("Change label2 Color");
dialog.show();
}
}
}
/*处理用户对颜色选择对话框中的按钮事件.当用户按下"OK"键时,便将label的背景颜色改变成用户所选择的颜色.当用户
*按下"Cancel"键时,则会用Dialog类所提供的dispose()方法就可以关闭颜色选择对话框了.
*/
public void actionPerformed(ActionEvent ae)
{
if(ae.getActionCommand().equals("OK"))
{
if (flag == true)
label1.setBackground(colorChooser.getColor());
else
label2.setBackground(colorChooser.getColor());
}
if(ae.getActionCommand().equals("Cancel"))
dialog.dispose();
}
}
13-2-3:将JColorChooser置于一般容器中显示.
我们刚刚所讲的JColorChooser都是以对话框的形式出现.事实上JColorChooser可以置于一般的java容器上,不过这时候你就必
须实际构造出JColorChooser对象,并使用ColorSelectionModel来管理用户所选择的颜色.ColorSelectionModel本身是个interface
.里面定义一些用户选择颜色或设置颜色的方法,并有addChangeListener()方法来检测用户是否改变了颜色的选择.要使用到
ColorSelectionModel Interface所定义的方法,理论上我们必须实现它,然而java本身可利用JColorChooser所提供的
getSelectionModel()方法得到ColorSelectionModel的实体.这时候就可以直接以ColorSelectionModel的addChangeListener()方法
来检测用户是否对颜色的选择有所改变,而不需要再另外实现这些方法.
每当用户JColorChooser上做一次颜色的改变时,就会触发ChangeEvent事件,因此我们必须实现ChangeListener界面来处理这个
事件.此界面只定义了一个方法,那就是stateChanged().下面范例我们将JColorChooser放在JPanel上,并在label上输出用户所选择
的颜色与颜色参数.
import java.awt.*;
import java.awt.event.*;//ChangeEvent是Swing的事件,因此我们必须将Swing的event package import进来.
import javax.swing.*;
import javax.swing.colorchooser.*;
import javax.swing.event.*;
public class ColorChooserDemo3 implements ChangeListener
{
JFrame f = null;
JLabel label = null;
JColorChooser colorChooser = null;
public ColorChooserDemo3()
{
f = new JFrame("ColorChooser Example");
Container contentPane = f.getContentPane();
label = new JLabel(" ",JLabel.CENTER);
//设定label背景颜色为不透明,这样才可以将label的背景颜色显示出来
label.setOpaque(true);
//设定label上字体的颜色,也就是label的前景颜色
label.setForeground(Color.black);
JPanel panel = new JPanel();
/*建立一个JColorChooser对象,并以getSelectionModel()方法取得ColorSelectionModel实体,并在这个实体上以
*addChangeListener()方法检测用户是否有改变颜色.
*/
colorChooser = new JColorChooser();
/****add code***/
//此处为下面"13-2-4中所要加代码的区块"
/****add code***/
panel.add(colorChooser);
ColorSelectionModel selectModel =
colorChooser.getSelectionModel();
selectModel.addChangeListener(this);
contentPane.add(label,BorderLayout.NORTH);
contentPane.add(panel,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] arg)
{
new ColorChooserDemo3();
}
//实现ChangeListener Interface,stateChanged()方法是在处理ChangeEvent事件.当用户改变颜色的选择时,我们就在label
//输出用户所选择的颜色,并显示颜色参数.
public void stateChanged(ChangeEvent e)
{
Color color = colorChooser.getColor();
label.setBackground(color);
label.setText("您选择的颜色参数为:R:"+color.getRed()+
" G:"+color.getGreen()+" B:"+color.getBlue());
}
}
13-2-4:改变JColorChooser的颜色选择面版.
在以前我们曾经提到JColorChooser提供3种面版让我们选择,分别"Swatches","HSB"与"RGB".这3个面版是java已经构造好的颜
色面版,如果佻要自行产生自己所设计的颜色面版,你可以继承AbstractColorChooserPanel这个抽象类,并实现里面的抽象方法,这个
抽象类位于javax.swing.colorchooser这个package中.当你实现完成之后,你可以使用JColorChooser类提供的addChooserPanel()
方法,或是setChooserPanels()方法,将你所设计的颜色面版增加到上图的颜色显示面版中.
若你想删除某一个颜色面版模式,你可以先使用JColorChooser类所提供的getChooserPanels()方法,得到类型为
AbstractColorChooserPanel的Array Object.例如在上例中运行所示,"Swatches"就会放在此类型的Array[0]中,面"HSB"会放在
Array[1]中,以此类推.得到此Array Object之后,我们就可以利用JColorChooser类提供的removeChooserPanel()方法.决定删除一个
颜色面版.例如我们若要删除上例运行所示的"HSB"面版,我们可以在上面范例/****add code***/里面增加这2行程序:
AbstractColorChooserPanel[] colorPanel=colorChooser.getChooserPanels();
colorChooser.removeChooserPanel(colorPanel[1]);
13-3:建立分隔线(JSeparator):
JSeparator)的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JSeparator
JSeparator通常用在菜单(Menu)或工具栏(ToolBar)上,可以明显地分格出不同的功能区域.在JMenu或JPopupMenu中我们可以使用
addSeparator()方法轻易的加入分隔线,但若是在一般的面版中呢?这时候我们必须自行建立JSeparator对象,然后再依照自己所需将
分隔线放在所想要的位置上.JSeparator有水平与垂直两种,建立的方式非常简单,我们来看看JSeparator的构造函数:
JSeparator构造函数:
JSeparator():建立水平的JSeparator组件.
JSeparator(int orientation):建立水平或垂直的JSeparator组件.
JSeparator类所提供的方法跟其他Swing组件比较起来算是少了许多,因为分隔线本身并没有什么功能可言,主要是设置分隔线的方
向,其他如分隔线的长短或设置位置方法,都可以在它的父类JComponent中找到.下面我们来看如何使用JSeparator,并显示水平与垂
直分隔线的外观.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SeparatorDemo1
{
JFrame f = null;
public SeparatorDemo1()
{
f = new JFrame("Separator Example");
Container contentPane = f.getContentPane();
contentPane.setLayout(new BorderLayout(1,2));
JPanel panel1 = new JPanel(new GridLayout(2,1));
JLabel label = new JLabel("水平分隔线",JLabel.CENTER);
JSeparator seph = new JSeparator();
panel1.add(label);
panel1.add(seph);
JTextArea textarea = new JTextArea();
textarea.setPreferredSize(new Dimension(150,100));
JPanel panel2 = new JPanel(new BorderLayout());
panel2.add(panel1,BorderLayout.NORTH);
panel2.add(textarea,BorderLayout.CENTER);
JPanel panel3 = new JPanel(new GridLayout(1,3));
label = new JLabel("垂直");
label.setVerticalAlignment(JLabel.CENTER);
panel3.add(label);
JSeparator sepv = new JSeparator();
sepv.setOrientation(JSeparator.VERTICAL);
panel3.add(sepv);
contentPane.add(panel2,BorderLayout.CENTER);
contentPane.add(panel3,BorderLayout.EAST);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] arg)
{
new SeparatorDemo1();
}
}
++ Swing程序设计
++ Slider,Timer,Progress的使用
滑动杆(Slider),时间控制(Timer),进度元件(Progress)的使用与介绍:
14-1:使用JSlider组件:
JSlider的类层次结构图:
java.lang.Object
--java.awt.COmponent
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JSlider
我们曾在前面提到JScrollBar这个组件,可以让用户决定拉曳时一次滚动的区域大小,并且可以得到目前滚动杆上的值,看起来JScrollBar好象可以当作这
种微调的组件.然而JScrollBar通常置于窗口的最右边或最下面,且常JScrollBar来使用,因此在外观上或
实际应用上并不适合当微调工具使用,不过不用担心,java提供了一个特别为微调设计的组件,那就是JSlider.JSlider不仅可以置于
面版的任何地方,也可以在JSlider上标上刻度与数字,既美观又实用,我们现在就来看如何使用JSlider吧.
JSlider的构造函数:
JSlider():建立一个水平的JSlider对象,刻度从0-100,初始刻度为50.
JSlider(BoundedRangeModel brm):使用默认模式建立一个水平的JSlider对象.
JSlider(int orientation):建立一个自定义方向的JSlider对象,刻度从0-100,初始刻度为50.
JSlider(int min,int max):建立一个水平的JSlider对象,自定义刻度,从min-max,初始刻度为50.
JSlider(int min, int max,int value):建立一个水平的JSlider的对象,自定义刻度与初始值.
JSlider(int orientation,int min,int max,int value):建立一个自定义方向,刻度与刻度初始值的JSlider对象.
要使用JSlider组件就不得不提到JSlider事件的处理.当用户在JSlider上滑动杆时,就会产生ChangeEvent事件,若我们要处理
ChangeEvent事件就必须实作ChangeListener界面,此界面定义了一个方法,那就是stateChanged().通常我们在这个方法上会取得或
置滑动杆的相关信息,例如滑动杆的延伸区(extent),最大最小值或滑动杆目前所在刻度等等.我们来看下一节所举的范例:
14-1-1:建立JSlider组件:
这个范例我们建立了3个JSlider组件,并对每个JSlider组件做相关的设置,例如设置方向,初始值,最大最小值,延伸区值(extent)
等.
import javax.swing.*;//ChangeEvent事件是属于Swing事件,若要处理此事件必须将import swing的event package进来.
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
public class SliderDemo1 implements ChangeListener
{
JFrame f = null;
JSlider slider1;
JSlider slider2;
JSlider slider3;
JLabel label1;
JLabel label2;
JLabel label3;
public SliderDemo1()
{
f = new JFrame("JSlider Example");
Container contentPane = f.getContentPane();
JPanel panel1 = new JPanel();
panel1.setLayout(new GridLayout(2,1));
slider1 = new JSlider();//建立一个默认的JSlider组件.
label1 = new JLabel("目前刻度:"+slider1.getValue());
panel1.add(label1);
panel1.add(slider1);
panel1.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 1",TitledBorder.LEFT,
TitledBorder.TOP));
JPanel panel2 = new JPanel();
panel2.setLayout(new GridLayout(2,1));
/*下面五行程序建立一个水平方向的JSlider组件,并设置其取大值,最小值,初始值与延伸区值,所谓的延伸区值我们在前面
*JScrollBar中也提到过,意思是限制JSlider刻度可变动的范围,也就是说延伸区就像是一个障碍区,是无法通行的.延伸区
*设得越大,刻度可变动的范围就越小.例如若minimum值设为0,maximan值设为100,而extent值设为0,则JSlider刻度可变动
*的区域大小为100-50-0=50刻度(从0-50).
*/
slider2 = new JSlider(JSlider.HORIZONTAL);
slider2.setMinimum(0);
slider2.setMaximum(100);
slider2.setValue(30);
slider2.setExtent(50);
label2 = new JLabel("目前刻度:"+slider2.getValue());
panel2.add(label2);
panel2.add(slider2);
panel2.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 2",TitledBorder.LEFT,
TitledBorder.TOP));
JPanel panel3 = new JPanel();
panel3.setLayout(new GridLayout(2,1));
//下面两行建立一个具有最大最小值的JSlider组件,并设置此JSlider组件为垂直方向.
slider3 = new JSlider(20,80);
slider3.setOrientation(JSlider.VERTICAL);
label3 = new JLabel("目前刻度:"+slider3.getValue());
panel3.add(label3);
panel3.add(slider3);
panel3.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 3",TitledBorder.LEFT,
TitledBorder.TOP));
slider1.addChangeListener(this);
slider2.addChangeListener(this);
slider3.addChangeListener(this);
panel1.setPreferredSize(new Dimension(300,100));
panel2.setPreferredSize(new Dimension(300,100));
panel3.setPreferredSize(new Dimension(150,200));
GridBagConstraints c;
int gridx,gridy,gridwidth,
gridheight,anchor,fill,ipadx,ipady;
double weightx,weighty;
Insets inset;
GridBagLayout gridbag = new GridBagLayout();
contentPane.setLayout(gridbag);
gridx=0; //第0行
gridy=0; //第0列
gridwidth = 2; //占两单位宽度
gridheight = 1; //占一单位高度
weightx = 0; //窗口增大时组件宽度增大比率0
weighty = 0; //窗口增大时组件高度增大比率0
anchor = GridBagConstraints.CENTER; //容器大于组件size时将组件
//置于容器中央
fill = GridBagConstraints.BOTH; //窗口拉大时会填满水平与垂
//直空间
inset = new Insets(0,0,0,0); //组件间间距
ipadx = 0; //组件内水平宽度
ipady = 0; //组件内垂直高度
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel1,c);
contentPane.add(panel1);
gridx=0;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel2,c);
contentPane.add(panel2);
gridx=2;
gridy=0;
gridwidth = 1; //占一单位宽度
gridheight = 2; //占两单位高度
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel3,c);
contentPane.add(panel3);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
new SliderDemo1();
}
//处理ChangeEvent事件,当用户移动滑动杆时,label上的值会随着用户的移动而改变.
public void stateChanged(ChangeEvent e)
{
if ((JSlider)e.getSource() == slider1)
label1.setText("目前刻度:"+slider1.getValue());
if ((JSlider)e.getSource() == slider2)
label2.setText("目前刻度:"+slider2.getValue());
if ((JSlider)e.getSource() == slider3)
label3.setText("目前刻度:"+slider3.getValue());
}
}
注:由于slider3设置延伸区值(Extent)为50,因此slider2刻度可变动的区域只到50,因此当slider2超过50刻度时就算你再向右移
动,刻度值一样维持在50上.
14-1-2:为JSlider组件加入刻度.
上面这个例子中,你是否觉得好像少了什么?没错,就是刻度!接下来,我们来设置JSlider的刻度与数字,并增加一些设置项目,完
整的JSlider组件就大功告成了.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.util.*;
public class SliderDemo2 implements ChangeListener
{
JFrame f = null;
JSlider slider1;
JSlider slider2;
JSlider slider3;
JLabel label1;
JLabel label2;
JLabel label3;
public SliderDemo2()
{
f = new JFrame("JSlider Example");
Container contentPane = f.getContentPane();
JPanel panel1 = new JPanel();
panel1.setLayout(new GridLayout(2,1));
slider1 = new JSlider();
//setPaintTicks()方法是设置是否在JSlider加上刻度,若为true则下面两行才有作用。
slider1.setPaintTicks(true);
/*设置大刻度与小刻度之间的距离(setMajorTickSpacing()与setMinorTickSpacing()方法).例如若大刻度间距离为30,
*小刻度间距离为10,则表示2个大刻度间会有3个小刻度.
*/
slider1.setMajorTickSpacing(20);
slider1.setMinorTickSpacing(10);
//setPaintLabels()方法为设置是否数字标记,若设为true,则JSlider刻度上就会有数值出现。
slider1.setPaintLabels(true);
//setPaintTrack()方法表示是否出现滑动杆的横杆。默认值为true.
slider1.setPaintTrack(true);
//setSnapToTicks()方法表示一次移动一个小刻度,而不再是一次移动一个单位刻度。
slider1.setSnapToTicks(true);
label1 = new JLabel("目前刻度:"+slider1.getValue());
panel1.add(label1);
panel1.add(slider1);
panel1.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 1",TitledBorder.LEFT,
TitledBorder.TOP));
JPanel panel2 = new JPanel();
panel2.setLayout(new GridLayout(2,1));
slider2 = new JSlider(JSlider.HORIZONTAL);
slider2.setMinimum(0);
slider2.setMaximum(100);
slider2.setValue(30);
slider2.setExtent(50);
slider2.setPaintTicks(true);
slider2.setMajorTickSpacing(10);
slider2.setMinorTickSpacing(2);
slider2.setPaintLabels(true);
/*JComponent提供了一个putClientProperty()方法,可以使得JSlider中的小于滑动杆位置与大于滑动杆位置间的颜色不
*一样,这样的视觉效果会比较好,"JSlider.isFilled"值是定义在MetalSliderUI这个类的SLIDER_FILL常数中,此类是
*定义在java的JSlider默认外观,你可以在javax.swing.plaf.metal.package中找到这个类。
*/
slider2.putClientProperty("JSlider.isFilled",Boolean.TRUE);
label2 = new JLabel("目前刻度:"+slider2.getValue());
panel2.add(label2);
panel2.add(slider2);
panel2.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 2",TitledBorder.LEFT,
TitledBorder.TOP));
JPanel panel3 = new JPanel();
panel3.setLayout(new GridLayout(2,1));
slider3 = new JSlider(20,80);
slider3.setOrientation(JSlider.VERTICAL);
slider3.setPaintTicks(true);
slider3.setMajorTickSpacing(30);
slider3.setMinorTickSpacing(10);
slider3.setPaintLabels(true);
slider3.putClientProperty("JSlider.isFilled",Boolean.TRUE);
label3 = new JLabel("目前刻度:"+slider3.getValue());
panel3.add(label3);
panel3.add(slider3);
panel3.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 3",TitledBorder.LEFT,
TitledBorder.TOP));
slider1.addChangeListener(this);
slider2.addChangeListener(this);
slider3.addChangeListener(this);
panel1.setPreferredSize(new Dimension(300,130));
panel2.setPreferredSize(new Dimension(300,130));
panel3.setPreferredSize(new Dimension(150,260));
GridBagConstraints c;
int gridx,gridy,gridwidth,
gridheight,anchor,fill,ipadx,ipady;
double weightx,weighty;
Insets inset;
GridBagLayout gridbag = new GridBagLayout();
contentPane.setLayout(gridbag);
gridx=0; //第0行
gridy=0; //第0列
gridwidth = 2; //占两单位宽度
gridheight = 1; //占一单位高度
weightx = 0;
weighty = 0;
anchor = GridBagConstraints.CENTER;
fill = GridBagConstraints.BOTH;
inset = new Insets(0,0,0,0);
ipadx = 0;
ipady = 0;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel1,c);
contentPane.add(panel1);
gridx=0;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel2,c);
contentPane.add(panel2);
gridx=2;
gridy=0;
gridwidth = 1; //占一单位宽度
gridheight = 2; //占两单位高度
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel3,c);
contentPane.add(panel3);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
new SliderDemo2();
}
public void stateChanged(ChangeEvent e)
{
if ((JSlider)e.getSource() == slider1)
label1.setText("目前刻度:"+slider1.getValue());
if ((JSlider)e.getSource() == slider2)
label2.setText("目前刻度:"+slider2.getValue());
if ((JSlider)e.getSource() == slider3)
label3.setText("目前刻度:"+slider3.getValue());
}
}
14-1-3:自定义JSlider标记名称:
我们在上个范例中看到的JSlider标记都是数字形态,当然我们也可以自定义自己想要的标记文字,这时候就必须使用JSlider所
提供的setLabelTable()方法。我们来看下面的例子。
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.util.*;
public class SliderDemo3 implements ChangeListener
{
JFrame f = null;
JSlider slider1;
JSlider slider2;
JSlider slider3;
JLabel label1;
JLabel label2;
JLabel label3;
public SliderDemo3()
{
f = new JFrame("JSlider Example");
Container contentPane = f.getContentPane();
JPanel panel1 = new JPanel();
panel1.setLayout(new GridLayout(2,1));
slider1 = new JSlider();
slider1.setPaintTicks(true);
slider1.setMajorTickSpacing(20);
slider1.setMinorTickSpacing(10);
slider1.setPaintLabels(true);
slider1.setPaintTrack(true);
slider1.setSnapToTicks(true);
label1 = new JLabel("目前刻度:"+slider1.getValue());
panel1.add(label1);
panel1.add(slider1);
panel1.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 1",TitledBorder.LEFT,
TitledBorder.TOP));
Hashtable table = new Hashtable();
table.put(new Integer( 0 ),new JLabel("低"));
table.put(new Integer( 50 ),new JLabel("中"));
table.put(new Integer( 100 ),new JLabel("高"));
slider1.setLabelTable(table);
JPanel panel2 = new JPanel();
panel2.setLayout(new GridLayout(2,1));
slider2 = new JSlider(JSlider.HORIZONTAL);
slider2.setMinimum(0);
slider2.setMaximum(100);
slider2.setValue(30);
slider2.setExtent(50);
slider2.setPaintTicks(true);
slider2.setMajorTickSpacing(10);
slider2.setMinorTickSpacing(5);
slider2.setPaintLabels(true);
slider2.putClientProperty("JSlider.isFilled",Boolean.TRUE);
label2 = new JLabel("目前刻度:"+slider2.getValue());
panel2.add(label2);
panel2.add(slider2);
panel2.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 2",TitledBorder.LEFT,
TitledBorder.TOP));
table = new Hashtable();
table.put(new Integer( 0 ),new JLabel("弱"));
table.put(new Integer( 25 ),new JLabel("有点弱"));
table.put(new Integer( 50 ),new JLabel("中"));
table.put(new Integer( 75 ),new JLabel("有点强"));
table.put(new Integer( 100 ),new JLabel("强"));
slider2.setLabelTable(table);
JPanel panel3 = new JPanel();
panel3.setLayout(new GridLayout(2,1));
slider3 = new JSlider(20,80);
slider3.setOrientation(JSlider.VERTICAL);
slider3.setPaintTicks(true);
slider3.setMajorTickSpacing(30);
slider3.setMinorTickSpacing(10);
slider3.setPaintLabels(true);
slider3.putClientProperty("JSlider.isFilled",Boolean.TRUE);
label3 = new JLabel("目前刻度:"+slider3.getValue());
panel3.add(label3);
panel3.add(slider3);
panel3.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(),"Slider 3",TitledBorder.LEFT,
TitledBorder.TOP));
slider1.addChangeListener(this);
slider2.addChangeListener(this);
slider3.addChangeListener(this);
panel1.setPreferredSize(new Dimension(300,130));
panel2.setPreferredSize(new Dimension(300,130));
panel3.setPreferredSize(new Dimension(150,260));
GridBagConstraints c;
int gridx,gridy,gridwidth,
gridheight,anchor,fill,ipadx,ipady;
double weightx,weighty;
Insets inset;
GridBagLayout gridbag = new GridBagLayout();
contentPane.setLayout(gridbag);
gridx=0; //第0行
gridy=0; //第0列
gridwidth = 2; //占两单位宽度
gridheight = 1; //占一单位高度
weightx = 0;
weighty = 0;
anchor = GridBagConstraints.CENTER;
fill = GridBagConstraints.BOTH;
inset = new Insets(0,0,0,0);
ipadx = 0;
ipady = 0;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel1,c);
contentPane.add(panel1);
gridx=0;
gridy=1;
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel2,c);
contentPane.add(panel2);
gridx=2;
gridy=0;
gridwidth = 1; //占一单位宽度
gridheight = 2; //占两单位高度
c = new GridBagConstraints(gridx,gridy,gridwidth,gridheight,
weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(panel3,c);
contentPane.add(panel3);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
new SliderDemo3();
}
public void stateChanged(ChangeEvent e)
{
if ((JSlider)e.getSource() == slider1)
label1.setText("目前刻度:"+slider1.getValue());
if ((JSlider)e.getSource() == slider2)
label2.setText("目前刻度:"+slider2.getValue());
if ((JSlider)e.getSource() == slider3)
label3.setText("目前刻度:"+slider3.getValue());
}
}
说明:要改变标记值必须使用setLabelTable(Dictionary table)方法,参数Dictionary本身是一个抽象类,我们并不能直接就new
出一个Dictionary对象,而必须使用它的子类Hashtable来产生Dictionary类型的对象。Hashtable存储信息的方式是以
key-value pair类型来存储,换名话说,当你要找某个对象时,你就必须知道此对象的key值。而在此例中,我们要换原有
JSlider上的文字,必须指明那个数字要理发成什么文字。例如table.put(new Integer(0)),new JLabel("弱"))就表示数字
0要变更成文字"弱",在Hashtable中,Integer(0)就是对象JLabel("弱")的key值。
14-2:使用Timer组件:
java.lang.Object
--javax.swing.Timer
使用Timer组件可以让你在一段时间内依次做出你指定的操作,这在动画的展示上非常有用。如果你有用过如ACDsee这类的看图
软件,你可以发现这类软件都会提供一种功能,那就是自动换图的功能,而且也可以让你设置换图时间间隔的长短。在java中,
swing的Timer组件就可以让你做到这样的功能,而且非常容易使用,下面我们先来看Timer的构造函数。
Timer构造函数:
Timer(int delay,ActionListener listener):建立一个Timer组件,并在每一次delay的时间点上触发ActionEvent.
使用Timer组件它会在根据你所给予的delay时间,周期性的触发ActionEvent事件,如果你要处理这个事件,你必须实作
ActionListener界面所定义的actionPerformed()方法。要开始激活Timer组件,你可以用start()方法,要停止Timer组件可以使用
stop()方法,要从新激活Timer组件可以使用restart()方法,若只想Timer组件只触发一次ActionEvent事件,可利用
setRepeats(false)方法,将参数设为false,若要设置delay时间则可用setDelay()方法。
事实上使用Timer组件表示在程序背后是利用Threads在运行Timer的工作,因此你当然也可以利用Thread的功能来自行制造出这
样的效果,不过这不在本书的讨论范围内,下面的范例我们实作一个显示图程序,可让用户调整显示图时间的快慢。
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.util.*;
public class TimerDemo1 implements ActionListener,ChangeListener
{
JFrame f = null;
ImageIcon[] icons;
JSlider slider1;
JLabel label;
JToggleButton toggleb1,toggleb2;
JButton b;
javax.swing.Timer timer;
int index = 0;
public TimerDemo1()
{
f = new JFrame("Timer Example");
Container contentPane = f.getContentPane();
icons = new ImageIcon[5];
for (int i=0 ; i<5 ; i++)
icons[i] = new ImageIcon(".//icons//"+(i+1)+".jpg");
label = new JLabel(icons[0]);
JPanel panel1 = new JPanel();
panel1.setLayout(new GridLayout(2,1));
slider1 = new JSlider();
slider1.setPaintTicks(true);
slider1.setMajorTickSpacing(20);
slider1.setMinorTickSpacing(10);
slider1.setPaintLabels(true);
slider1.addChangeListener(this);
panel1.add(slider1);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1,3));
toggleb1 = new JToggleButton("Start");
toggleb1.addActionListener(this);
buttonPanel.add(toggleb1);
b = new JButton("Restart");
b.addActionListener(this);
buttonPanel.add(b);
toggleb2 = new JToggleButton("Don't Repeat");
toggleb2.addActionListener(this);
buttonPanel.add(toggleb2);
panel1.add(buttonPanel);
Hashtable table = new Hashtable();
table.put(new Integer( 0 ),new JLabel("е"));
table.put(new Integer( 50 ),new JLabel("い"));
table.put(new Integer( 100 ),new JLabel("篊"));
slider1.setLabelTable(table);
/*由于java的Timer组件有两种,一种是javax.swing.Timer,一种是java.util.Timer,若我们在程序中import了这两种
*package,则系统将不晓得到底要产生哪种Timer组件,就如同本范例一般,因此我们必须在new Timer组件的同时,指
*定要new出哪一种类型的Timer组件。因此我们必须在new Timer组件的同时,指定要new出哪一种类型的Timer组件,在
*此我们当然是要产生Swing的Timer组件,在此我们当然是要产生Swing的Timer组件。
*/
timer = new javax.swing.Timer(slider1.getValue()*10,this);
contentPane.add(label,BorderLayout.CENTER);
contentPane.add(panel1,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
new TimerDemo1();
}
//处理按钮事件与Timer事件。
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == toggleb1)
{//当用户按下"start"按钮时,Timer开始运行,且"Start"按钮会变成"Stop",若用户再次按下"stop"按钮,则Timer暂停
//运行,且"stop"按钮变成"start".
if (e.getActionCommand().equals("Start"))
{
timer.start();
toggleb1.setText("Stop");
}
if (e.getActionCommand().equals("Stop"))
{
timer.stop();
toggleb1.setText("Start");
}
}
//当用户按下"Don't Repeat"按钮时,则Timer事件只触发一次,若再按一次"Don't Repeat"按钮,则Timer继续运行。
if (e.getSource() == toggleb2)
{
if(timer.isRepeats())
{
timer.setRepeats(false);
}
else
{
timer.setRepeats(true);
timer.start();
}
}
//当用户按下"Restart"按钮时,则Timer组件的delay值恢复成初如值,并重新运行Timer.
if (e.getSource() == b)
{
slider1.setValue(50);
timer.restart();
}
//处理Timer产生的ActionEvent事件,每次时间一到delay所设置的时间,label上的图片就会更换一次。
if (e.getSource() == timer)
{
if (index == 5)
index = 0;
label.setIcon(icons[index]);
label.repaint();
//f.pack(); //若要窗口随图形大小变化,可加入此行.
index++;
}
}
//处理slider所产生的ChangeEvent事件,当用户移动slider1的滑动杆时,等于从新设置Timer的delay时间。
public void stateChanged(ChangeEvent e1)
{
timer.setDelay(slider1.getValue()*10);
}
}
14-3:使用Progress Bar组件:
JProgressBar的类层次结构图:
java.lang.Object
--java.awt.Component
--java.awt.Container
--javax.swing.JComponent
--javax.swing.JProgressBar
当你在安装一个新软件时,系统会告知你目前软件安装的进度如何?才不会让你觉得程序好像死了,同样的,若你设计的程序所
需要的运行超过2秒以上,你应该显示程序正在运行中的图标,或直接显示程序运行的进度,这样就能让用户清楚知道程序到底是死
了还是继续运行,在swing中,JProgressBar组件提供了类似这样的功能,它可以簋简单地输出进度的变化情况,让你想要提供进度
信息时,不再需要自行绘制绘图组件,只需要使用JProgressBar再加上几行程序设置就可以了。以下是JProgressBar的范例,在此
范例中,我们使用Timer组件当作控制进度杆移动的速度,当用户按下"start"按钮,则进度杆线就会开始向右移动,并显示出目前
的进度信息。每当JProgressBar的值改变一次(利用setValue()方法),就会触发一次ChangeEvent事件,如果你要处理这个事件,
你必须实作ChangeListener界面所定义的stateChanged()方法,在此我们是将JPogressBar的移动信息放在label上。
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
public class ProgressBarDemo implements ActionListener,ChangeListener
{
JFrame f = null;
JProgressBar progressbar;
JLabel label;
Timer timer;
JButton b;
public ProgressBarDemo()
{
f = new JFrame("progressbar Example");
Container contentPane = f.getContentPane();
label = new JLabel(" ",JLabel.CENTER);
progressbar = new JProgressBar();
progressbar.setOrientation(JProgressBar.HORIZONTAL);
progressbar.setMinimum(0);
progressbar.setMaximum(100);
progressbar.setValue(0);
progressbar.setStringPainted(true);
progressbar.addChangeListener(this);
progressbar.setPreferredSize(new Dimension(200,30));
progressbar.setBorderPainted(false);
JPanel panel = new JPanel();
b = new JButton("Start");
b.addActionListener(this);
panel.add(b);
timer = new Timer(50,this);
contentPane.add(panel,BorderLayout.NORTH);
contentPane.add(progressbar,BorderLayout.CENTER);
contentPane.add(label,BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
new ProgressBarDemo();
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == b)
{
timer.start();
}
if(e.getSource() == timer)
{
int value = progressbar.getValue();
if( value < 100)
{
value++;
progressbar.setValue(value);
}
else
{
timer.stop();
progressbar.setValue(0);
}
}
}
public void stateChanged(ChangeEvent e1)
{
int value = progressbar.getValue();
if(e1.getSource() == progressbar)
{
label.setText("目前已完成进度:"+Integer.toString(value)+" %");
}
}
}
======================================================================================
++ Swing程序设计
++ 怎么计算中英文合并的字符串的长度
import java.io.*;
public class StringTest
{
public static void main(String[] args)
{
String aString = "这是一个测试串,This is a test string.";
String anotherString = null;
try {
anotherString = new String(aString.getBytes("GBK"), "ISO8859_1");
}
catch (UnsupportedEncodingException ex) {
}
System.out.println(aString.length() + "," + anotherString.length());
}
}
++ Swing程序设计
++ Java Application启动画面的制作
现象:
JBuilder启动时有一个启动画面,在Jbuilder所有的初始化工作都完成之后,启动画面消失,继而JBuilder可以开始使用。
解决方案:
该方案基于我所做过的一个项目。
1、新建一个启动画面Window类
java.awt.Window windowSplash;
2、调用prepareSplash()函数,初始化启动界面
private void prepareSplash()
{
Toolkit toolkit = Toolkit.getDefaultToolkit();
windowSplash = new Window( this );
Image image = toolkit.getImage( "images" + File.separator + "splash.gif" );
ImageCanvas canvas = new ImageCanvas( image );
windowSplash.add( canvas, "Center" );
Dimension scmSize = toolkit.getScreenSize();
int imgWidth = image.getWidth( this );
int imgHeight = image.getHeight( this );
windowSplash.setLocation( scmSize.width/2 - (imgWidth/2), scmSize.height/2 - (imgHeight/2) );
windowSplash.setSize( imgWidth, imgHeight );
}
3、在Application的JFrame类(主界面)中调用startSplash(),显示启动界面,然后初试化JFrame的各个可视化组件,初始化后台数据库等(如数据
库的连接)
private void startSplash()
{
windowSplash.setVisible( true );
windowSplash.toFront();
}
4、在所有的初始化工作完成之后,调用stopSplash()函数,停止显示启动画面
private void stopSplash()
{
windowSplash.dispose();
}
++ jar的基本操作
Jar文件的基本操作
1.创建相关
/>jar cf jar-file input-file(s)
/*
说明,windows下和UNIX下对目录结构的分隔符习惯不同,前者为/,后者为/ ,本文仅仅为了说明问题,并不严格加以说明。——注意,无论任何平
台,在manifest文件中均采用/
*/
/*
该形式的命令在当前目录下创建一个jar-file
c开关指明“创建”一个jar文件
f开关指明输出到文件,而不是stdout(标准输出)
jar-file如果不指明后缀,则默认为*.jar
空格用于分隔多个输入文件,可以使用通配符“*”
有必要时指明目录
开关出现的顺序不重要,但是如果有m开关则另当别论。
该命令默认创建一个manifest文件
*/
/*
对于java版本1,jar文件仅支持ASCII作文件名,java版本2则支持UTF-8编码的文件名。
*/
/*
关于创建,可用的其他开关:
v 当jar文件创建时,在stderr(java版本1)或stdout(java版本2)产生冗余(verbose)输出。报告添加到jar的文件名录。
0 (zero)指明不要压缩。
M 指明不要产生默认的manifest文件。
m 添加手工已编制好的manifest文件:
/>jar cmf existing-manifest jar-file input-file(s)
-C 在操作过程中转变目录(仅对java版本2)。
*/
/*
一个例子。
假设,如下目录结构(windows下):
TicTacToe/TicTacToe.class (文件)
TicTacToe/audio (子目录,该层下全是au文件)
TicTacToe/images (子目录,该层下全是gif文件)
如果要将该东东压入jar文件TicTacToe.jar,应在TicTacToe目录中(!)执行下面命令:
TicTacToe>jar cvf TicTacToe.jar TicTacToe.class audio images
jar程序会自动将audio和images目录及其子目录一咕脑(recursively)全压入TicTacToe.jar文件,该文件将出现于 TicTacToe/TicTacToe.jar
因为使用了verbose output开关,可以看到类似如下的输出:
adding: TicTacToe.class (in=3825) (out=2222) (deflated 41%)
adding: audio/ (in=0) (out=0) (stored 0%)
adding: audio/beep.au (in=4032) (out=3572) (deflated 11%)
adding: audio/ding.au (in=2566) (out=2055) (deflated 19%)
adding: audio/return.au (in=6558) (out=4401) (deflated 32%)
adding: audio/yahoo1.au (in=7834) (out=6985) (deflated 10%)
adding: audio/yahoo2.au (in=7463) (out=4607) (deflated 38%)
adding: images/ (in=0) (out=0) (stored 0%)
adding: images/cross.gif (in=157) (out=160) (deflated -1%)
adding: images/not.gif (in=158) (out=161) (deflated -1%)
如果:
TicTacToe>jar cvf0 TicTacToe.jar TicTacToe.class audio images
则表示只备份不压缩。
如果该目录内全是需要jar掉的文件及其相应目录结构:
TicTacToe>jar cvf TicTacToe.jar *
是比较简洁的写法。
如果不特别使用开关m或M,默认的manifest文件将产生于
META-INF/MANIFEST.MF
继承了GZIP的特点,-C开关用于跳到某目录,以改变所存入jar文件的目录结构。多半用于将原来位于不同目录结构的文件作jar时聚合在一起。例如:
TicTacToe>jar cf ImageAudio.jar -C images . -C audio .
产生的jar文件内容和结构:
META-INF/MANIFEST.MF
cross.gif
not.gif
beep.au
ding.au
return.au
yahoo1.au
yahoo2.au
(现在假设我们images子目录下还有子目录,像这样:
TicTacToe/images/jpg
jpg子目录下还有一些*.jpg文件那以上命令的结果应该是:
META-INF/MANIFEST.MF
jpg/AMAKUSA.jpg
jpg/UKYO.jpg
cross.gif
not.gif
beep.au
ding.au
return.au
yahoo1.au
yahoo2.au
说明了-C的真正含义。
)
*/
2.关于查看jar内容
/>jar tf jar-file
/*
t 开关指明jar文件的内容表(table of contents)。
f 开关指明该jar文件由命令行指出,如果不用该开关,jar则在stdin中期待一个文件名。
t和f出现的顺序无关,但是之间不能有空格。
该命令向stdout输出相应jar文件的内容表。
v 开关可以用于查看关于文件大小、最近更改日期等等详细内容。
*/
/*
例子。
TicTacToe>jar tf TicTacToe.jar
将在标准输出中看到:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
注意,无论在任何操作系统下(windows、Linux或Unix)所有文件结构均以正斜杠/(forward slash)分隔。而在jar文件中的路径显示都是相对
(relative)的。
又例。
TicTacToe>jar tvf TicTacToe.jar
显示如下:
256 Mon Apr 20 10:50:28 PDT 1998 META-INF/MANIFEST.MF
3885 Mon Apr 20 10:49:50 PDT 1998 TicTacToe.class
0 Wed Apr 15 16:39:32 PDT 1998 audio/
4032 Wed Apr 15 16:39:32 PDT 1998 audio/beep.au
2566 Wed Apr 15 16:39:32 PDT 1998 audio/ding.au
6558 Wed Apr 15 16:39:32 PDT 1998 audio/return.au
7834 Wed Apr 15 16:39:32 PDT 1998 audio/yahoo1.au
7463 Wed Apr 15 16:39:32 PDT 1998 audio/yahoo2.au
0 Wed Apr 15 16:39:44 PDT 1998 images/
157 Wed Apr 15 16:39:44 PDT 1998 images/cross.gif
158 Wed Apr 15 16:39:44 PDT 1998 images/not.gif
*/
3. 释放文件
/>jar xf jar-file [archived-file(s)]
/*
x 开关是“释放文件”的标志
f 开关指明是由命令行提供待释放jar文件的文件名,而不是stdin
jar-file 可以是一个带有路径的文件
[archived-file(s)] 指出期待释放的内容,如果略去这个参数,则将jar-file中的内容完全释放。
释放之后,原jar文件保持不变。
注意,当释放文件时,jar会覆盖目标目录下同名的文件(但之下不同名的目录和文件不会被洗掉(——覆盖的原则!))。
*/
/*
例子。
TicTacToe>jar xf TicTacToe.jar TicTacToe.class images/cross.gif
该命令做两件事情:
在当前目录下产生一个TicTacToe新的拷贝。
在当前目录下产生子目录images,并在其下产生一个cross.gif新的拷贝。如果该目录已经存在,则只作后一个动作。
可以用命令:
TicTacToe>jar xf TicTacToe.jar
释放整个TicTacToe.jar文件。
*/
4.jar归档和相应描述文件(manifest file)
jar归档实现多种功能,例如electronic signing, version control, package sealing, extensions。其中的 manifest文件发生了不可替
代的作用。
manifest像一个归档内容清单。(The manifest is a special file that can contain information about the files packaged in a JAR file.
)
manifest文件的默认和定制方法前面已经描述,下面看内容。
默认的MANIFEST.MF(java版本2制造):
————————————
Manifest-Version: 1.0
————————————
可见,manifest文件的表项形式为"header: value",由默认产生的manifest文件表项(entry)只包括描述manifest自身的一项(版本)。
java版本1和java版本2都对应相同的manifest标准(manifest版本一)。但是,两个java版本的jar产生的默认manifest文件却是不同的。如果是java版
本1,则产生MANIFEST.MF如下形式:
————————————
Manifest-Version: 1.0
Name: java/math/BigDecimal.class
SHA1-Digest: TD1GZt8G11dXY2p4olSZPc5Rj64=
MD5-Digest: z6z8xPj2AW/Q9AkRSPF0cg==
Name: java/math/BigInteger.class
SHA1-Digest: oBmrvIkBnSxdNZzPh5iLyF0S+bE=
MD5-Digest: wFymhDKjNreNZ4AzDWWg1Q==
————————————
可见,java版本1的MANIFEST.MF对jar包中每一个文件都有所描述,表项包括文件的路径名(pathname)和摘要值(digest value,指由文件内容产生
的某种哈希密文)。——注意Name和Digest之间没有空行。
这里的摘要值一般用于对jar文件签名(sign),但由于它不是总是很有必要,于是在java版本2中将其省掉了。(也是为了更好地将功能结构化。)
一言以蔽之,manifest记录什么样的文件信息完全取决于jar包的用途。(Exactly what file information is recorded in the manifest will
depend on what use you intend for the JAR file.)你可以根据jar文件打算扮演的何种角色,来修改manifest文件。
如果仅仅将jar用作一种简单的压缩方式(像一种zip),则不必关心manifest文件。
manifest用作特定用途(以下仅对java版本2):
1)java应用程序(application)以jar文件形式捆绑(bundle)
表项 Main-Class: classname 指明程序的入口(entry point)——即含有方法public static void main(String[] args){}的类。
2)下载扩展(Download Extensions)
下载扩展是指被其他jar文件的manifest文件所引用的jar文件(http://java.sun.com/docs/books/tutorial/ext/index.html)。
举典型一例,某个applet会被捆绑在一个jar文件内,该jar的manifest引用(指向)了一个或多个其他jar文件(这些文件serve as an extension(or
extensions) for the purpose of that applet)。当然,扩展之间可以相互引用。
下载扩展由引用者的相应manifest文件以Class-Path为头部(header field)的表项指明,例如:
Class-Path: servlet.jar infobus.jar acme/beans.jar
注意,The URLs in the Class-Path header are given relative to the URL of the JAR file of the applet or application.
3)包密封(Package Sealing)
这是指定义在同一个package内的所有的class都打包在同一个jar文件内。这样,可以保证版本一致性(version consistency)或者作为一种安全措施
(security measure)——避免默认的package可视性(当前目录.加入classpath之后)。
Seal一个包,格式如此:
————————————————
Name: myCompany/myPackage/
Sealed: true
————————————————
Name头(head)的值(value)指明该包对应的相对路径名(代码中"package myCompany.myPackage;")。(注意,它以/结尾以区别于文件名)。
4)包版本控制(Package Versioning)
参见 http://java.sun.com/products/jdk/1.2/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersioning
一个例子。
————————————————
Name: java/util/
Specification-Title: "Java Utility Classes"
Specification-Version: "1.2"
Specification-Vendor: "Sun Microsystems, Inc.".
Implementation-Title: "java.util"
Implementation-Version: "build57"
Implementation-Vendor: "Sun Microsystems, Inc."
————————————————
关于manifest格式的specification:
http://java.sun.com/products/jdk/1.2/docs/guide/jar/manifest.html
下面有关jar工具的m开关的说明。
如果要使用m开关,则先要准备一个用作manifest的文本文件。m开关的意思是合并(merge),作用是将该文件的内容(!)附加在默认的(或者已有
的)manifest之上(注意不是替换!)。
/>jar cmf manifest-addition jar-file input-file(s)
/>jar cfm jar-file manifest-addition input-file(s)
产生同样的结果,注意开关和参数的对应关系!
一个例子,用以说明jar、manifest和package的seal……
假设jar文件准备包含下列package(注意package没有进行jar时和目录是对应的):
myCompany/firstPackage/
myCompany/secondPackage/
myCompany/thirdPackage/
myCompany/fourthPackage/
如果要seal了firstPackage和thirdPackage,应该写一个这样的manifest:
sealInfo
————————————————
Name: myCompany/firstPackage/
Sealed: true
Name: myCompany/thirdPackage/
Sealed: true
————————————————
注意,该文本文件需要以一对回车换行结束,否则难通过parse程序。
设当前目录为myCompany的父目录。则,
>jar cmf sealInfo myJar.jar myCompany
在myJar.jar中产生了如下的manifest文档:
————————————————
Manifest-Version: 1.0
Name: myCompany/firstPackage/
Sealed: true
Name: myCompany/thirdPackage/
Sealed: true
————————————————
其中,第一行来自默认manifest,其他来自手工添加。
5.更新jar文件
java版本2的u开关用于更新已存在的jar文件(通过修改他的manifest或者增添新的文件)。
/>jar uf jar-file input-file(s)
u开关指明更新一个已存在的jar文件。
input-file(s)是将要add进jar-file里的文件列表,以空格分隔。
用这个命令,jar-file里同名同路径的文件将被覆盖。
正如前面创建jar文件所述,可以用-C开关转换路径。
/>jar umf manifest1 jar-file
该命令归并manifest1到jar-file的manifest文件中。
一个例子。
TicTacToe.jar有如下内容:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
设将要向jar归档中加入images/new.gif,应该在images的父目录中执行:
TicTacToe>jar uf TicTacToe.jar images/new.gif
则修改过的jar归档应该有如下内容:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
images/new.gif
如果,
TicTacToe>jar uf TicTacToe.jar -C images new.gif
该命令会在添加new.gif文件前先转到目录images,归档结果就不会将images路径包括进去了。结果:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
new.gif
最后,假设想更改TicTacToe.jar的manifest文件(添加一些版本和销售商信息),应该先准备如下文本文档:
versionInfo
————————————————
Name: TicTacToe.class
Implementation-Title: "TicTacToe demo"
Implementation-Version: "build57"
Implementation-Vendor: "Sun Microsystems, Inc."
————————————————
然后,
TicTacToe>jar umf versionInfo TicTacToe.jar
更新就搞定啦。
6.执行以jar归档的软件
三种情况:
1)jar归档了applet,被浏览器浏览
2)jar归档了application,在命令行调用
3)jar包含了将被用以扩展(extension)的代码
(前两种情况将在下面描述,3)参见URL: http://java.sun.com/docs/books/tutorial/ext/index.html)
对于applet,html中如下例:
————————————————
————————————————
如果该class在jar归档内,用参数archive:
————————————————
applet code=TicTacToe.class
archive="TicTacToe.jar"
width=120 height=120>
————————————————
如果该jar和该html不在同一目录下,而在当前目录的子目录applets下,
————————————————
————————————————
对于application,在java版本1的平台上。
可以使用jre工具:
/>jre -cp app.jar MainClass
-cp 开关将app.jar预添加到系统classpath中。
如果是在java版本2的平台上。
/>java -jar jar-file
注意,java版本2之前的java命令不支持-jar开关。
当然,runtime environment必需知道程序的入口点(Mainclass)。前面说过,这是manifest的任务了。在manifest中:
Main-Class: classname
例如:
————————————————
Main-Class: HelloWorld
————————————————