AWT
AWT(Abstract Window Toolkit)包括了很多类和接口,用于Java Application
的GUI(Graphics User Interface图形用户界面)编程
GUI的各元素(如:窗口,按钮,文本框等)由Java类来实现
使用AWT所涉及的类一般在java.awt包及其子包中
Container和Component是AWT中的两个核心类
所有的可以显示出来的图形元素都叫Component
Component中有一类比较特殊的叫做Container,它是用来容纳其它Component的元素
Container里面又分两种,一种叫Window,一种叫Panel
Window是可以独立显示的
Window本身又分两种,一种叫Frame(一般的窗口),一种叫Dialog(对话框)
Dialog又分两种,一种叫模态的对话框,一种叫非模态的对话框
Panel一般看不见它,它也可以容纳其它的元素,把Panel装在Window里面再显示出来
组件和容器
Component & Container
Java的图形用户界面的最基本组成部分是Component,Component类及其子类的对象
用来描述以图形化的方式显示在屏幕上并能与用户进行交互的GUI元素,例如,一个按钮,
一个标签等
一般的Component对象不能独立的显示出来,必须将“放在”某一个Container对象中才可以
显示出来
Container是Component子类,Container子类对象可以“容纳”别的Component对象
Container对象可使用方法add(...)向其中添加其他Component对象
Container是Component子类,因此Container对象也可以被当作Component对象添加
到其他Container对象中
有两种常有的Container:
Window:其对象表示自由停泊的顶级窗口
Panel:其对象可作为容纳其他Component对象,但不能独立存在,必须被添加到其他
Container中(如Window 或 Applet)
Window - Frame
Frame是Window的子类,由Frame或其子类创建的对象为一个窗体
Frame的常用构造方法:
Frame()
Frame(String s)创建标题栏为字符串s的窗口
setBounds(int x, int y, int width, int height)
//设置窗体位置和大小,x、y是左上角坐标,width和height是宽度和高度
setSize(int width, int height)
//设置窗体的大小,width和height分别是宽度和高度
setLocation(int x, int y)
//设置窗体的位置,x、y是左上角坐标
setBackground(Color c)
//设置背景颜色,参数为Color对象 java.awt包中的Color类定义了各种颜色
setVisible(boolean b)
//设置是否可见
setTitle(String name)
//设置标题栏
String getTitle()
//获得标题栏
setResizable(boolean b)
//设置是否可以调整大小
Frame类有个子类叫JFrame,它是在swing包里
/*
* TestFrame.java
* Frame组件的创建及显示设置
*/
import java.awt.*;
public class TestFrame {
public static void main(String args[]) {
Frame f = new Frame("My First Test");
f.setSize(170, 100);
f.setBackground(Color.blue);
f.setVisible(true); //Frame new出来是内存里的一个对象,必须setVisible传入true才能显示出来
}
}
/*
* TestMultiFrame.java
* 显示多个窗口
*/
import java.awt.*;
public class TestMultiFrame {
public static void main(String args[]) {
MyFrame f1 =
new MyFrame(100,100,200,200,Color.BLUE);
MyFrame f2 =
new MyFrame(300,100,200,200,Color.YELLOW);
MyFrame f3 =
new MyFrame(100,300,200,200,Color.GREEN);
MyFrame f4 =
new MyFrame(300,300,200,200,Color.MAGENTA);
}
}
class MyFrame extends Frame {
static int id = 0;
MyFrame(int x, int y, int w, int h, Color color) {
super("MyFrame " + (++id));
setBackground(color);
setLayout(null); //把窗口内部自己的布局管理器设为空
setBounds(x, y, w, h);
setVisible(true);
}
}
Window - Panel
Panel对象可以看成是可以容纳Component的空间
Panel对象可以拥有自己的布局管理器
Panel类拥有从其父类继承来的:
setBounds(int x, int y, int width, int height)
setSize(int width, int height)
setLocation(int x, int y)
setBackground(Color c)
setLayout(LayoutManager mgr)等方法
Panel的构造方法为:
Panel() 使用默认的FlowLayout类布局管理器初始化
Panel(LayoutManager layout) 使用指定的布局管理器初始化
/*
* TestPanel.java
*/
import java.awt.*;
public class TestPanel {
public static void main(String args[]) {
Frame f = new Frame("Java Frame with Panel");
Panel p = new Panel(null);
f.setLayout(null);
f.setBounds(300, 300,500, 500); //Frame设置Bounds相对于屏幕
f.setBackground(new Color(0, 0, 102));
p.setBounds(50, 50, 400, 400); //Panel设置Bounds相对于它装到谁里边,就相对于谁
p.setBackground(new Color(204, 204, 255));
f.add(p);
f.setVisible(true);
}
}
/*
* TestMultiPanel.java
*/
import java.awt.*;
public class TestMultiPanel {
public static void main(String args[]) {
new MyFrame2("My Frame with Panel", 300, 300, 400, 400);
}
}
class MyFrame2 extends Frame {
private Panel p1,p2,p3,p4;
MyFrame2(String s, int x, int y, int w, int h) {
super(s);
setLayout(null);
p1 = new Panel(null); //传空表明这几个Panel不在自己的布局管理器里
p2 = new Panel(null);
p3 = new Panel(null);
p4 = new Panel(null);
p1.setBounds(0, 0, w/2, h/2);
p2.setBounds(0, h/2, w/2, h/2);
p3.setBounds(w/2, 0, w/2, h/2);
p4.setBounds(w/2, h/2, w/2, h/2);
p1.setBackground(Color.BLUE);
p2.setBackground(Color.GREEN);
p3.setBackground(Color.YELLOW);
p4.setBackground(Color.MAGENTA);
add(p1);
add(p2);
add(p3);
add(p4);
setBounds(x, y, w, h);
setVisible(true);
}
}
布局管理器
Java语言中提供了布局管理器类的对象可以管理:
1)管理Component在Container中的布局,不必直接设置Component位置和大小
2)每个Container都有一个布局管理器对象,当容器需要对某个组件进行定位
或判断其大小尺寸时,就会调用其对应的布局管理器,调用Container的setLayout
方法改变其布局管理器对象
AWT提供了5种布局管理器类:
FlowLayout
BorderLayout
GridLayout
CardLayout
GridBagLayout
布局管理器是布局排列的大管家,布局管理器各有各的风格
封装了布局管理器的类是LayoutManager,AWT提供给我们的布局管理器都是实现了
LayoutManager接口的类,因此我们可以用Container的setLayout方法来设置哪一种
布局管理器在起作用
FlowLayout布局管理器
FlowLayout是Panel类的默认布局管理器
FlowLayout布局管理器对组件逐行定位,行内从左到右,一行排满后换行
不改变组件的大小,按组件原有尺寸显示组件,可设置不同的组件间距,行距以及对齐方式
FlowLayout布局管理器默认的对齐方式是居中
FlowLayout的构造方法
new FlowLayout(FlowLayout.RIGHT, 20, 40);
右对齐,组件之间水平间距20个像素,垂直间距40个像素
new FlowLayout(FlowLayout.LEFT);
左对齐,水平和垂直间距为缺省值(5)
new FlowLayout();
使用缺省的居中对齐方式,水平和垂直间距为缺省值(5)
BorderLayout布局管理器
BorderLayout是Frame类的默认布局管理器
BorderLayout将整个容器和布局划分成
东(EAST)
西(WEST)
南(SOUTH)
北(NORTH)
中(CENTER)五个区域,组件只能被添加到指定的区域
如不指定组件的加入部位,则默认加入到CENTER区
每个区域只能加入一个组件,如加入多个,则先前加入的会被覆盖
BorderLayout型布局管理器尺寸缩放原则:
北、南两个区域在水平方向缩放
东、西两个区域在垂直方向缩放
中部可在两个方向上缩放
GridLayout布局管理器
GridLayout型布局管理器将空间划分成规则的矩形网络,每个单元格
区域大小相等。组件被添加到每个单元格中,先从左到右添满一行后
换行,再从上到下
在GridLayout构造方法中指定分隔的行数和列数
如:GridLayout(3, 4)
布局管理器总结
1)Frame是一个顶级窗口,Frame的缺省布局管理器为BorderLayout
2)Panel无法单独显示,必须添加到某个容器中
Panel的缺省布局管理器为FlowLayout
3)当把Panel作为一个组件添加到某个容器中后,该Panel仍然可以有
自己的布局管理器
4)使用布局管理器时,布局管理器负责各个组件的大小和位置,因此
用户无法在这种情况下设置组件大小和位置属性,如果试图使用Java
语言提供的setLocation(),setSize(),setBounds()等方法,则都会
被布局管理器覆盖
5)如果用户确实需要亲自设置组件大小或位置,则应取消该容器的布局
管理器,方法为:
setLayout(null);
事件处理
事件监听
事件源对象:发出这件事的是哪个Component,是哪个元素?TextFild、Button啊等
事件:事件本身也是对象。到底发生的是什么事。事件和监听这个事件的接口一一对应
当某件事发生的时候:事件源对象会调用实现了监听器接口的对象的方法
注册:把自己的监听器的对象注册到事件源对象中
当有一个按钮,我们想要知道它什么时候被按下去了,可以主动的监听,
是一件很昂贵的一件事,显然不好。实际上我们可以监听按钮被按下去这件
事有没有发生,发生了就可以执行后面的操作
这种执行操作,叫钩子函数,也叫回调函数
原理是:你实现某一个特定的接口,而Button里边也照着这个接口调用实际当中
的对象,Button把你这个类的对象当成某一个固定的接口来调用,你肯定要实现
某一个固定的接口的某一个特定的方法
Button调用的是接口里的方法,根据多态的原理,实际上你new的是谁调用的就是
谁的方法
当我们的Button被按下去时,发出的事叫做ActionEvent(动作事件)
/*
* TestActionEvent.java
* 1. Java事件处理机制
* 2. 事件源、事件监听器概念及作用
* 3. 如何在一个现有组件上注册监听器
*/
import java.awt.*;
import java.awt.event.*;
public class TestActionEvent {
public static void main(String args[]) {
Frame f = new Frame("Test");
Button b = new Button("Press Me!");
Monitor bh = new Monitor();
b.addActionListener(bh);
f.add(b, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
}
class Monitor implements ActionListener {
public void actionPerformed(ActionEvent e) { //ActionEvent对象包装了这件事发生的具体信息
System.out.println("a button has been pressed");
}
}
这个事件模型,它实现了Observer设计模式(观察者模式)。一般的伴随事件模型
还有Command模式
TextField类
java.awt.TextField类用来创建文本框对象。就是一个输入框。
TextField有如下常用方法:
TextField()
TextField(int columns)
TextField(String text)
TextField(String text, int columns)
public void setText(String t)
public String getText()
public void setEchoChar(char c) //设置回显字符
public void setEditable(boolean b)
public boolean isEditable()
public void setBackground(Color c)
public void select(int selectionStart, int selectionEnd)
public void selectAll()
public void addActionListener(ActionListener l) //添加动作监听器
tf.setEchoChar("*"); //和密码框差不多,文本框回显的都是*号
TextField事件监听
1)TextField对象可能发生Action(光标在文本框内敲击回车)事件。与该事件对应
的事件类是java.awt.event.ActionEvent
2)用来处理ActionEvent事件是实现了java.awt.event.ActionListener接口的
类的对象。ActionListener接口定义有方法:
public void actionPerformed(ActionEvent e)
3)实现该接口的类要在该方法中添加处理该事件(Action)的语句
4)使用addActionListener(ActionListener l)方法为TextField对象注册一个
ActionListener对象,当TextField对象发生Action事件时,会生成一个ActionEvent
对象,该对象作为参数传递给ActionListener对象的actionPerformerd方法在方法中
可以获取该对象的信息,并做相应的处理
/*
* TFTestActionEvent.java
*/
import java.awt.*;
import java.awt.event.*;
public class TFTestActionEvent {
public static void main(String args[]) {
new TFFrame();
}
}
class TFFrame extends Frame {
TFFrame() {
TextField tf = new TextField();
add(tf);
tf.addActionListener(new TFActionListener());
pack();
setVisible(true);
}
}
class TFActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
TextField tf = (TextField)e.getSource(); //getSource拿到事件源,返回值是事件发生在哪个对象上
System.out.println(tf.getText());
tf.setText("");
}
}
持有对方的引用
这种模式叫做Facade模式,门面模式。有一个大管家管着所有的事,其他人要互相打交道
都要通过这个大管家。对内叫调停者模式,Mediator模式
/*
* TFMath.java
* 持有对方的引用
*/
import java.awt.*;
import java.awt.event.*;
public class TFMath {
public static void main(String args[]) {
new TFFrame().launchFrame();
}
}
class TFFrame extends Frame {
TextField num1, num2, num3; //设置成成员变量,Button才能拿到它的内容
public void launchFrame() {
num1 = new TextField(10);
num2 = new TextField(10);
num3 = new TextField(15);
Label lbPlus = new Label("+");
Button btnEqual = new Button("=");
btnEqual.addActionListener(new MyMonitor(this));
setLayout(new FlowLayout());
add(num1);
add(lbPlus);
add(num2);
add(btnEqual);
add(num3);
pack();
setVisible(true);
}
}
class MyMonitor implements ActionListener {
//在监听器对象里边持有整个Frame的引用
//不需要记住Frame内部装了什么,不用再装一遍
TFFrame tf = null;
public MyMonitor(TFFrame tf) {
this.tf = tf;
}
public void actionPerformed(ActionEvent e) {
int n1 = Integer.parseInt(tf.num1.getText());
int n2 = Integer.parseInt(tf.num2.getText());
tf.num3.setText("" + (n1+n2));
}
}
内部类
内部类可以非常方便的访问包装类的成员变量或成员方法
内部类编译出来的class文件:TFFrame2$MyMonitor.class
好处:
可以方便的访问包装类的成员
可以更清楚的组织逻辑,防止不应该被其他类访问的类进行访问
何时使用:
该类不允许或不需要其他类进行访问时,可以把内部类设成private class XXX
/*
* TFMath2.java
* 内部类
*/
import java.awt.*;
import java.awt.event.*;
public class TFMath2 {
public static void main(String args[]) {
new TFFrame2().launchFrame();
}
}
class TFFrame2 extends Frame {
TextField num1, num2, num3; //设置成成员变量,Button才能拿到它的内容
public void launchFrame() {
num1 = new TextField(10);
num2 = new TextField(10);
num3 = new TextField(15);
Label lbPlus = new Label("+");
Button btnEqual = new Button("=");
btnEqual.addActionListener(new MyMonitor());
setLayout(new FlowLayout());
add(num1);
add(lbPlus);
add(num2);
add(btnEqual);
add(num3);
pack();
setVisible(true);
}
//内部类可以畅通无阻的访问包装类的成员变量或成员方法
//外部类对象默认的就拥有内部类对象的引用
class MyMonitor implements ActionListener {
public void actionPerformed(ActionEvent e) {
int n1 = Integer.parseInt(num1.getText());
int n2 = Integer.parseInt(num2.getText());
num3.setText("" + (n1+n2));
}
}
}
Java图形
Graphics类
每个Component都有一个paint(Graphics g)用于实现绘图目的,每次重画
该Component是都自动调用paint方法
Graphics类中提供了许多绘图方法,如:
drawRect(int x, int y, int width, int height)
fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)等
/*
* TestPaint.java
*/
import java.awt.*;
public class TestPaint {
public static void main(String args[]) {
new PaintFrame().launchFrame();
}
}
class PaintFrame extends Frame {
public void launchFrame() {
setBounds(200, 200, 640, 480);
setVisible(true);
}
public void paint(Graphics g) { //重写paint方法
Color c = g.getColor();
g.setColor(Color.red);
g.fillOval(50, 50, 30, 30);
g.setColor(Color.GREEN);
g.fillRect(80, 80, 40, 40);
g.setColor(c); //把原来的颜色设回去
}
}
画直线:在Graphics类中有public abstract void drawLine方法,它是一个抽象方法。为什么
抽象方法它可以直接调用?这里面有一个多态的存在,传到paint方法里面的是Graphics类的子类
调用的是子类的drawLine方法
鼠标事件适配器
抽象类java.awt.event.MouseAdapter实现了MouseListener接口,可以使用
其子类作为MouseEvent的监听器,只要重写其相应的方法即可
对于其他的监听器,也有对应的适配器
使用适配器可以避免监听器类定义没有必要的空方法
MyMouseAdapter.java鼠标适配器
/*
* MyMouseAdapter.java
*/
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class MyMouseAdapter {
public static void main(String args[]) {
new MyFrame("drawing...");
}
}
class MyFrame extends Frame {
ArrayList points = null;
MyFrame(String s) {
super(s);
points = new ArrayList();
setLayout(null);
setBounds(300, 300, 400, 300);
this.setBackground(new Color(204, 204, 255));
setVisible(true);
this.addMouseListener(new Monitor());
}
public void paint (Graphics g) {
Iterator i = points.iterator();
while (i.hasNext()) { //把这个ArrayList里所有点都拿出来
Point p = (Point)i.next();
g.setColor(Color.BLUE);
g.fillOval(p.x, p.y, 10, 10);
}
}
public void addPoint(Point p) {
points.add(p);
}
}
//addMouseListener参数是MouseListener接口
//MouseAdapter实现了MouseListener接口
//如果Monitor直接实现MouseListener接口,要把5个接口都定义一边
class Monitor extends MouseAdapter {
public void mousePressed(MouseEvent e) {
MyFrame f = (MyFrame)e.getSource();
f.addPoint(new Point(e.getX(), e.getY()));
f.repaint(); //让Frame强制重画,这个方法内部调用paint方法
}
}
repaint - update() - paint();
图形中的双缓冲,repaint调用update方法,update方法调用了paint方法
大多数图形系统都会有双缓冲
Window事件
Window事件所对应的事件类为WindowEvent,所对应的事件监听接口为WindowListener
WindowListener定义的方法有:
public void windowOpened(WindowEvent e)
public void windowClosing(WindowEvent e) //窗口正在被关闭
public void windowClosed(WindowEvent e) //窗口已经关了
public void windowIconified(WindowEvent e) //让窗口最小化
public void windowDeiconified(WindowEvent e) //让窗口恢复正常
public void windowActivated(WindowEvent e)
public void windowDeactivated(WindowEvent e)
与WindowListener对应的适配器为WindowAdapter
当一个类和除了某个方法之外都没有关系,可以用匿名内部类
/*
* TestWindowClose.java
*/
import java.awt.*;
import java.awt.event.*;
public class TestWindowClose {
public static void main(String args[]) {
new MyFrame55("MyFrame");
}
}
class MyFrame55 extends Frame {
MyFrame55 (String s) {
super(s);
setLayout(null);
setBounds(300, 300, 400, 300);
this.setBackground(new Color(204, 204, 255));
setVisible(true);
this.addWindowListener(
new WindowAdapter() { //使用匿名类
public void windowClosing(WindowEvent e) {
setVisible(false);
System.exit(-1);
}
}
);
}
}
键盘事件
键盘上的按键对应一个虚拟的码
/*
* TestKey.java
*/
import java.awt.*;
import java.awt.event.*;
public class TestKey {
public static void main(String args[]) {
new KeyFrame().launchFrame();
}
}
class KeyFrame extends Frame {
public void launchFrame() {
setSize(200, 200);
setLocation(300, 300);
addKeyListener(new MyKeyMonitor());
setVisible(true);
}
class MyKeyMonitor extends KeyAdapter {
public void keyPressed(KeyEvent e) {
//System.out.println("ok");
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) {
System.out.println("up");
}
}
}
}
小结
一个图
布局管理器
事件模型
ActionEvent
MouseEvent
WindowEvent
KeyEvent
graphics类和paint方法
双缓冲 repaint - update - paint
内部类、匿名类