七. I/O操作,字节流,字符流,字符集编码
1.I/O操作
是放在java.io包中的;
2.File类
一个File类的对象,表示了磁盘上的文件或目录。
File类提供了与平台无关的方法来对磁盘上的文件或目录进行操作。
import java.io.*;
class FileTest
{
public static void main(String[] args) throws Exception //IO操作会经常抛出异常,我们交给JVM来处理
{
//File f=new File("1.txt");
// f.createNewFile(); //创建一个文件1.txt
//f.mkdir(); //创建一个目录:1.txt
/*指定绝对路径:\在JAVA是特殊的转义字符;所以输出\用“\\” */
//File f=new File("E:\\JavaLesson\\Lesson7\\1.txt"); //--但它只能在当前windows系统有效;在Linux下无效
File fDir = new File(File.separator); //定义父目录为根目录;在windows下表示当前运行盘符的根目录!
String strFile="JavaLesson"+File.separator+
"Lesson7"+File.separator+"1.txt"; //win和Linux系统中编译成不同符合;
File f = new File(fDir,strFile); //根目录+当前目录和文件;可移植到Linux;
f.createNewFile();
}
}
属性和方法:
a.separator
separator属性用来代表路径斜杠;通用的!
构造函数可以采用父目录+子文件名的方式:
File(File parent, String child)
Creates a new File instance from a parent abstract pathname and a child pathname string.
b.删除文件:delete()
boolean delete()
Deletes the file or directory denoted by this abstract pathname.
f.delete() //将f文件删除
c.deleteOnExit
deleteOnExit(); 在程序退出的时候删除文件!
可以用来删除垃圾文件;临时文件等;
d.createTempFile 创建临时文件到临时目录(返回File对象);
static File createTempFile(String prefix, String suffix)
Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its name.
e.g.: for(int i=0;i<5;i++)
{
File f = File.createTempFile("winsun",".tmp"); //会创建到系统默认的临时文件夹中;
f.deleteOnExit(); //必须手动删除
}
Thread.sleep(3000);
e.List()方法:
String[] list() ---返回字符串数组; 列出所有文件和子目录;
Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname.
e.g.:
File fDir=new File(File.separator);
String strFile="JavaLesson"+File.separator+"Lesson6";
File f=new File(fDir,strFile);
String[] names=f.list(); //返回一个数组
for(int i=0;i<names.length;i++)
{
System.out.println(names[i]); //打印内容
}
e.2 增加过滤器: -- 增加条件
String[] list(FilenameFilter filter) --增加一个文件过滤器,选择文件
Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter.
其中,FilenameFilter 是一个接口;包含一个方法accept:
boolean accept(File dir, String name) ---- Tests if a specified file should be included in a file list.
e.g.:
File fDir=new File(File.separator);
String strFile="JavaLesson"+File.separator+"Lesson6";
File f=new File(fDir,strFile);
//利用内部类来实现FilenameFilter接口,accept方法使用了一个Sting的indexOf方法:
String[] names=f.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.indexOf(".java")!=-1;
} //有.java子串时返回真,选所有java文件!
}); //作为方法参数传递
for(int i=0;i<names.length;i++)
{
System.out.println(names[i]);
}
e.3: String.indexOf()
int indexOf(String str)
Returns the index within this string of the first occurrence of the specified substring.
功能: 返回子串的索引值,当没有该子串时返回-1
在File类中,没有给我们提供对文件进行读写操作的方法!
3.输入流,输出流 --- 流式I/O
流(Stream)是字节的源或目的。
两种基本的流是:输入流(Input Stream)和输出流(Output Stream)。可从中读出一系列字节的对象称为输入流。而能向其中写入一系列字节的对象称为输出流。
流的分类:
节点流:从特定的地方读写的流类,例如:磁盘或一块内存区域。
过滤流:使用节点流作为输入或输出。过滤流是使用一个已经存在的输入流或输出流连接创建的。 --- 能够获得一些额外的功能!
4.InputStream -- 抽象类!
三个基本的读方法
abstract int read() :读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。 -- 返回一个整型,所以int中第一个字节有效,后三个无效!
int read(byte[] b) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。
int read(byte[] b, int off, int len) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。
其它方法
long skip(long n) :在输入流中跳过n个字节,并返回实际跳过的字节数。
int available() :返回在不发生阻塞的情况下,可读取的字节数。
void close() :关闭输入流,释放和这个流相关的系统资源。-- 创建一个输入流时,OS会分配一些资源;
void mark(int readlimit) :在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。 -- 在InputStream中是个空实现!
void reset() :返回到上一个标记。-- 在InputStream中是个空实现!
boolean markSupported() :测试当前流是否支持mark和reset方法。如果支持,返回true,否则返回false。-- 然后再实现
5. OutputStream
三个基本的写方法
abstract void write(int b) :往输出流中写入一个字节。
void write(byte[] b) :往输出流中写入数组b中的所有字节。
void write(byte[] b, int off, int len) :往输出流中写入数组b中从偏移量off开始的len个字节的数据。
其它方法
void flush() :刷新输出流,强制缓冲区中的输出字节被写出。-- 为了加快输出设备的出入速度,一般先写到缓冲区,然后一次性与I/O设备交互进行输出,但是为了立即输出,则采用此方法!
void close() :关闭输出流,释放和这个流相关的系统资源。
System.out 就是一个PrintStream类型!
System还有两个对象: in, out 从标准输入设备读,从标准输出设备写
6.基本的流类
FileInputStream和FileOutputStream
节点流,用于从文件中读取或往文件中写入字节流。如果在构造FileOutputStream时,文件已经存在,则覆盖这个文件。
e.g.:
import java.io.*;
class StreamTest
{
public static void main(String[] args) throws Exception
{
FileOutputStream fos=new FileOutputStream("1.txt");
fos.write("http://www.mybole.com.cn".getBytes()); //write(byte[] b) -- 需要个字节数组,利用String的方法得到!神奇!
fos.close(); //关闭资源
FileInputStream fis=new FileInputStream("1.txt"); //用已存在的文件构造文件输入流对象;
byte[] buf=new byte[100];
int len=fis.read(buf); //从文件中读取数据流到buf数组
System.out.println(new String(buf,0,len)); //用字节数组构造String串,用另一个构造函数
fis.close();
}
}
BufferedInputStream和BufferedOutputStream
过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率。
BufferedInputStream将mark和reset方法实现了!BufferedOutputStream实现了flush方法
需要用已经存在的FileInputStream和FileOutputStream 来构建它们!
import java.io.*;
class StreamTest
{
public static void main(String[] args) throws Exception
{
FileOutputStream fos=new FileOutputStream("1.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos); //用fos来构建bos
bos.write("http://www.winsun.com.cn".getBytes()); //将字符串写入bos对象
bos.flush(); //或者用 bos.close(); 也能将缓冲区的数据写入磁盘! 关了它就无需关闭fos了!-- 连锁
FileInputStream fis=new FileInputStream("1.txt");
BufferedInputStream bis=new BufferedInputStream(fis); //用fis构建bis
byte[] buf=new byte[100];
int len=bis.read(buf); //读出对象内容到buf中
System.out.println(new String(buf,0,len));
bis.close(); //无需再fis.close;
}
}
DataInputStream和DataOutputStream
过滤流,需要使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能。
是由FilterInputStream继承而来,实现了DataInput接口(基本类型的读取);Output类似!
Constructor:
DataOutputStream(OutputStream out)
e.g.
import java.io.*;
class StreamTest
{
public static void main(String[] args) throws Exception
{
FileOutputStream fos=new FileOutputStream("1.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos);
DataOutputStream dos=new DataOutputStream(bos); //也可以用fos!
byte b=3;
int i=78;
char ch='a';
float f=4.5f;
dos.writeByte(b); //dos中实现的方法
dos.writeInt(i);
dos.writeChar(ch);
dos.writeFloat(f);
dos.close(); //由于我们链接了一个bos,所以有buffer的功能!关闭才能写入!
FileInputStream fis=new FileInputStream("1.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
DataInputStream dis=new DataInputStream(bis);
System.out.println(dis.readByte());
System.out.println(dis.readInt());
System.out.println(dis.readChar());
System.out.println(dis.readFloat());
dis.close();
}
}
PipedInputStream和PipedOutputStream
管道流,用于线程间的通信。一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。要使管道流有用,必须同时构造管道输入流和管道输出流。
可用无参构造,然后用connect()方法进行连接;
也可在构造的时候直接指定管道输出流进行连接!
PipedInputStream(PipedOutputStream src)
Creates a PipedInputStream so that it is connected to the piped output stream src.
同样,PipedOutputStream也有类似的方法!
注意管道流是由输入输出流继承而来的而不是过滤流FilterInput(Output)Stream继承而来的!
e.g.
import java.io.*;
class PipedStreamTest
{
public static void main(String[] args) throws Exception
{
PipedOutputStream pos=new PipedOutputStream();
PipedInputStream pis=new PipedInputStream();
try
{
pos.connect(pis); //也可以反过来连接,或者构造的时候连接!
new Producer(pos).start();
new Consumer(pis).start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
class Producer extends Thread //用管道输出流定义生产者
{
private PipedOutputStream pos;
public Producer(PipedOutputStream pos)
{
this.pos=pos;
}
public void run()
{
try
{
pos.write("Hello,welcome you!".getBytes());
pos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
class Consumer extends Thread //用管道输入流定义消费者
{
private PipedInputStream pis;
public Consumer(PipedInputStream pis)
{
this.pis=pis;
}
public void run()
{
try
{
byte[] buf=new byte[100];
int len=pis.read(buf); //无实体文件,直接从输入流中读(得到的是对应输出流中的数据)
System.out.println(new String(buf,0,len)); //字节数组,偏移量,长度
pis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
7.Java I/O库的设计原则
Java的I/O库提供了一个称做链接的机制,可以将一个流与另一个流首尾相接,形成一个流管道的链接。这种机制实际上是一种被称为Decorator(装饰)设计模式的应用。
通过流的链接,可以动态的增加流的功能,而这种功能的增加是通过组合一些流的基本功能而动态获取的。
我们要获取一个I/O对象,往往需要产生多个I/O对象,(如buffer流产生就需要先构造基本输入输出流)这也是Java I/O库不太容易掌握的原因,但在I/O库中Decorator模式的运用,给我们提供了实现上的灵活性。
之前的都是字节流;下面介绍字符流:
8.Reader和Writer
Java程序语言使用Unicode来表示字符串和字符(一个字符用两个字节表示)。
Reader和Writer这两个抽象类主要用来读写字符流。
BufferedRead并没有从FilterReader中派生而来(不同于字节流中的层次),是sun的一个bug!
InputStreamReader起到了一个桥梁的作用,用来进行字符流与字节流之间的相互转换!
BufferedWriter以及OutputStreamWriter与上面对应!
BufferedReader,BufferedWriter提供了对字符的快速读取
构造函数:
OutputStreamWriter(OutputStream out)
Creates an OutputStreamWriter that uses the default character encoding.
import java.io.*;
class StreamTest
{
public static void main(String[] args) throws Exception
{
FileOutputStream fos=new FileOutputStream("1.txt");
OutputStreamWriter sw=new OutputStreamWriter(fos); //字节流到字符流的桥梁!
BufferedWriter bw=new BufferedWriter(osw); //写操作一般用这个而不用OSW,更高效!
/*Constructor:BufferedWriter(Writer out) Creates a buffered character-output stream
that uses a default-sized output buffer. -- OSW是Writer的子类,所以也可以用来构造*/
bw.write("http://www.mybole.com.cn");
bw.close();
FileInputStream fis=new FileInputStream("1.txt");
InputStreamReader isr=new InputStreamReader(fis);
BufferedReader br =new BufferedReader(isr);
System.out.println(br.readlLine());
br.close();
}
}
从键盘接收多行输入,然后输出到屏幕:
InputStreamReader isr=new InputStreamReader(System.in); //不用文件输入流(fis)构造了,而直接用in
BufferedReader br=new BufferedReader(isr);
String strLine;
while((strLine=br.readLine())!=null) //按行读取
{
System.out.println(strLine);
}
br.close();
9.字符集的编码
ASCII(American Standard Code for Information Interchange,美国信息互换标准代码),是基于常用的英文字符的一套电脑编码系统。我们知道英文中经常使用的字符、数字符号被计算机处理时都是以二进制码的形式出现的。这种二进制码的集合就是所谓的ASCII码。每一个ASCII码与一个8位(bit)二进制数对应。其最高位是0,相应的十进制数是0-127。如,数字?°0?±的编码用十进制数表示就是48。另有128个扩展的ASCII码,最高位都是1,由一些制表符和其它符号组成。ASCII是现今最通用的单字节编码系统。
GB2312:GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集-基本集》。主要用于给每一个中文字符指定相应的数字,也就是进行编码。一个中文字符用两个字节的数字来表示,为了和ASCII码有所区别,将中文字符每一个字节的最高位置都用1来表示。
GBK:为了对更多的字符进行编码,国家又发布了新的编码系统GBK(GBK的K是?°扩展?±的汉语拼音第一个字母)。在新的编码系统里,除了完全兼容GB2312 外,还对繁体中文、一些不常用的汉字和许多符号进行了编码。
ISO-8859-1:是西方国家所使用的字符编码集,是一种单字节的字符集 ,而英文实际上只用了其中数字小于128的部分。
Unicode:这是一种通用的字符集,对所有语言的文字进行了统一编码,对每一个字符都用2个字节来表示,对于英文字符采取前面加“0”字节的策略实现等长兼容。如 “a” 的ASCII码为0x61,UNICODE就为0x00,0x61。
UTF-8:Eight-bit UCS Transformation Format,(UCS,Universal Character Set,通用字符集,UCS 是所有其他字符集标准的一个超集)。一个7位的ASCII码值,对应的UTF码是一个字节。如果字符是0x0000,或在0x0080与0x007f之间,对应的UTF码是两个字节,如果字符在0x0800与0xffff之间,对应的UTF码是三个字节。
10.CharsetTest
Charset类有个方法能列出可以使用的字符集:
static SortedMap<String,Charset> availableCharsets()
Constructs a sorted map from canonical charset names to charset objects.
import java.util.*;
import java.nio.charset.*;
class CharsetTest
{
public static void main(String[] args) throws Exception
{
Map m=Charset.availableCharsets(); //调用静态方法
Set names=m.keySet(); //map接口的keyset方法返回key的集合
Iterator it=names.iterator(); //集合没有get方法,用迭代器
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
java.lang.System.有个getProperty方法
Properties pps=System.getProperties(); //属性类
pps.list(System.out); //列出所有系统属性 file.encoding
在java中,字节,字符串都是用unicode来构成的;所以得到unicode(如:获得字符或字符串)的过程就是解码,把unicode转化成本地字符集所表示的编码的过程就是编码!
import java.util.*;
import java.nio.charset.*; //new io
class CharsetTest
{
public static void main(String[] args) throws Exception
{
Properties pps=System.getProperties(); //属性类
pps.list(System.out); //列出所有系统属性 file.encoding
pps.put("file.encoding","ISO-8859-1"); //设置属性的方法!
int data;
byte[] buf=new byte[100];
int i=0;
while((data=System.in.read())!='q') //从键盘读取中文字符,q退出;读取使用OS默认charset:中文GBK!
//在标准设备读取时,依赖于本地操作系统字符集
{
buf[i]=(byte)data; //中文会以GBK码值存储;默认charset
i++;
}
String str=new String(buf,0,i); //获取字符 --- 解码!解码使用JVM指定的编码:ISO...
System.out.println(str); //打印出乱码! -- Java 1.6中正常打印, Why?
String strGBK=new String (str.getBytes("ISO-8859-1"),"GBK"); //用ISO先编码回去,然后再用GBK重新解码!!!!
System.out.println(strGBK);
}
}
11. RandomAccessFile
RandomAccessFile类同时实现了DataInput和DataOutput接口(-- 所以实现了对基本数据类型的读写!),提供了对文件随机存取的功能,利用这个类可以在文件的任何位置读取或写入数据。
RandomAccessFile类提供了一个文件指针,用来标志要进行读写操作的下一数据的位置。
Constructor:
RandomAccessFile(String name, String mode)
Creates a random access file stream to read from, and optionally to write to, a file with the specified name.
--- mode:Value Meaning:
"r" Open for reading only. Invoking any of the write methods of the resulting object will cause an IOException to be thrown.
"rw" Open for reading and writing. If the file does not already exist then an attempt will be made to create it.
"rws" Open for reading and writing, as with "rw", and also require that every update to the file's content or metadata be written synchronously to the underlying storage device.
"rwd" Open for reading and writing, as with "rw", and also require that every update to the file's content be written synchronously to the underlying storage device.
writeBytes(String str) //中文字符会
writeChars(String str)
writeUTF(String str) //在前两个字节中记录了字符的长度! 常用这个!
11.1: long length()
Returns the length of this file.
11.2: long getFilePointer()
Returns the current offset in this file. offset:偏移量!
11.3: void seek(long pos)
Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs.
e.g.:
import java.io.*;
class RandomFileTest
{
public static void main(String[] args) throws Exception
{
Student s1=new Student(1, "zhangsan", 98.5);
Student s2=new Student(2, "sdsan", 74.5);
Student s3=new Student(3, "adsfn", 81.5);
RandomAccessFile raf=new RandomAccessFile("student.txt","rw");
s1.writeStudent(raf);
s2.writeStudent(raf);
s3.writeStudent(raf);
Student s=new Student();
raf.seek(0);
for(long i=0;i<raf.length();i=raf.getFilePointer()) //因为length返回值为long故i也定义为long!
//getFilePointer() 获得文件中当前的偏移量!
{
s.readStudent(raf);
System.out.println(s.num+":"+s.name+":"+s.score);
}
raf.close();
}
}
class Student
{
int num;
String name;
double score;
public Student()
{
}
public Student(int num, String name, double score)
{
this.num=num;
this.name=name;
this.score=score;
}
public void writeStudent(RandomAccessFile raf) throws IOException
{
raf.writeInt(num);
raf.writeUTF(name);//writeUTF前两个字节记录了写入的字节数
raf.writeDouble(score);
}
public void readStudent(RandomAccessFile raf) throws IOException
{
num=raf.readInt();
name=raf.readUTF();
score=raf.readDouble();
}
} //随时注意文件指针!
12.对象序列化
将对象转换为字节流保存起来,并在日后还原这个对象,这种机制叫做对象序列化。
将一个对象保存到永久存储设备上称为持续性。
一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。--IO包内; Serializable接口中没有方法,是个空接口!标示接口!Externalizable是从Serializable继承而来的!
要想实现对象的序列化,我们可以利用两个类:ObjectOutputStream/ObjectInputStream 它们实现了DataOutput/DataInput对象,可以读写基本数据类型!
其中有个方法writeObject(),写入对象成员!
ObjectOutputStream(OutputStream out) -- 将对象信息转化成字节流写入文件中保存!
Creates an ObjectOutputStream that writes to the specified OutputStream.
import java.io.*;
class ObjectSerialTest
{
public static void main(String[] args) throws Exception
{
Employee e1=new Employee("zhangsan",25,3000.50);
Employee e2=new Employee("lisi",24,3200.40);
Employee e3=new Employee("wangwu",27,3800.55);
FileOutputStream fos=new FileOutputStream("employee.txt");
ObjectOutputStream os=new ObjectOutputStream(fos);
oos.writeObject(e1);
oos.writeObject(e2);
oos.writeObject(e3);
oos.close();
FileInputStream fis=new FileInputStream("employee.txt");
ObjectInputStream is=new ObjectInputStream(fis);
Employee e;
for(int i=0;i<3;i++)
{
e=(Employee)ois.readObject(); // 反序列化的时候并不会调用构造函数!
System.out.println(e.name+":"+e.age+":"+e.salary);
}
ois.close();
}
}
class Employee implements Serializable
{
String name;
int age;
double salary;
transient Thread t=new Thread();
public Employee(String name,int age,double salary)
{
this.name=name;
this.age=age;
this.salary=salary;
}
private void writeObject(java.io.ObjectOutputStream oos) throws IOException //重新定义写方法,实现自己的控制,如薪水加密后再保存,可无
{
oos.writeInt(age);
oos.writeUTF(name);
System.out.println("Write Object");
}
private void readObject(java.io.ObjectInputStream ois) throws IOException //重新定义读方法,可无!
{
age=ois.readInt();
name=ois.readUTF();
System.out.println("Read Object");
}
}
当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
13.总结
InputStream和OutputStream:字节流的输入输出。--抽象基类!
-- 派生了
FileInputStream和FileOutputStream: 用来对文件进行读写操作;
BufferedInputStream和BufferedOutputStream: 提供了带缓冲的读写;
DataInputStream和DataOutputStream: 提供了读写JAVA基本数据类型的功能;
PipedInputStream和PipedOutputStream:在两个线程中间通信
ObjectInputStream和ObjectOutputStream:完成对象的序列化和反序列化;
Reader和Writer:字符流的输入输出。-- 抽象基类!:1.0中只提供字节流操作;JDK1.1以后新出现字符流;
-- 派生了:
InputStreamRead/OutputStreamWriter:提供了字节流到字符流转换的桥梁!
BufferedReader/Writer: 提高了读写字符流的效率!比较常用
流的链接(Java I/O库的设计原则) -- 功能组合在一起形成功能更加强大的机制!
八. Java图形界面编程
内容:
Java图形界面编程,AWT、布局管理器、事件模型,JFC、Swing编程。应用JBuilder快速开发图形界面程序。
1.AWT
AWT(Abstract Window Toolkit),抽象窗口工具包,SUN公司提供的用于图形界面编程(GUI)的类库。基本的AWT库处理用户界面元素的方法是把这些元素的创建和行为委托给每个目标平台上(Windows、Unix、Macintosh等)的本地GUI工具进行处理。例如:如果我们使用AWT在一个Java窗口中放置一个按钮,那么实际上使用的是一个具有本地外观和感觉的按钮。这样,从理论上来说,我们所编写的图形界面程序能运行在任何平台上,做到了图形界面程序的跨平台运行。
Class Component --JAVA中所有图形界面组件的抽象基类
=》派生:Container -- 容器对象是可以容纳其它组件的组件
=》派生: Window -- 顶层窗口,无边框无菜单
=》派生: Frame. -- 顶层窗口,有一个边框和一个标题
Component.setVisible(boolean b) //为真则显示(只能显示窗口,但不能带到前端)
Window.show() //显示窗口并带到前端!
窗口就是一个容器
e.g.
public static void main(String[] args)
{
Frame. f = new Frame("mybole");
f.setSize(600,400);
f.setLocation(100,100);
f.setBackground(Color.CYAN);
f.show();
Button btn = new Button("winsun");
f.add(btn);
f.show();
}
2.布局管理器
容器里组件的位置和大小是由布局管理器来决定的。容器对布局管理器的特定实例保持一个引用。当容器需要定位一个组件时,它将调用布局管理器来完成。当决定一个组件的大小时,也是如此。
在AWT中,给我们提供了五种布局管理器:
a. BorderLayout ---- Frame. 的缺省布局管理器;分为东西南北中五个方向!
BorderLayout (int 水平间隙, int 水平间隙)
package lesson8;
import java.awt.*;
public class MyFrame
{
public static void main(String[] args)
{
Frame. f = new Frame("mybole");
f.setSize(600,400);
f.setLocation(100,100);
f.setBackground(Color.BLUE);
f.setLayout(new BorderLayout(10,10)); //设置Layout:BorderLayout,设置间隙!
Button btn1 = new Button("North");
Button btn2 = new Button("South");
Button btn3 = new Button("West");
Button btn4 = new Button("East");
Button btn5 = new Button("Center");
f.add(btn1,"North");
f.add(btn2,"South");
f.add(btn3,"West");
f.add(btn4,"East");
f.add(btn5,"Center");
f.show();
}
}
b. FlowLayout //依次摆放每个组件;
f.setLayout(new FlowLayout(FlowLayout.LEFT)); //添加参数,靠左开始;
c. GridLayout -- 网格状摆放
构造函数可无参;
GridLayout(int rows, int cols) -- 参数指定几行几列
Creates a grid layout with the specified number of rows and columns.
CardLayout
e. GridBagLayout -- 五种里最复杂的;平时很少使用;(很少直接使用)
我们可以通过设置空布局管理器,来控制组件的大小和位置。调用setLayout(null)。
在设置空布局管理器后,必须对所有的组件调用setLocation(),setSize()或setBounds(),将它们定位在容器中。
3.如何关闭窗口;
AWT事件模型
Events(事件):描述发生了什么的对象。
Event source(事件源):事件的产生器。
Event handlers(事件处理器):接收事件对象、解释事件对象并处理用户交互的方法。
JDK1.0的事件模型:层次模型;
Frame->Panel->Button -- 产生事件:可以传递给它的容器,返回给上一层;
JDK1.1的事件模型:委托模型 -- 将事件的执行分开
事件监听器:实现了监听器接口的类。一个监听器对象是一个实现了专门的监听器接口的类的实例。-- awt.envent.windowListener
窗口事件必须委托给窗口监听器!
法1:
...
f.addWindowListener(new MyWindowListener());
f.show();
...
class MyWindowListener implements WindowListener
{
public void windowOpened(WindowEvent e)
{
}
public void windowClosing(WindowEvent e)//当窗口关闭时响应
{
System.exit(0);
}
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)
{
}
}
为避免实现所有方法:
法2:JBuilder提供了一个接口实现向导可以直接实现所有方法; 工具栏->wizards
法3:JAVA 提供了一个抽象适配器类WindowAdapter(实现了监听器WindowListener的所有方法,但都是空实现!) -- 继承它并实现需要的方法即可:
适配器类:简化监听器接口的实现(只有一个方法的接口没有适配器类,没有意义,因为无论如何都要实现这一个方法)
class HisWindowListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
法4:匿名内部类 -- 用Window适配器类实现;
//使用了一个匿名的内部类对象
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.show();
小技巧:
CTRL+G --- JBuilder提供的代码生成功能!!
空白处按CTRL+g得到全部函数列表;
如:out CTRL+g 得到一个println语句!
一个容器类只能有一个布局管理器
想用四种布局管理器,用新的容器类Panel--它是Frame的子类;
package lesson8;
import java.awt.*;
import java.awt.event.*;
public class YourFrame. extends Frame
{
private Panel borderPanel;
private Panel flowPanel;
private Panel gridPanel;
private Panel cardPanel;
public YourFrame(String title) //Constructor
{
super(title); //传递基类标题
setSize(600,400);
setLocation(100,100);
setBorderLayoutPanel(); //对4个panel初始化
setFlowLayoutPanel();
setGridLayoutPanel();
setCardLayoutPanel();
setLayout(new GridLayout(2,2)); //框架窗口初始化,两行两列,刚好4个panel
add(borderPanel);
add(flowPanel);
add(gridPanel);
add(cardPanel);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void setBorderLayoutPanel()
{
borderPanel=new Panel();
borderPanel.setLayout(new BorderLayout());
Button btn1=new Button("North");
Button btn2=new Button("South");
Button btn3=new Button("West");
Button btn4=new Button("East");
Button btn5=new Button("Center");
borderPanel.add(btn1,BorderLayout.NORTH);
borderPanel.add(btn2,BorderLayout.SOUTH);
borderPanel.add(btn3,BorderLayout.WEST);
borderPanel.add(btn4,BorderLayout.EAST);
borderPanel.add(btn5,BorderLayout.CENTER);
}
public void setFlowLayoutPanel()
{
flowPanel=new Panel();//Panel()缺省的就是FlowLayoutPanel,所以可以不用设置
Button btn1=new Button("mybole");
btn1.addActionListener(new ActionListener() { //增加按钮响应
public void actionPerformed(ActionEvent e) {
((Button)e.getSource()).setLabel("weixin"); //改变button上的文本!
}
});
Button btn2=new Button("winsun");
flowPanel.add(btn1);
flowPanel.add(btn2);
}
public void setGridLayoutPanel()
{
gridPanel=new Panel();
gridPanel.setLayout(new GridLayout(2,2));
Button btn1=new Button("Button1");
Button btn2=new Button("Button2");
Button btn3=new Button("Button3");
Button btn4=new Button("Button4");
gridPanel.add(btn1);
gridPanel.add(btn2);
gridPanel.add(btn3);
gridPanel.add(btn4);
}
public void setCardLayoutPanel()
{
//匿名内部类要访问方法中的局部变量,那么这个变量必须为final
final CardLayout cl=new CardLayout();
cardPanel=new Panel();
cardPanel.setLayout(cl);
Button btn1=new Button("黑桃A");
Button btn2=new Button("红桃K");
ActionListener al=new ActionListener() //ActionListener是个接口,所以不能实例化,直接实现
{
public void actionPerformed(ActionEvent e)
{
cl.next(cardPanel); //内部类访问cl变量,它必须定义为final的!
}
};
btn1.addActionListener(al); //注册监听器
btn2.addActionListener(al); //可以使用同一个
cardPanel.add(btn1,"1");//一定要加约束字符串(可任意)
cardPanel.add(btn2,"2");
}
public static void main(String[] args) throws HeadlessException
{
YourFrame. yf = new YourFrame("http://www.mybole.com.cn");
yf.show();
}
}
4.在AWT中创建一个菜单需要创建:
MenuBar-》Menu-》MenuItem
SetMenubar()
package lesson8;
import java.awt.*;
public class HisFrame
{
public static void main(String[] args)
{
Frame. f=new Frame("http://www.mybole.com.cn");
f.setSize(600,400);
f.setLocation(100,100);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
MenuBar mb=new MenuBar();
Menu m1=new Menu("File");
Menu m2=new Menu("Edit");
MenuItem mi1=new MenuItem("New");
MenuItem mi2=new MenuItem("Open");
MenuItem mi3=new MenuItem("Save");
MenuItem mi4=new MenuItem("Exit");
MenuItem mi5=new MenuItem("Copy");
MenuItem mi6=new MenuItem("Paste");
m1.add(mi1);
m1.add(mi2);
m1.add(mi3);
m1.add(mi4);
m2.add(mi5);
m2.add(mi6);
mb.add(m1);
mb.add(m2);
f.setMenuBar(mb);
f.show();
}
}
a.实现功能打开并显示一个文件:
MenuItem mi2=new MenuItem("Open");
mi2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
FileDialog fd=new FileDialog(f,"Weixin Open File Dialog",
FileDialog.LOAD); //(父Frame,title,model)
fd.show();
String strFile=fd.getDirectory()+fd.getFile(); //路径+文件名
if(strFile!=null)
{
try {
FileInputStream fis=new FileInputStream(strFile);
byte[] buf=new byte[10*1024];
int len=fis.read(buf);
tf.append(new String(buf,0,len));
fis.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
创建对话框用FileDialog类,需指定一个父Frame;
显示文本的方法:
1.TextField --- 可以指定初始文本,但是只能显示单行文本
2.TextArea -- 多行文本
b.退出
MenuItem mi4=new MenuItem("Exit");
mi4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
其它常用组件,看例子代码即可:
Chois -- 下拉列表框
Checkbox -- 复选框
Label -- 标签
5.Swing(Swing中的类都以J开头)
JAVA基础类:
JFC(Java Foundation Classes):Java基础类,是关于GUI组件和服务的完整集合,主要包含5个API:AWT、Java2D、Accessibility、Drag & Drop、Swing。JFC提供了帮助开发人员设计复杂应用程序的一整套应用程序开发包。
Java2D是一套图形API,它为Java应用程序提供了一套高级的有关二维(2D)图形图像处理的类。Java2D API扩展了java.awt和java.awt.image类,并提供了丰富的绘图风格,定义了复杂图形的机制和精心调节绘制过程的方法和类。这些API使得独立于平台的图形应用程序的开发更加简便。
Accessibility API提供了一套高级工具,用以辅助开发使用非传统输入和输出的应用程序。它提供了一个辅助的技术接口,如:屏幕阅读器,屏幕放大器,听觉文本阅读器(语音处理)等等。
Drag & Drop技术提供了Java和本地应用程序之间的互操作性,用来在Java应用程序和不支持Java技术的应用程序之间交换数据。
JFC模块的重点在Swing。Swing用来进行基于窗口的应用程序开发,它提供了一套丰富的组件和工作框架,以指定GUI如何独立于平台地展现其视觉效果。
Swing的所有元素都是基于JComponent的; -- 由它派生!
包javax.swing
所有swing元素都是J开头:JButton,JCheckBox
缺省的布局管理器为BorderLayout
6.可以用图形界面生成器生成一个框架;(Swing)
用Application向导生成appli并在图形界面手动设计界面
AWT.event.*; 事件
MouseEvent类的方法:
isPopupTrigger()是否是弹出事件的触发事件;
getComponent()获取事件发生的父组件;
getX(),getY() 获取鼠标当前位置;
a.鼠标右键弹出菜单:
void contentPane_mouseReleased(MouseEvent e) //鼠标键松开事件
{
if(e.isPopupTrigger()) //判断是否为右键;
{
jPopupMenu1.show(e.getComponent(), e.getX(), e.getY());
}
}
b.右键菜单show增加事件响应:
void jMenuItem3_actionPerformed(ActionEvent e) //弹出消息框
{
JOptionPane.showMessageDialog(null,"show"); //Swing类方法 -- JOptionPane.showMessageDialog
}
static void showMessageDialog(Component parentComponent, Object message)
Brings up an information-message dialog titled "Message".
图形界面的编程不是java的强项;而且运行速度较慢!
awt和swing用法不用强记,会用就
5行,使用时利用帮助文档和相关书籍现学现卖就可以了!