1、图形坐标系
- 小圆代表坐标,正方形代表像素,坐标位于像素之间。
- 对于输出设备来讲,坐标位于像素之间。绘制形状轮廓的操作,例如Graphics .drawRect(),用一支画笔沿着一个坐标路径移动,画笔对坐标路径下方或右方的像素进行绘画。
- 画笔的尺寸通常是一个像素高和一个像素宽。
2、applet绘图例子
import java.applet.Applet;
import java.awt.*;
public class demo03 extends Applet {
public void paint(Graphics g) {
g.drawRect(2,2,4,4);
}
}
- 乍一看该applet 程序,我们可能会认为其显示的是由drawRect (2,2,4,4)中的参数在像素坐标中定义的一个矩形框。实际上,其显示的结果如上所示,参数指定图形笔的坐标路径。当绘制矩形时,坐标路径开始点是(2,2),而后面的两个4则分别代表坐标增长的宽度和高度,所绘制的坐标路径如下所示:
(2,2)→(6,2)→(6,6)→ (2,6)→(2,2) - 图形笔移动的路径,从起点开始,向右移动到第二个点,然后向下移动到第三个点,向左绘制至第四个点,最后回到起点。当画笔沿路径移动时,其像素颜色来自画笔,而画笔所采用的颜色则是通过调用Graphics. setColor ( Color)来指定的。
- 画笔是沿上面所讲坐标路径绘制矩形的,所以g.drawRect(2,2,4,4)实际上绘制出来的矩形的宽度和高度是5个像素单位,而不是4个像素单位。
3、绘制构件四周边界
因为绘制出的矩形将比构件宽一个像素也高一个像素。结果,右边缘和底边缘边界将被绘制在构件的外面,因此将看不到该部分。
常用的解决方法是,从宽度和高度中都减去一个像素单位,如下所示:
public void paint (Graphics g) {
Dimension size = getSize();
g.drawRect(0,0,size.width-1,size.height-1);
}
4、填充形状
import java.applet.Applet;
import java.awt.*;
public class demo03 extends Applet {
public void paint(Graphics g) {
g.fillRect(2,2,4,4);
}
}
- 传递给fillRect ()的参数指定的坐标路径与在前面调用drawRect()时指定的坐标路径相同。但是,填充外形的Graphics方法将填充路径的内部,所以填充的矩形是4个像素宽和4个像素高,如上图所示。
- 注意形状填充和形状轮廓容易引起混淆。另外,传递给drawRect()和 fillRect ()的参数定义的是坐标路径,但是经常被错误地描述为以像素为单位的矩形的边界。所有绘制轮廓和填充形状的Graphics方法的主要差异是尺寸上的差异。
5、Graphics引用
注意:
从Component、Image和 PrintJob中的getGraphics ()方法返回的Graphics 引用并不是一个对Graphics引用的引用,而是返回一个初始Graphics 的副本。
5.1 Graphics 的副本
import java.applet.Applet;
import java.awt.*;
public class demo03 extends Applet {
public void paint(Graphics g) {
setForeground(Color.yellow);
g.drawLine(0,0,getSize().width - 1,getSize().height - 1);
}
}
- 画线时使用的是applet默认的前景颜色,该颜色在Windows 95中是黑色。
- 在 applet初始着色后,紧接着调用paint ()方法,结果得到黄色的线条。
- 调用Component . setForeground (),改变构件中 Craphics 的当前颜色,该颜色被改变成黄色。
- SetFroeground ()影响applet的Graphics,但并不影响传递给 paint ()的Graphics的副本。因此,当第一次调用paint ()时,线条的颜色并没有变成黄色。当调用drawLine()时,传递给paint ()的 Grahpics和实际的 Grphics并不同步。
- 后来调用paint()时,传递给paint ()的是 applet 的Graphics的一个新副本,因此setFore-gound ()的调用结果可以将applet的Graphics的当前颜色改变成黄色。
import java.applet.Applet;
import java.awt.*;
public class demo03 extends Applet {
public void paint(Graphics g) {
setForeground(Color.yellow);
Graphics copy = null;
try {
copy = getGraphics();
copy.drawLine(0,0,getSize().width - 1, getSize().height - 1);
} catch (Exception e) {
e.printStackTrace();
} finally {
copy.dispose(); //处置此图形上下文并释放它正在使用的任何系统资源
}
}
}
- 传递给paint ( )的 Graphics将被忽略掉,通过调用getGraphics ()方法得到一个新的Graphics,应用这个新的Graphics绘制直线。
- 因为在调用setForegroud ()之后获取Grpahics,所以Graphics当前的颜色,也就是线条的颜色,将变成黄色。
- 注意到在paint ()方法返回之前调用Graphics.dispose ()方法,处理由Component.getGraphics ()返回的Graphics,而传递给paint ()的Graphics却没有被处理。
5.2 Graphics引用的寿命
- 除了引用副本外,传递给 paint (和update ()等方法的Graphics引用仅仅在方法的执行过程中才有效。一旦方法返回,引用将不再有效。
- 下面给出的程序范例,在该applet程序中,想重用最初传递给paint ()的Graphics引用。直线将在第一次调用paint ()时画出,但是对paint ()的后续访问将导致直线在一个无效的Graphics内绘制,因此直线不再显示(通过调整窗口大小可以强行重绘该applet)
- Graphics引用方法调用结束后,自动销毁。所以第一次以后的oldg指向的地址对象已经被销毁,所以变成无效Graphics
import java.applet.Applet;
import java.awt.*;
public class demo03 extends Applet {
private Graphics oldg;
private boolean first = true;
public void paint(Graphics g) {
if(first) {
oldg = g;
first = false;
}
oldg.drawLine(0,0,getSize().width - 1, getSize().height - 1);
}
}
5.3 处理Graphics
public void demo() {
Graphics g = getGraphics();
if(g != null) {
try {
//code
} cache() {
//code
} finally {
g.dispose()
}
}
}
- 如果最后不调用dispose(),那么将会导致窗口系统用完图形环境
- 这里对g做null检测是因为:如果在构件的同位体之前调用getGraphics(),则会返回null
Graphics表示本地图形环境,是一个典型的有限资源,所以一定要使用dispose释放资源。但传递Graphics引用的方法一般不需要手动调用方法处理。