绘图
一、图形环境和图形坐标
1.坐标:
(1)GUI(图形用户界面)组件的左上角坐标默认为(0,0)
(2)从左上角到右下角,水平坐标x和垂直坐标y增加
(3)坐标的单位是像素
2.Graphics对象:
(1)专门管理图形环境。Graphics类是一个抽象类
(2)抽象类Graphics提供了一个与平台无关的绘图接口
(3)各平台上实现的Java系统将创建Graphics类的一个子类,来实现绘图功能,但这个子类对程序员是透明的
(4)在执行paint方法时,系统会传递一个指向特定平台的Graphics子类的图形对象g
二、颜色和字体
1.颜色:Color类,以及Graphics类中与颜色有关的方法:
2.字体:Font类,以及Graphics类中与字体有关的方法:
三、Graphics类
1.抽象类
2.Graphics类常用方法:
一般清空用public void fillRect(intx, int y ,int weight,int height)
四、Graphics2D类
1.Graphics类的子类
2.要使用Java2D API,就必须建立该类的对象。Java2D API能轻松实现更多功能
3.传递给paint方法的对象是Graphics2D的一个子类实例,被向上转型为Graphics类的实例。要访问Graphics2D功能,必须将传递给paint方法的Graphics引用强制转换为Graphics2D引用,例:Graphics2D g2d=(Graphics2D)g
Swings基础
一、JFC与Swing
1.JFC(Java FoundationClasses/Java基础类库)
(1)是关于GUI组件和服务的完整集合
(2)作为JAVA SE的一个有机部分,主要包括五个内容:AWT(Abstract Window Toolkit/抽象窗口工具包)、Java2D、Accessibility、Drag&Drop(拖动&下拉)、Swing
2.Swing
(1)JFC的一部分
(2)提供按钮、窗口、表格等所有的组件
(3)纯Java组件(完全用Java写的)
二、AWT与Swing
1.AWT组件
(1)在Java.awt包中,包括Button、Checkbox、Scrollbar等,都是Component类的子类
(2)大部分含有native code,所以随操作系统平台的不同会显示出不同的样子,而不能进行更改,是重量级组件
2.Swing组件
(1)其名称都是在原来的AWT组件名称前加上J,例如JButton、JCheckBox、JScrollbar等,都是JComponent类的子类
(2)架构在AWT之上,是AWT的扩展而不是取代
(3)完全是由java语言编写的,其外观和功能不依赖于任何由宿主平台的窗口系统所提供的代码,是轻量级组件
(4)可提供更丰富的视觉感受
三、在Applet(Java小程序)和Application中应用Swing
1.Applet和Application介绍
(1)Applet(应用小程序):不是一个完整的程序,只能嵌入HTML语言中在WWW 浏览器环境下运行
(2)Application(应用程序):通常包含main()方法,可在Java虚拟机独立运行的程序
2.应用
(1)Applet中应用Swing,就要将Swing组件加载到Applet容器上(通常是JApplet),这通常在init方法中完成。例如:
运行结果:
(2)Application中应用Swing,也要将Swing组件加载到这个Application的顶层容器(通常是JFrame),例如:
运行结果:
Swing的层次:
一、多数Swing组件的继承层次
javax.swing.JComponent->java.awt.Container->java.awt.Component->java.lang.Object
JComponent类是除了顶层容器以外所有Swing组件的超类
二、各个类功能
1.JComponent类(多数Swing组件的超类)
(1)可根据需求定制观感
(2)快捷键(通过键盘直接访问GUI组件)
(3)一般的事件处理功能
2.Container类
(1)容纳相关组件
(2)包括add方法,用来添加组件
(3)包括setLayout方法,用来设置布局,帮助Container对象对其中的组件进行定位和设置组件大小
3.Component类
(1)包括paint、repaint方法,可以在屏幕上绘制组件
(2)大多数GUI组件直接或间接扩展Component
三、Swing组件和容器层次
1.顶层容器(主框架):包括JFrame类、JDialog类、JApplet类
(1)作用
JFrame:实现单个主窗口
JDialog:实现一个二级窗口(对话框)
JApplet:在浏览器窗口中实现一个applet显示区域
(2)必须和操作系统打交道,所以都是重量级组件
(3)从继承结构上来看,它们分别是从原来AWT组件的Frame、Dialog、Applet类继承而来
(4)每个使用Swing组件的Java程序都必须至少有一个顶层容器,别的组件都必须放在这个顶层容器才能显现出来
2.中间层容器(面板)
(1)分为两类:
一般用途的:JPanel、JScrollPane、JSplitPane、JTabbedPane、JToolBar
特殊用途的:JInternalFrame、JRootPane
(2)可以直接从顶层容器中获得一个JRootPane对象来直接使用,而别的中间容器使用的时候需要新建一个对象
3.原子组件
(1)显示不可编辑信息的,例如:JLabel、JProgressBar、JToolTip
(2)有控制功能、可以用来输入信息的,例如:JButton、JCheckBox、JRadioButton、JComboBox、JList、JMenu、JSlider、JSpinner、JTexComponent
(3)能提供格式化的信息并允许用户选择的,例如:JColorChooser、JFileChooser、JTable、JTree
四、例题:三层容器结构
import javax.swing.*;
import java.awt.*;
public class ComponentTester{
publicstatic void main(String[] args){
JFrame.setDefaultLookAndFeelDecorated(true) //外观修饰,要写在newJFrame()之前
JFrameframe=new JFrame(“Swing Frame”);
Container contentPane=frame.getContentPane();
JPanel panel=new JPanel();
panel.setBorder(Border Factory.createLineBorder(Color.black,5));
panel.setLayout(newGirdLayout(2,1));
JLabellabel=new JLabel(“Lable”,SwingConstants.CENTER);
JButtonbutton=new JButton(“Button”);
panel.add(label);
panel.add(button);
contentPane.add(panel);
frame.pack();
frame.show();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
运行结果:
五、常用Swing组件
一、布局管理器
1.调用容器对象的setLayout方法,并以布局管理器对象为参数,例如:
Container contentPane=frame.getContentPane(); //Container:容器类
contentPane.setLayout(new FlowLayout());
2.使用布局管理器可以更容易地进行布局,而且当改变窗口大小时,它还会自动更新版面来配合窗口的大小,不需要担心版面会因此混乱
二、常用的布局管理器类
1.Java中有很多实现LayoutManager接口的类,经常用到的有以下几种:
BorderLayout、FlowLayout、GridLayout、GardLayout、GridBagLayout、BoxLayout、SpringLayout
2.内容面板(content Pane,*容器包含的一个普通容器)默认使用的就是BorderLayout,它可以将组件放置到五个区域:东、西、南、北、中
3.布局示例:
(4)CardLayout:可以实现在一个区域出现不同的组件布局,就像在一套卡片中选取其中任意一张一样。它经常由一个复选框控制这个区域显示哪一组组件,可通过组合框选择卡片一样选择某一种布局
(5)GridBagLayout:把组件放置在网络中,这一点类似于GridLayout,但它的优点在于不仅能设置组件摆放的位置,还能设置该组件占多少行/列。这是一种非常灵活的布局管理器
(6)BoxLayout:将组件放在单一的行或列中,和FlowLayout不同的是,它可以考虑到组件的对齐方式,最大、最小、优先尺寸
一、内部类
1.在另一个类或方法的定义中定义的类
2.可访问其外部类中的所有数据成员和方法成员
3.可对逻辑上相互联系的类进行分组
4.对于同一个包中的其他类来说,能够隐藏
5.可非常方便地编写事件驱动程序
6.声明方式:
(1)命名的内部类:可在类的内部多次使用
(2)匿名内部类:可在new关键字后声明内部类,并立即创建一个对象
7.假设外层类名为Myclass,则该类的内部类名为:
(1)Myclass$c1.class(c1为命名的内部类名)
(2)Myclass$1.class(表示类中声明的第一个匿名内部类)
二、实例
例1:内部类
public class Parcel1{
class Contents{
privateint i=11;
publicint value(){return I;}
}
class Destination{
privateString label;
Destination(StringwhereTo){ label=whereto;}
StringreadLabel(){ return label;}
}
public void ship(String dest){
Contentsc=new Contents();
Destinationd=new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args)
{
Parcel1p=new Parcel1();
p.ship(“Tanzania”);
}
}
例2:外部类方法返回内部类的引用
public class Parcel2{
class Contents{
privateint i=11;
publicint value() {return I;}
}
class Destination{
privateString label;
Destination(StringwhereTo) {label=whereto;}
StringreadLabel(){ return new Contents();}
}
public Destination to(String s) //to()方法返回内部类Destination引用
{
returnnew Destination(s);
}
public Contents cont() //cont()方法返回内部类Contents的引用
{
returnnew Content();
}
public void ship(String dest){
Contentsc=cont();
Destinationd=to(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args) {
Parcel2p=new Parcel2();
p.ship(“Tanzania”);
Parcel2q=new Parcel2();
Parcel2.Contents c=q.cont();
Parcel2.Destination d=q.to(“Borneo”);
}
}
三、内部类实现接口、继承抽象类
1.可以完全不被看到,而且不能被调用
2.可以方便实现“隐藏实现细节”,外部能得到的仅仅是指向超类或者接口的一个引用
3.实例:
abstract class Contents{
abstractpublic int value();
}
interface Destination{
StringreadLabel();
}
public class Parcel3{
privateclass PContents extends Contents {
privateint i=11;
publicint value() {return I;}
}
protectedclass PDestination implements Destination {
privateString label;
privatePDestination(String whereTo) {label=whereTo;}
publicString readLabel() {return label;}
}
public Destination dest(String s) {return new PDestination(s);}
public Contents cont() {return newPContents();}
}
class Test {
publicstatic void main(String[] args){
Parcel3p=new Parcel3();
Contentsc=p.cont();
Destinationd=p.dest(“Tanzania”);
}
}
四、局部作用域中的内部类
1.实现某个接口,产生并返回一个引用
2.为解决一个复杂问题,需要建立一个类,而又不想它为外界所用
3.实例
例1:方法中的内部类
interface Destination{
StringreadLabel();
}
public class Parcel4{
publicDestination dest(String s) {
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label=whereTo;
}
public String readLabel() {return label;}
}
returnnew PDestination(s);
}
public static void main(String[] args)
{
Parcel4p=new Parcel4();
Destinationd=p.dest(“Tanzania”);
}
例2:块作用域中的内部类
public class Parcel5 {
private void internalTracking(boolean b)
{
if(b)
{
class TrackingClip
{
private String id;
TrackingSlip(String s) {id=s;}
String getSlip() {return id;}
}
TrackingSlip ts=new TrackingSlip(“Slip”);
String s=ts.getSlip();
}
}
public void track() {internalTracking(true);}
public static void main(String[] args)
{
Parcel5p=new Parcel5();
p.track();
}
}
例3:匿名的内部类
abstract class Contents{
abstractpublic int value();
}
public class Parcel6
{
publicContents cont()
{
returnnew Contents() //以Contents为超类派生出匿名的子类
{
private int i=11;
public int value() {return i;}
};
}
publicstatic void main(String[] args)
{
Parcel6p=new Parcel6();
Contentsc=p.cont();
}
}
事件处理的基本概念
一、常见的事件
移动鼠标、单双击鼠标各个按钮、单击按钮、在文本字段输入、在菜单中选择菜单项、在组合框中选择、拖动滚动条、关闭窗口、……
Swing通过事件对象来包装事件,程序可以通过事件对象获得事件的有关信息
二、事件处理的几个要素
1.事件源:与用户进行交互的GUI组件,表示事件来自于哪个组件或对象,比如要对按钮被按下这个事件编写处理程序,按钮就是事件源
2.事件监听器:负责监听事件并做出相应。一旦它监视到事件发生,就会自动调用相应的事件处理程序作出响应
3.事件对象:封装了有关已发生的事件的信息。例如按钮被按下就是一个要被处理的事件,当用户按下按钮时,就会产生一个事件对象。事件对象中包含事件的相关信息和事件源
三、程序要应完成的两项任务
1.为事件源注册一个事件监听器
2.实现事件处理方法
四、事件源
1.提供注册事件监听器或取消监听器的方法
2.如有事件发生,已注册的监听器就会被通知
3.一个事件源可以注册多个事件监听器,每个监听器又可以对多种事件进行相应,例如一个JFrame事件源上可以注册:
(1)窗口事件监听器,响应:窗口关闭、窗口最大化、窗口最小化
(2)鼠标事件监听器,响应:鼠标点击、鼠标移动
五、事件监听器
1.是一个对象,通过事件源的add×××Listener方法被注册到某个事件源上
2.不同的Swing组件可以注册不同的事件监听器
3.一个事件监听器中可以包含有对多种具体事件的专用处理方法,例如:
用于处理鼠标的事件监听器接口MouseListener中就包含有对应于鼠标压下、放开、进入、离开、敲击五种事件的相应方法mousePressed、mouseReleased、mouseEntered、mouseExited、mouseClicked,这五种方法都需要一个事件对象作为参数
六、事件对象
常用的事件对象:
(1)ActionEvent:发生在按下按钮、选择了一个项目、在文本框中按下回车键
(2)ItemEvent:发生在具有多个选项的组件上,如JCheckBox、JComboBox
(3)ChangeEvent:用在可设定数值的托业杆上,例如JSlider、JProgressBar
(4)WindowEvent:用在处理窗口的操作
(5)MouseEvent:用于鼠标操作
八、接口与适配器
1.事件监听器接口:例如MouseListener是一个接口,为了在程序中创建一个鼠标事件监听器的对象,我们需要实现其所有五个方法,在方法体中,我们可以通过鼠标事件对象传递过来的信息(例如点击的次数、坐标),实现各种处理功能
2.事件监听器适配器类:有时我们并不需要对所有事件进行处理,为此Swing提供了一些适配器类×××Adapter,这些类含有所有×××Listener中方法的默认实现(就是什么都不做),因此我们就只需编写那些需要进行处理的事件的方法。例如,如果只想对鼠标敲击事件进行处理,如果使用MouseAdapter类,则只需要重写mouseClicked方法就可以了
九、事件处理
1.实现事件监听器接口:这种方法需要实现接口中所有的方法,对我们不需要进行处理的事件方法,也要列出来,其方法体使用一对空的花括号
2.继承事件监听器适配器类:只需要重写我们感兴趣的事件
3.使用匿名内部类:特别适用于已经继承了某个父类(例如Applet程序,主类必须继承JApplet类或Applet类),则根据java语法规则,就不能再继承适配器类的情况,而且使用这种方法程序看起来会比较清楚明了
4.lambda表达式:对于只有一个抽象方法的函数式监听器接口,也可以使用lambda表达式
事件派发的机制
一、事件派发机制------事件派发线程
1.Swing中的组件是非线程安全的,在Swing中专门提供了一个事件派发线程(EDT)用于对组件的安全访问
(1)用来执行组件事件处理程序的线程(如按钮的点击事件),依次从系统事件队列取出事件并处理,一定要执行完上一个事件的处理程序后,才会处理下一个事件
(2)事件监听器的方法都是在事件派发线程中执行的,如ActionListener的actionPerformed方法
二、事件派发机制------由事件派发线程启动GUI
1.可以调用invokeLater或invokeAndWait请事件分发线程以运行某段代码
(1)要将这段代码放入一个Runnable对象的run方法中,并将该Runnable对象作为参数传递给invokeLater
(2)invokeLater是异步的,不用等代码执行完就返回。javax.swing.SwingUtilities中
(3)invokeAndWait是同步的,要等代码执行完才返回。调用时要避免死锁
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Demoimplements ItemListener
{
JPanel cards; //中间容器,面板容器类
finalstatic String BUTTONPANEL="JPanel With JButton";
finalstatic String TEXTPANEL="JPanel With JTextield";
publicvoid addComponentToPane(Container pane)
{
JPanel comboBoxPane=new JPanel(); //中间容器,默认使用FlowLayout
StringcomboBoxItems[] ={BUTTONPANEL,TEXTPANEL};
JComboBoxcb=new JComboBox(comboBoxItems); //原子组件
cb.setEditable(false); //设置成不可编辑的
cb.addItemListener(this); //添加事件监听器
comboBoxPane.add(cb); //将原子组件添加到中间容器上
JPanel card1=new JPanel();
card1.add(newJButton("Button 1"));
card1.add(newJButton("Button 2"));
card1.add(newJButton("Button 3"));
JPanel card2=new JPanel();
card2.add(newJTextField("TextField",20));
cards=new JPanel(new CardLayout());
cards.add(card1,BUTTONPANEL);
cards.add(card2,TEXTPANEL);
pane.add(comboBoxPane,BorderLayout.PAGE_START); //对应位置
pane.add(cards,BorderLayout.CENTER); //对应位置
}
public void itemStateChanged(ItemEvent evt)
{
CardLayout cl=(CardLayout)(cards.getLayout());
cl.show(cards,(String)evt.getItem());
}
private static void createAndShowGUI()
{
JFrameframe=new JFrame("CardLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口关闭按钮的含义
Demodemo=new Demo();
demo.addComponentToPane(frame.getContentPane());
frame.pack(); //根据窗口里面的布局及组件preferedSize来确定frame的最佳大小
frame.setVisible(true); //把图形界面设置为可见
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(newRunnable()
{
publicvoid run()
{
createAndShowGUI();
}
});
}
}
顶层容器类
一、Swing的三个顶层容器类
1.JFrame、JApplet、JDialog
2.都是重量级组件,分别继承了AWT组件Frame、Applet和Dialog
3.每个顶层容器都有一个内容面板,通常直接或间接的容纳别的可视组件
4.可以有选择地为顶层容器添加菜单,菜单被放置在顶层容器上,但是在内容面板外
二、三大顶层容器类继承结构
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FrameDemo
{
publicstatic void main(String []args)
{
JFrameframe=new JFrame(“FrameDemo”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭按钮功能
JLabelemptyLabel=new JLable(“”); //原子组件JLabel显示文本
emptyLabel.setPreferredSize(new Dimension(175,100)); //Dimension类用于初始化长和宽
frame.getContentPane().add(emptyLabel,BorderLayout.CENTER);
frame.pack(); //大小调整成合适的
frame.setVisible(true); //设置为可见
}
}
例2:TopLevelDemo.java
import java.awt.event.*;
import javax.swing.*;
public class TopLevelDemo
{
publicstatic void main(String agrs[])
{
JFrameframe=new JFrame(“TopLevelDemo”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabelyellowLabel =new JLabel(“”);
yellowLabel.setOpaque(true);
yellowLabel.setBackground(Color.yellow);
yellowLabel.setPreferredSize(new Dimension(200,180));
JMenuBarcyanMenuBar=new JMenuBar();
cyanMenuBar.setOpaque(true); //设置组件是否透明,true不透明,false透明
cyanMenuBar.setBackground(Color.cyan);
cyanMenuBar.setPreferredSize(new Dimension(200,20));
frame.setJMenuBar(cyanMenuBar);
frame.getContentPane().add(yellowLabel,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
例3:JOptionPaneDemo.java
通过静态方法show×××Dialog,可以产生四种简单的对话框
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JOptionPaneDemo extends JFrameimplements ActionListener
{
publicJOptionPaneDemo()
{
super(“简单对话框”);
Containerc=getContentPane();
JButtonbutton=new JButton(“退出”);
button.addActionListener(this);
c.setLayout(newFlowLayout());
c.add(button);
}
publicvoid actionPerformed(ActionEvent e)//弹出对话框,并用变量select记录用户做的选择
{
intselect=JOptionPane.showConfirmDialog(this,”确定要退出吗?”,“确定”,JOptionPane.OK_CANCEL_OPTION,JOptionPane.WARNING_MESSAGE);
if(select==JOptionPane.OK_OPTION)
System.exit(0);
}
publicstatic void main(String args[])
{
JFrameframe=new JOptionPaneDemo();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200,100);
frame.setVisible(true);
}
中间容器
一、分类
1.一般用途的:JPanel、JScrollPane(带滚动条)、JSplitPane(把窗口一分为二)、JTabbedPane(像一套卡片)、JToolBar(工具栏)
2.特殊用途的:JInternalFrame(在一个主窗口中打开多个子窗口)、JRootPane(可以直接从顶层容器中获得)
JRootPane的层次结构:
1.glassPane:默认状态下是隐藏的,可以使用glassPane来截获所有要到达JRootPane别的部分的事件
二、JPanel
1.默认状态下,除了背景色外不绘制任何东西
2.可以很容易的为它设置边框和绘制特性,有效地利用JPanel可以使版面管理更为容易
3.可以使用布局管理器来规划它所容纳的组件的位置和大小
(1)可以通过setLayout方法来改变其布局
(2)也可以在创建一个JPanel对象时就为它确定某种布局方式。在默认状态下panel使用FlowLayout布局,将各组件布局在一行
三、JScrollPane
1.容器有滚动条,通过拖动滑块,就可以看到更多内容
4.实例:ScrollDemo2.java,鼠标左键画圆,右键刷新画板,画到边界自动延伸
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class ScrollDemo2extends JPanel //JPanel子类
{
privateDimension size;
privateVector objects;
private final Color colors[]={Color.red,Color.blue,Color.green,Color.orange,Color.cyan,Color.magenta,Color.yellow};
privatefinal int color_n=colors.length;
JPaneldrawingArea;
publicScrollDemo2()
{
setOpaque(true); //透明度,true表示不透明
size=newDimension(0,0);
objects=newVector();
JLabelinstructionsLeft=new JLabel("Click left mouse button to place acircle");
JLabelinstructionsRight=new JLabel("Click right mouse button to clear drawing area");
JPanel instructionPanel=new JPanel(new GridLayout(0,1)); //GridLayout(行数,列数)
instructionPanel.add(instructionsLeft);
instructionPanel.add(instructionsRight);
drawingArea=newJPanel()
{
protected void paintComponent(Graphics g) //由于多种原因,极少数情况覆盖paint方法,一般选择覆盖paintComponent方法
{
super.paintComponent(g);
Rectanglerect;
for(inti=0; i<objects.size();i++)
{
rect=(Rectangle)objects.elementAt(i); //elementAt(i),返回Vector中第i+1个元素
g.setColor(colors[(i%color_n)]);
g.fillOval(rect.x,rect.y,rect.width,rect.height);
}
}
};
drawingArea.setBackground(Color.white);
drawingArea.addMouseListener(newMyMouseListener());
JScrollPanescroller=new JScrollPane(drawingArea);
scroller.setPreferredSize(new Dimension(200,200)); //设置最佳大小
setLayout(newBorderLayout());
add(instructionPanel,BorderLayout.NORTH);
add(scroller,BorderLayout.CENTER);
}
classMyMouseListener extends MouseInputAdapter //继承监听器适配器类
{
finalint W=100;
finalint H=100;
publicvoid mouseReleased(MouseEvent e)
{
booleanchanged=false;
if(SwingUtilities.isRightMouseButton(e)) //点击右键
{
objects.removeAllElements();
size.width=0;
size.height=0;
changed=true;
}
else //点击鼠标左键,画圆
{
intx=e.getX()-W/2;
inty=e.getY()-H/2;
if(x<0)
x=0;
if(y<0)
y=0;
Rectanglerect=new Rectangle(x,y,W,H);
objects.addElement(rect);
drawingArea.scrollRectToVisible(rect);
intthis_width=(x+W+2);
if(this_width>size.width)
{
size.width=this_width;
changed=true;
}
intthis_height=(y+H+2);
if(this_height>size.height)
{
size.height=this_height;
changed=true;
}
}
if(changed)
{
drawingArea.setPreferredSize(size);
drawingArea.revalidate(); //revalidate是把布局管理器对应的容器的子组件重新布局并绘制,使得当组件越过默认最佳边界时会产生滚动条
}
drawingArea.repaint(); //刷新显示之前调用paintComponent绘制的图
}
}
publicstatic void main(String args[])
{
JFrameframe=new JFrame("ScrollDemo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new ScrollDemo2());
frame.pack();
frame.setVisible(true);
}
}
PS:
四、JSplitPane
1.可以把两个组件显示在两个显示区域内,且随着区域间分割线的拖动,区域内组件的大小也随之发生变动
2.它允许设置水平分割或者垂直分割;也允许设置动态拖曳功能(拖动分界线时两边组件是否会随着拖曳动态改变大小还是在拖曳结束后才改动)
3.我们通常先把租组件放到ScrollPane中,再把Scroll Pane放到Split Pane中。这样在每部分窗口中,都可以拖动滚动条看到组件的全部内容
4.JSplitPane常用API:
5.实例: JSplitPaneDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
public class JSplitPaneDemo implements ListSelectionListener //实现监听器接口
{
privateVector imageNames;
privateJLabel picture;
privateJList list;
privateJSplitPane splitPane;
publicJSplitPaneDemo()
{
ResourceBundle imageResource;
try
{
imageResource=ResourceBundle.getBundle("imagenames"); //ResourceBundle.getBundle从文件imagenames中取出写好的内容
StringimageNamesString=imageResource.getString("images");
imageNames=parseList(imageNamesString);
}
catch(MissingResourceExceptione)
{
System.err.println();
System.err.println("Can'tfind the properties file"+" that contains the image names.");
System.err.println("Itsname should be imagenames properties,"+"and it should");
System.err.println("containa single line that specifies"+" one or more image");
System.err.println("filesto be found in a directory"+"named images.Example:");
System.err.println("images=Bird.gifCat.gif Dog.gif");
System.err.println();
System.exit(1);
}
list=newJList(imageNames); //用动态String数组Vector初始化JList
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //设置选择模式,一次只能选一项。 MULTIPLE_INTERVAL_SELECTION可以选择不相邻的几项,SINGLE_INTERVAL_SELECTION只能选择连续的几项
list.setSelectedIndex(0); //默认第一个选项被选中
list.addListSelectionListener(this);
JScrollPanelistScrollPane=new JScrollPane(list); //给选择列表加滚动条
// ImageIcon firstImage= newImageIcon("D://软件工程//IDE//eclipse//code//JSplitPaneDemo//src//"+(String)imageNames.firstElement()); //默认展示第一张图
picture=newJLabel(); //picture=new JLabel(firstImage);
// picture.setPreferredSize(newDimension(firstImage.getIconWidth(),firstImage.getIconHeight()));
JScrollPanepictureScrollPane=new JScrollPane(picture);
splitPane=newJSplitPane(JSplitPane.HORIZONTAL_SPLIT,listScrollPane,pictureScrollPane); //HORIZONTAL_SPLIT将两个面板左右分离,VERTICAL_SPLIT将两个面板上下分离
splitPane.setOneTouchExpandable(true); //选择是否加上完全隐藏一侧功能的小三角
splitPane.setDividerLocation(150); //设置分隔条位置
DimensionminimumSize=new Dimension(100,50);
listScrollPane.setMinimumSize(minimumSize); //设置选项面板的最小大小
pictureScrollPane.setMinimumSize(minimumSize);
splitPane.setPreferredSize(newDimension(400,200)); //设置整个界面最佳大小
}
publicJList getImageList()
{
returnlist;
}
publicJSplitPane getSplitPane()
{
returnsplitPane;
}
publicvoid valueChanged(ListSelectionEvent e) //改变选项
{
if(e.getValueIsAdjusting()) //按下鼠标并拖动过程中,getValueIsAdjusting()始终为true,松开鼠标后为false
return;
JList theList=(JList)e.getSource(); //得到选项列表JList
if(theList.isSelectionEmpty()) //是否选择的选项为空
{
picture.setIcon(null);
}
else
{
int index=theList.getSelectedIndex(); //得到选择的选项下标
ImageIconnewImage=new ImageIcon("D://软件工程//IDE//eclipse//code//JSplitPaneDemo//src//"+(String)imageNames.elementAt(index));//路径的冒号一定要用英文!!!
picture.setIcon(newImage);
picture.setPreferredSize(newDimension(newImage.getIconWidth(),newImage.getIconHeight()));
picture.revalidate(); //当组件越过默认最佳边界时会产生滚动条
}
}
protectedstatic Vector parseList(String theStringList)
{
Vectorv=new Vector(10); //初始化Vector含有10个元素
StringTokenizer tokenizer=newStringTokenizer(theStringList," "); //StringTokenizer是用来分割String的类,此处以“ ”为依据分隔
while(tokenizer.hasMoreTokens()) //hasMoreTokens()返回是否还有分隔符
{
String image=tokenizer.nextToken(); //返回从当前位置到下一个分隔符之间的字符串
v.addElement(image);
}
returnv;
}
publicstatic void main(String []args)
{
JFrameframe=new JFrame("SplitPaneDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JSplitPaneDemosplitPaneDemo=new JSplitPaneDemo();
frame.getContentPane().add(splitPaneDemo.getSplitPane());
frame.pack();
frame.setVisible(true);
}
}
PS:StringTokenizer类的使用:
五、JTabbedPane
1.如果一个窗口的功能有几项,可以给每项设置一个标签,每个标签下面包含为完成此功能专用的若干组件
2.JTabbedPane常用API:
六、JToolBar
1.将一些常用的功能以工具栏的方式呈现
import javax.swing.JToolBar;
import javax.swing.JButton;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class JToolBarDemo extends JFrame
{
protectedJTextArea textArea;
protectedString newline="\n";
public JToolBarDemo()
{
super("ToolBarDemo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JToolBar toolBar=new JToolBar();
addButtons(toolBar);
textArea=newJTextArea(5,30);
JScrollPane scrollPane=new JScrollPane(textArea); //创建滚动面板,并加入文本框
JPanelcontentPane=new JPanel();
contentPane.setLayout(newBorderLayout());
contentPane.setPreferredSize(newDimension(400,300));
contentPane.add(toolBar,BorderLayout.NORTH); //将工具栏置于上方
contentPane.add(scrollPane,BorderLayout.CENTER); //将滚动面板置于*
setContentPane(contentPane); //将contentPane作为内容面板
}
protectedvoid addButtons(JToolBar toolBar)
{
JButtonbutton=null;
button=newJButton(new ImageIcon("D://软件工程//IDE//eclipse//code//JToolBar//src//1.jpg")); //使用本地图片
button.setToolTipText("Thisis the left button"); //设置提示语句
button.addActionListener(new ActionListener() { //匿名内部类实现事件处理
public void actionPerformed(ActionEvent e)
{
displayResult("播放");
}
});
toolBar.add(button); //在工具栏上加按钮
button=newJButton(new ImageIcon("D://软件工程//IDE//eclipse//code//JToolBar//src//2.jpg"));
button.setToolTipText("Thisis the middle button");
button.addActionListener(newActionListener(){
publicvoid actionPerformed(ActionEvent e)
{
displayResult("暂停");
}
});
toolBar.add(button);
button=newJButton(new ImageIcon("D://软件工程//IDE//eclipse//code//JToolBar//src//3.jpg"));
button.setToolTipText("Thisis the right button");
button.addActionListener(newActionListener(){
publicvoid actionPerformed(ActionEvent e)
{
displayResult("结束");
}
});
toolBar.add(button);
}
protectedvoid displayResult(String actionDescription)
{
textArea.append(actionDescription+newline); //setText()是设置TextArea的内容,而append()是在TextArea里添加新内容,前者TextArea内容会被覆盖,后者则不会
}
publicstatic void main(String[] args)
{
JToolBarDemoframe=new JToolBarDemo();
frame.pack();
frame.setVisible(true);
}
}
七、JIternalFrame
1.在一个主窗口中打开多个文档,每个文档各自占用一个新的窗口
2.JInternalFrame的使用跟JFrame几乎一样,可以最大化、最小化、关闭窗口、加入菜单
3.JInternalFrame是轻量级组件,因此它只能是中间容器,必须依附于顶层容器上
4.通常将internal frame加入JDesktopPane类的对象来方便管理,JDesktopPane继承自JLayeredPane,用来建立虚拟桌面。它可以显示并管理众多internal frame之间的层次关系
5.JInternalFrame常用API:
一、分类
1.显示不可编辑信息:JLabel、JProgressBar、JToolTip
2.有控制功能、可以用来输入信息:JButton、JCheckBox、JRadioButton、JComboBox、JList、JMenu、JSlider、JSpinner、JTextComponent
3.能提供格式化的信息并允许用户选择:JColoChooser、JFileChooser、JTable、JTree
二、显示不可编辑信息的原子组件
1.JLabel
该组件上可以显示文字和图像,并能指定两者的位置
2.JProgressBar
在一些软件运行时,会出现一个进度条告知目前进度如何。通过使用该组件我们可以轻松为软件加上一个进度条
3.JToolTip
(1)使用setToolTipText()方法为组件设置提示信息
(2)有的组件例如JTabbedPane由多个部分组成,需要鼠标在不同部分停留时显示不同的提示信息,这时可以在其addTab()方法中设置提示信息参数,也可以通过setTooltipTextAt方法进行设置
三、有控制功能、可以用来输入信息的原子组件
1.按钮类:
(1)AbstractButton抽象类是众多按钮类的超类,继承图为
(2)JToggleButton表示有两个选择状态的按钮,JCheckBox是多选按钮,JRadioButton为单选按钮
(3)JMunuItem表示在菜单中使用,JCheckBoxMenuItem是多选按钮,JRadioButtonMenuItem是单选按钮,JMenu是一般的菜单项
2.列表框JList
(1)有几种各有特色的构造方法(选项是否可添加、删除)
(2)提供了很多API可以用来设置各选项的显示模式(在一列还是若干列)、选择模式(一次可选几项及是否可连续)
(3)因为JList通常含有很多选项,所以经常把它放在一个JScrollPane对象里
(4)JList的事件处理一般可分为两类:
a.取得用户选取的项目,事件监听器是ListSelectionListener
b.对鼠标事件做出相应,其事件监听器是MouseListener
3.组合框JComboBox
(1) 在许多选项中选其一,可以有两种非常不一样的格式:
a.默认状态是不可编辑的模式,其特色是包括一个按钮和一个下拉列表,用户只能在下拉列表提供的内容中选其一
b.另一种是可编辑的模式,其特色是多了一个文本区域,用户可以在此文本区域内填入列表中不包括的内容‘
(2)组合框只需要很少的屏幕区域,而一组JRadioBox、JCheckBox、JList占据的空间比较大
4.连续数值选择类
(1)占空间大
(2)可以设置它的最小、最大、初始刻度,还可以设置它的方向,还可以为其标上刻度或文本
(3)在JSlider上移动滑动杆,会产生ChangeEvent事件
2.JSpinner
(1)占空间小
(2)类似于可编辑的JComboBox,是一种复合组件,由三个部分组成:向上按钮、向下按钮和一个文本编辑区
(3)可以通过按钮选择待选项,也可以直接在文本编辑区输入
(4)和JComboBox不同的是,它的待选项不会显示出来
5.文本类
(1)继承自JTextComponent抽象类,继承图为:
a.JTextField、JPassWordField、JFormattedTextField:只能显示和编辑一行文本。像按钮一样,它们可以产生ActionEvent事件,通常用来接受少量用户输入信息并在输入结束进行一些事件处理
b.JTextArea:可以显示和编辑多行文本,但是这些文本只能是单一风格的,通常用来让用户输入任意长度的无格式文本或显示无格式的帮助信息
c.JEditorPane、JTextPane:可以显示和编辑多行多种风格的文本,嵌入图形或别的组件
四、能提供格式化的信息并允许用户选择的原子组件
1.JColorChooser颜色选择对话框
(1)通常使用这个类的静态方法showDialog()来输出标准的颜色选择对话框,其返回值就是选择的颜色
(2)也可以通过静态方法createDialog()方法输出个性化的颜色对话框,例如为其添加菜单、定义其时间处理程序,这个方法的返回值就是一个对话框
2.JFileChooser文件选择对话框
(1)可以使用JFileChooser的showDialog、showOpenDialog或showSaveDialog()方法来打开文件对话框,但是它仅仅会返回用户选择的按钮(确认还是取消)和文件名(如果确认的话),接下来的要实现的例如存盘或者打开的功能还需要程序员自己编写
(2)这个类提供了专门的方法用于设置可选择的文件类型,还可以指定每类文件使用的类型图标
3.JTable表格
(1)可为表格设计显示外观(是否有滚动条、调整某一列宽)、显示模式(根据数据类型的不同有不同的排列显示方式、为某一字段添加组合框JComboBox)、选择模式(单选、多选、连续选、任意选)
(2)JTable的事件都是针对表格内容的操作处理,我们称为TableModelEvent事件。通过addTableModelListener方法为表格添加此中事件监听器
(3)和其相关的还有一些接口和类,包括TableModel、AbstractTableModel、DefaultTableModel、SelectionModel、TableColumnModel
4.JTree
(1)构造方法有多种,参数可以是一个Hashtable,也可以是TreeNode或TreeModel对象
(2)可以使用JComponent提供的putClientProperty方法来设置JTree外观,也可以使用TreeCellRenderer来个性化各类节点的显示样式
五、实例:简单计算器
在第一个窗口输入用户和密码,要求输入密码使用JPasswordField组件,密码正确后,才能进入第二个窗口进行“+、-、*、/”计算。运算符号使用单选按钮JRadioButton,操作数使用JcomboBox和Jspinner
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
public class CalculatorDemo implements ItemListener,ActionListener
{
staticJFrame f=null; //因为要在main静态方法中被引用,所以必须设为static
ButtonGroup bg; //按钮组,可组合若干单选按钮,来保证选项为单选
JComboBox combo; //下拉式列表框
JSpinner s1; //有序变化选择框
JLabelL3; //显示计算结果
JRadioButtonr1,r2,r3,r4; //单选按钮
intop=0;
publicCalculatorDemo()
{
f=newJFrame("第二类原子组件演示");
ContainercontentPane=f.getContentPane();
JPanelp1=new JPanel();
p1.setLayout(newGridLayout(1,4)); //1行4列
p1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.blue,2),"选择运算种类",TitledBorder.CENTER,TitledBorder.TOP));
r1=newJRadioButton("+");
r2=newJRadioButton("-");
r3=newJRadioButton("×");
r4=newJRadioButton("÷");
p1.add(r1);
p1.add(r2);
p1.add(r3);
p1.add(r4);
bg=newButtonGroup();
bg.add(r1);
bg.add(r2);
bg.add(r3);
bg.add(r4);
r1.addItemListener(this);
r2.addItemListener(this);
r3.addItemListener(this);
r4.addItemListener(this);
JPanelp2=new JPanel();
p2.setLayout(newGridLayout(2,2));
p2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.blue,2),"选择或输入操作数",TitledBorder.CENTER,TitledBorder.TOP));
JLabelL1=new JLabel("第一个操作数:");
JLabelL2=new JLabel("第二个操作数:");
String[]data1={"0","10","20","30","40","50","60","70","80","90","100"};
combo=newJComboBox(data1);
combo.setEditable(true); //设置为可编辑的
ComboBoxEditoreditor=combo.getEditor(); //得到编辑器
combo.configureEditor(editor,"请选择或直接输入数字"); //可以输入数字
SpinnerModel sM1=new SpinnerNumberModel(50,0,100,1); //初始50,最小0,最大100,每次变化1
s1=newJSpinner(sM1);
p2.add(L1);
p2.add(combo);
p2.add(L2);
p2.add(s1);
JPanelp3=new JPanel();
p3.setLayout(newGridLayout(1,2));
JButtonbutton1=new JButton("计算");
L3=new JLabel("",SwingConstants.CENTER); //JLabel是实现SwingConstants接口的,SwingConstants.CENTER和JLabel.CENTER没有区别,表示JLabel的中心
p3.add(button1);
p3.add(L3);
button1.addActionListener(this);
contentPane.add(p1,BorderLayout.NORTH);
contentPane.add(p2,BorderLayout.CENTER);
contentPane.add(p3,BorderLayout.SOUTH);
f.setBounds(200, 150, 400, 200); //setBounds作用在顶层容器才有用,前两个参数对应左上角在屏幕上的坐标,后两个参数对应长宽
f.getRootPane().setDefaultButton(button1); //getRootPane方法返回的RootPane对象中的setDefaultButton方法可以设置默认按钮,点击回车触发
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
publicvoid itemStateChanged(ItemEvent e) //选项改变
{
if(e.getSource()==r1) //getSource(),得到使得事件发生的组件
op=1;
if(e.getSource()==r2)
op=2;
if(e.getSource()==r3)
op=3;
if(e.getSource()==r4)
op=4;
}
publicvoid actionPerformed(ActionEvent e)
{
doublea=Double.parseDouble(combo.getSelectedItem().toString()); //getSelectedItem()返回的是一个对象(object),得到字符串还要用toString()
doubleb=Double.parseDouble(s1.getValue().toString());
doublec;
switch(op)
{
case1:
c=a+b;
L3.setText(""+c); //setText呈现字符串内容
break;
case2:
c=a-b;
L3.setText(""+c);
break;
case3:
c=a*b;
L3.setText(""+c);
break;
case4:
c=a/b;
L3.setText(""+c);
break;
default:
L3.setText("请选择运算符");
}
}
publicstatic void main(String []args)
{
newCalculatorDemo();
newPassWord(f);
}
}
class PassWord implements ActionListener
{
JTextField user;
JPasswordField passWd;
JButtonb1,b2;
ContainerdialogPane;
JDialogd;
JFramef;
publicPassWord(JFrame f)
{
d=newJDialog();
d.setTitle("请输入用户名和密码");
dialogPane=d.getContentPane();
dialogPane.setLayout(newGridLayout(3,2));
dialogPane.add(newJLabel("用户名",SwingConstants.CENTER));
user=newJTextField();
dialogPane.add(user);
dialogPane.add(newJLabel("密码",SwingConstants.CENTER));
passWd=new JPasswordField();
dialogPane.add(passWd);
b1=newJButton("确定");
b2=newJButton("退出");
dialogPane.add(b1);
dialogPane.add(b2);
b1.addActionListener(this);
b2.addActionListener(this);
d.setBounds(200,150,400,130); //前两行对应JDialog在屏幕上的坐标
d.getRootPane().setDefaultButton(b1);
d.setVisible(true);
this.f=f;
}
publicvoid actionPerformed(ActionEvent e)
{
Stringcmd=e.getActionCommand(); //JButtonjb=new JButton("a"); e.getSource()得到的是jb,一个object对象。而e.getActionCommand()得到的是“a”,一个字符串
if(cmd.equals("确定"))
{
Stringname=user.getText();
StringpassWord=passWd.getText();
if((name.equals("test"))&&(passWord.equals("1234")))
{
d.dispose(); //用dispose()关闭窗口可以释放该窗口所有资源,这些 Component 的资源将被破坏,它们使用的所有内存都将返回到操作系统,并将它们标记为不可显示。使用dispose()方法关闭的窗体可以使用pack 或 show 方法恢复,并且可以恢复到dispose前的状态
f.setVisible(true);
return;
}
else
{
JOptionPane.showMessageDialog(d,"错误的用户名或密码","请重新输入",JOptionPane.WARNING_MESSAGE); //第一个参数为弹出位置,填组件则在组件中心弹出,不填则在屏幕中心弹出
user.setText("");
}
}
if(cmd.equals("退出"))
System.exit(0);
}
}
其它Swing特性
一、Action对象
1.Action的用途:
(1)Action接口是对ActionListener接口的一个有用的扩展,它的继承关系如下
public interface Action extendsActionListener
(2)在很多既有菜单又有工具栏的应用程序中,可以通过Action对象封装事件响应代码和相关设置,并添加到不同的事件源
(3)可以通过它对不同组件的显示文字、图标、快捷键、提示文字、是否可用等属性进行统一的设置
2.创建Action对象
(1)AbstractAction类实现了Action接口中除了actionPerformed方法以外的其他方法。而且还提供了一些获取和设置Action域属性的方法
(2)首先需要创建一个继承抽象类AbstractAction类的子类,然后再实例化这个子类:设置需要的属性值、定义actionPerformed方法
3.使用Action对象
(1)通过GUI组件的setAction方法将Action对象关联组件
a.每个具有addActionListener方法的组件也具有setAction方法
b.Action是一个事件监听器,如果需要添加多个监听器,应使用addActionListener方法。一个GUI组件可以调用setAction不止一次,但组件和前一个Action对象之间的关联会被删除
(2)通过setAction方法把Action对象关联到某GUI组件后,会有以下效果:
a.此组件的属性会被设置为符合这个Action对象的属性
b.这个Action对象会被注册为此组件的一个事件监听器对象
c.如果改变了Action对象的属性和方法,则和它关联的组件的属性或方法也会自动变更以符合这个改变了的Action对象
1.使用组件的setBorder方法为组件添加边框,需要提供一个Border类型的对象
(1)可以使用BorderFactory类提供的很多静态方法产生一个常用的Border对象
(2)如果不能够满足要求,可以直接使用javax.swing.border包里的API来定义自己的边框
2.有关边框的常用API
三、设置观感
1.设置组件的观感:在产生任何可视组件以前需要使用UIManager类提供的setLookAndFeel()静态方法设置好它们的观感
(1)java提供的跨平台的观感。可以利用UIManager类提供的getCrossPlatformLookAndFeelClassName()静态方法获得类名
(2)程序所处系统的观感。可以利用UIManager类提供的getSystemLookAndFeel静态方法获得目前操作平台的Look and Feel类名称
2.设置顶层容器的观感:顶层容器JFrame和JDialog是重量级组件,依赖于操作系统,当使用的操作系统不同时,所显示的顶层容器就会有所不同。针对这两个顶层容器,有一个静态方法专门为其设置观感:
static voidsetDefaultLookAndFeelDecorated(boolean )
参数为true,就会选择默认的外观感觉
参数为false,就会选用操作平台的外观感觉
四、桌面API
1.从Java6开始,对于特定的文件类型,Java程序可以和关联该文件类型的主机应用程序进行交互,这种交互通过java.awt.DeskTop类进行的,因此java.awt.DeskTopAPI叫做桌面API。通俗的话讲就是桌面API可以调用本地的应用程序处理相关的文件
2.桌面API允许Java应用程序完成以下三件事:
(1)启用主机平台默认的浏览器打开URL,这个功能由DeskTop的browse方法完成
(2)启用主机平台上默认的邮件客户端,这个功能由DeskTop的mail方法完成
(3)对特定的文件,启用主机平台上与之关联的应用程序,对该文件进行打开、编辑、打印操作,这些功能分别由DeskTop的open、edit、print方法完成