7. 图形编程 - core java
Java1.0 包含一个基本的GUI类库. 叫抽象窗口工具箱(AWT). 它是把具体的图形界面交给不同平台去显式. 在1996年. Netscape开发了一个和AWT工作方式完全不同的GUI库. 叫英特网基础类库(IFC). 它把用户 使用Swing库就真正做到了一次编写到处运行. 它虽然比AWT慢一些.但现在的机器跑起来已经不成问题. Java中的顶层窗口(即不是包含在其它窗口中)被称作框架. 框架是一种容器. 可以容纳其它用户界面组件(如按钮等). 它的继承层次为: 创建框架的代码如下: class SimpleFrame extends JFrame { 其中javax是个Java1.1扩展包. 而不是核心包. 要得到屏幕大小用Toolket类的静态方法getDefaultToolket(). 如下: 给框架指定一个图标: 给框架定位. 可以指定框架的位置和大小(框架的缺省大小为0*0). 用: java.awt.Window(窗口.即Frame类的父类)的常用方法: java.awt.Frame类的常用方法: java.awt.Toolkit类的常用方法: 框架JFrame类实际上是组件的容器(可以容纳其它组件). 面板JPanel是一个能在其上绘制的表面. 同时也是容器(可以容纳其它组件). 注意: 和AWT中不同. Swing中没有了专门的画布(Canvas)类. 而且绘制也不再使用paint方法了. 从SDK2.0开始. J2SE包含了Java 2D库. 绘制形状时. 需要先创建一个实现了Shape接口的类的对象. 例如: java.awt.Color类提供了13个标准颜色的常量值如 Color.RED 等 要定制RGB颜色值. 用Color的构造器: 要使颜色变得更亮一点或更暗一点用 brighter() 或 darker(). 要用红色填充一个矩形用: 字体就免了. 用的时候再看. 绘制字符串用: 要显示图像. 先要读取图像. 然后用Graphics的drawImage()方法绘制: 另外.如果要复制图像(例如用image铺满整个面板就需要复制图像). 用: 在Swing中的组件的绘制都是双缓冲的. 但在AWT中不是. 在AWT中要避免显示时的抖动. 要自己想办法: 注意g.drawImage()函数. 它的第四个参数是一个观察者.
7.1 Swing概述
但由于不同的平台有差异.所以用这个库写的程序只能用这些平台的公共部分. 所以界面也不漂亮.还有bug.
界面元素是直接绘制在空白窗口上. 所以这个库写的程序在各个平台上看起来都一样. Sun和Netscape合作
完善了这种方法. 就是Swing库. 它已是Java基础类(JFC)的一部分. 但它的事件处理模型仍使用Java 1.1
的事件处理模型.
所以Swing是用户界面的未来. 应该在程序中使用它.
7.2 创建框架
在AWT库中对应Frame类. 在Swing中对应JFrame类. JFrame从Frame扩展而来.
它是少数几个不绘制在画布上的Swing组件之一. 所以它的修饰部件(按钮.标题栏.图标等)仍是通过用户的
窗口系统绘制.而不是Swing绘制.
Object
|-Component
|-Container
|-JComponent
| |-JPanel
|
|-Widow
|-Frame
|-JFrame
import javax.swing.*;
public class SimpleFrameTest {
public static void main(String[] args) {
SimpleFrame frame = new SimpleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //指定关闭框架时的动作.
frame.show();
}
}
public SimpleFrame() {
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); //缺省时框架大小是0*0
}
public static final int DEFAULT_WIDTH = 300;
public static final int DEFAULT_HEIGHT = 200;
}
但是在Java2平台上Swing包已经是核心包而不是扩展包了. 只是为了兼容性javax的名字保留了下来.
7.3 给框架定位
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
int screenWidth = screenSize.width;
int screenHeight = screenSize.height;
Image img = kit.getImage("icon.gif"); //先用Toolkit对象载入图标.
frm.setIconimage(img); //为框架设置一个图标.
public void setBounds(Rectangle r) //同时指定位置和大小
public void setLocation(int x, int y) //指定位置. 坐标为父级坐标系.
要把框架设置为最大尺寸.用:
frm.setExtendedState(Frame.MAXIMIZED_BOTH);
这时Frame类中的方法: public void setExtendedState(int state)
java.awt.Component(组件) 类的一些常用方法:
见笔记 19. java.awt 部件 - Java2详解
void toFront() //把该窗口显示到其它窗口之前.
void toBack() //把该窗口
void setResizeable(boolean b) //设置是否允许用户缩放框架
void setTitle(String) //设置框架的标题栏
void setIconImage(Image) //设置框架的图标
void setUndecorated(boolean) //设置是否清除对窗口的修饰
boolean isUndecorated() //返回窗口是否被修饰
int getExtendedState() //获取窗口的状态(是否最大化等).
void setExtendedState(int state) //设置窗口的状态.
static Toolkit getDefaultToolkit() //返回默认的Toolkit
Dimension getScreenSize() //获取屏幕大小
Image getImage(String filename) //加载filename所指定的图像.
7.4 在面板中显示信息
JFrame中安排了4个窗格. 其中根窗格.布局窗格.透明窗格和内容窗格. 向框架添加组件就是把组件添加到
内容窗格上. 如:
Container contentPane = frm.getContenPane(); //取JFrame的内容窗格对象
Component c = .... ;
contentPane.add(c);
如果框架中只显示一个Swing组件可以用:
JComponent c = .........;
frm.setContentPane(c);
要在JPanel中进行绘制. 需要定义一个类让它扩展JPanel类并覆盖其paintComponent方法:
public void paintComponent(Graphics g) { } //覆盖时其中应调用supper.paintComponent
这样当窗口需要重绘的时候事件处理器会通知组件并执行其paintComponent方法.
但在需要强制重绘屏幕时.你自己不应该调用该方法. 而应该调用repaint方法. repaint会"尽快的"重绘.
而且Swing组件使用缓冲进行无抖动绘制.
7.5 2D图形
使用Java 2D库要先得到 Graphics2D类的对象. Graphics2D是Graphics的子类.
JCompent的paintComponent方法如下:
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g; //如果使用的是启用了Java 2D库的SDK. 则参数g实际上
//就是Graphics2D对象.
}
Line2D(直线) Rectangle2D(矩形) Ellipse2D(椭圆)
都是实现了Shape接口的类. 绘制时如下:
Rectangle2D rect = ...;
g2.draw(rect);
7.6 颜色
例如把组件的背景色设置为红色:
p.setBackground(Color.RED);
Color(int r, int g, int b)
使用如
Graphics g = ..
g.setColor(new Color(0,128,128)); //接着的绘制使用该颜色.
Rectangle2D r = ....
g2.setPaint(Color.RED);
g2.fill(r); //用上边指定的红色填充
7.7 文本和字体
Graphics类的 void drawString(String str, int x, int y)
Graphics2D类的 void drawString(String str, float x, float y)
7.8 图像
读取本地存储的图像.用:
String filename = "...";
Image image = ImageIO.read(new File(filename));
读取网络上的图像文件用:
String filename = "...";
Image image = ImageIO.read(new URL(urlname));
若图像不存在. 则抛出IOException异常.
g.drawImage(image, x, y, null);
g.copy(x, y, imageWidth, imageHeight, x1, x2) //把从(x,y)开始的图像复制到新位置(x1,y1)
Image buffered_image = createImage(width, height);
Graphics bg = buffered_image.getGraphics();
//... //将图像先绘制在缓冲(buffered_image)上.
g.drawImage(buffered_image, 0, 0, null); //再将缓冲区复制到屏幕.
bg.dispose();
buffered_image.flush();
因为当加载图像时. 图像可能在网络上. 加载比较慢. 为了在加载图像的同时让程序继续向下运行. Java
在这里使用的是多线程的机制来并发运行. 这种机制允许我们跟踪图像的获取过程. 所以当图像的大小确定时.
当新的图像块变得可用时. 图像最终加载完毕时. 我们都会得到通知.
其中drawImage()的第四个参数就是我们指定的接收通知的ImageObserver对象.