java指南之使用图形:使用原始图形
2008-01-05 09:20:41 来源:WEB开发网核心提示:使用原始图形 接下来的几页提供产生原始图形和文本的细节, 绘制外形这页告诉你如何绘制诸如直线、矩形、椭圆、弧形和多边形等外形,java指南之使用图形:使用原始图形, 使用文本这页告诉你使用Graphics对象的drawString方法绘制文本,它同时告诉你如何使用Font 和 FontMetrics 对象得到字体大小的
使用原始图形
接下来的几页提供产生原始图形和文本的细节。
绘制外形
这页告诉你如何绘制诸如直线、矩形、椭圆、弧形和多边形等外形。
使用文本
这页告诉你使用Graphics对象的drawString方法绘制文本。它同时告诉你如何使用Font 和 FontMetrics 对象得到字体大小的信息。
绘制外形
Graphics 类定义了绘制下列外形的方法:
直线 (drawLine)
矩形 (drawRect 和 fillRect)
凸起的和下凹的矩形 (draw3DRect 和 fill3DRect)
圆边的矩形 (drawRoundRect 和fillRoundRect)
椭圆 (drawOval 和 fillOval)
弧线 (drawArc 和 fillArc)
多边形 (drawPolygon, drawPolyline, 和 fillPolygon)
下面是一个绘制矩形轮廓的例子:
g.drawRect(x, y, rectWidth - 1, rectHeight - 1);
下面是一个绘制填充矩形的例子:
g.fillRect(x, y, rectWidth, rectHeight);
注重,对于 drawRect 方法,你指定的宽度和高度必须比期望的大小至少小1个象素。这是因为绘图系统在指定的矩形外绘制直线而不是在指定的矩形内。同样的,这个规则也适用于其它的drawXxx 方法,例如draw3DRect。另一方面,对于fillXxx 方法methods,你指定的高度和宽度和期望的应该同样大。
--------------------------------------------------------------------------------
javaTM 2 注重: 假如你正使用Java 2 (JDKTM 1.2),你可以使用新的JavaTM 2D API,它可以让你创建任何几何外形并且指定直线的式样,尺寸和奇异的填充模式。要了解如何利用这些功能,参考 2D 图形 教材。非凡地,参考 绘制和填充原始图形 和 外形 课程,它们介绍了在范例 2: 外形样本里面的程序的一个Java 2D 实现。
--------------------------------------------------------------------------------
范例 1: 简单的矩形绘制
下面是一个和在坐标系统里面的CoordinatesDemo几乎一样的图片。和CoordinatesDemo相似,这个程序在用户点击的地方绘制一个矩形。然而,这个程序的矩形更大而且用黄色填充。下面是程序的GUI截图:
这个图片是该applet的GUI。要运行那个applet,单击图片。该applet将在一个新浏览窗口显示。
这个程序由两个组件构成。最大的一个是一个名字为RectangleArea的类实现的自定义组件。它绘制倾斜边界和它里面的所有东西,包括黄色矩形。另一个组件是出现在GUI底部的一个标签,就在自定义组件下面。标签描述程序的当前状态。
你可以在 RectangleDemo.java找到程序的代码。下面是自定义组件中和绘图相关的代码:
class RectangleArea extends JPanel {
...
int rectWidth = 50;
int rectHeight = 50;
...
public RectangleArea(...) {
...
Border raisedBevel = BorderFactory.createRaisedBevelBorder();
Border loweredBevel = BorderFactory.createLoweredBevelBorder();
Border compound = BorderFactory.createCompoundBorder
(raisedBevel, loweredBevel);
setBorder(compound);
...
}
...
public void paintComponent(Graphics g) {
super.paintComponent(g); //绘制背景
//在用户选择的地方绘制一个填充矩形。
if (point != null) {
g.drawRect(point.x, point.y,
rectWidth - 1, rectHeight - 1);
g.setColor(Color.yellow);
g.fillRect(point.x + 1, point.y + 1,
rectWidth - 2, rectHeight - 2);
controller.updateLabel(point);
}
}
}
组件的paintComponent 方法使用fillRect绘制一个边长为50的矩形的轮廓,并用边长为48的黄色矩形填充。注重指定给drawRect 和 fillRect的参数不同。
--------------------------------------------------------------------------------
注重: 指定x, y, 高度或者宽度值为负值或者比绘图区还大是完全合法的绘图区外的值没有什么影响,因为它们被剪切到绘图区。你仅仅不能看见部分外形。外形的负值的高度和宽度导致的结果是根本没有绘制。
--------------------------------------------------------------------------------
关于这个例子的更多信息,参考坐标系统,它描述了RectangleDemo的基础:CoordinatesDemo。
范例 2: 外形样本
ShapesDemo演示了使用JDK 1.1 和 Java 2 API都支持的所有可以绘制和填充的外形。下面是它的GUI的截图:
这个图片是该applet的GUI。要运行那个applet,单击图片。该applet将在一个新浏览窗口显示。
--------------------------------------------------------------------------------
注重: 除非缺省的字体很小,否则ShapesDemo显示的一些字符串可能和其它的字符串重叠。得到Font的信息: FontMetrics示范了如何修正这个问题。
--------------------------------------------------------------------------------
你可以在 ShapesDemo.java找到完整的源代码。下面的片断仅仅是绘制几何图形的代码,黑体的行是实际的绘图方法的调用。rectHeight和 rectWidth 变量指定包含被绘制外形的矩形的象素大小。 x和y 变量对每个外形都改变,因此外形不会彼此覆盖。 bg 和 fg 变量是 Color 对象,它们分别指定组件的背景色和前景色。
Color fg3D = Color.lightGray;
...
// drawLine(x1, y1, x2, y2)
g.drawLine(x, y+rectHeight-1, x + rectWidth, y);
...
// drawRect(x, y, w, h)
g.drawRect(x, y, rectWidth, rectHeight);
...
// draw3DRect(x, y, w, h, raised)
g.setColor(fg3D);
g.draw3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
...
// drawRoundRect(x, y, w, h, arcw, arch)
g.drawRoundRect(x, y, rectWidth, rectHeight, 10, 10);
...
// drawOval(x, y, w, h)
g.drawOval(x, y, rectWidth, rectHeight);
...
// drawArc(x, y, w, h, startAngle, arcAngle)
g.drawArc(x, y, rectWidth, rectHeight, 90, 135);
...
// drawPolygon(XPoints, yPoints, numPoints)
int x1Points[] = {x, x+rectWidth, x, x+rectWidth};
int y1Points[] = {y, y+rectHeight, y+rectHeight, y};
g.drawPolygon(x1Points, y1Points, x1Points.length);
...
// drawPolyline(xPoints, yPoints, numPoints)
// 注重: drawPolygon 会闭合多边形。
int x2Points[] = {x, x+rectWidth, x, x+rectWidth};
int y2Points[] = {y, y+rectHeight, y+rectHeight, y};
g.drawPolyline(x2Points, y2Points, x2Points.length);
...
// fillRect(x, y, w, h)
g.fillRect(x, y, rectWidth, rectHeight);
...
// fill3DRect(x, y, w, h, raised)
g.setColor(fg3D);
g.fill3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
...
// fillRoundRect(x, y, w, h, arcw, arch)
g.fillRoundRect(x, y, rectWidth, rectHeight, 10, 10);
...
// fillOval(x, y, w, h)
g.fillOval(x, y, rectWidth, rectHeight);
...
// fillArc(x, y, w, h, startAngle, arcAngle)
g.fillArc(x, y, rectWidth, rectHeight, 90, 135);
...
// fillPolygon(xPoints, yPoints, numPoints)
int x3Points[] = {x, x+rectWidth, x, x+rectWidth};
int y3Points[] = {y, y+rectHeight, y+rectHeight, y};
g.fillPolygon(x3Points, y3Points, x3Points.length);
...
使用文本
对于原始的文本的支持是在AWT的 Graphics, Font,, 和 FontMetrics 类上展开的。当然,你也可以通过使用文本绘制组件来给自己减少很多麻烦--例如 标签 或者 文本组件。
--------------------------------------------------------------------------------
JavaTM 2 注重: 假如你正使用Java 2 (JDKTM 1.2),你可以使用JavaTM 2D API中的丰富特性的文本支持。参考2D 图形教材中的 2D 图形 一节得到更多信息。然而,我们仍然推荐避免自己绘制文本而是使用标准的Swing 组件。
--------------------------------------------------------------------------------
绘制文本
Graphics 类提供三个绘制文本的方法: drawBytes, drawChars, 和 drawString。下面是向屏幕上绘制字符串的一个例子:
g.drawString("Hello World!", x, y);
对于文本绘制方法,x 和y是指定文本的左下角的位置的整数。更精确的讲,y 坐标指定文本的基线(baseline) -- 大多字母停留的线 --它没有包含像"y"这样的下行字母(descenders) 的尾部的空间。确定y值足够大以满足文本的垂直空间的要求,但是要足够小以确保对下行字母也有足够的空间。
下面是一个显示基线的图片,也显示了顶线和底线。你会在稍后了解更多关于顶线和底线的知识。
这是一个简单的applet的截图,它说明了假如你不注重你的文本的位置会发生什么:
这个图片是该applet的GUI。要运行那个applet,单击图片。该applet将在一个新浏览窗口显示。
字符串顶被截去了,因为它的y参数是5,字符串的基线以上只有5个象素的空间 --对于大多字体这是不够的。中间的字符串可能显示得很好,除非你使用很大的字体。下面的字符串的大多显示得很好,除了下行字母。下面的字符串的所有下行字母被截去,因为显示这个字符串的代码没有为它们预备足够的空间。你可以在 TextXY.java得到完整的代码。
--------------------------------------------------------------------------------
注重: 文本绘制方法对x 和 y的解释和外形绘制方法的不同。当绘制一个外形(例如矩形)时, x 和 y指定外形的范围矩形的左上角而不是左下角。
--------------------------------------------------------------------------------
得到Font的信息: FontMetrics
The shape-painting example from 范例 2: 外形样本中的外形绘制的范例可以通过选择一个比通常缺省的字体小的字体来进行改进。下面的例子进行了这个工作并且扩大了外形以占据由于字体的减小而释放的空间。下面是改进的applet的截图:
--------------------------------------------------------------------------------
这个图片是该applet的GUI。要运行那个applet,单击图片。该applet将在一个新浏览窗口显示。
--------------------------------------------------------------------------------
你可以在 FontDemo.java得到全部代码。 范例通过使用一个FontMetrics对象得到字体的大小的具体情况而选择合适的字体。例如下面的循环确保applet ("drawRoundRect")中显示的最大的字符串适合为它分配的空间。
boolean fontFits = false;
Font currentFont = biggestFont;
FontMetrics currentMetrics = getFontMetrics(currentFont);
int size = currentFont.getSize();
String name = currentFont.getName();
int style = currentFont.getStyle();
while (!fontFits) {
if ( (currentMetrics.getHeight() <= maxCharHeight)
&& (currentMetrics.stringWidth(longString)
<= xSpace)) {
fontFits = true;
} else {
if (size <= minFontSize) {
fontFits = true;
} else {
currentFont = new Font(name, style, --size);
currentMetrics = getFontMetrics(currentFont);
}
}
上面的范例代码使用了Graphics的 getFont, setFont, 和 getFontMetrics方法得到当前和设置当前字体以及得到对应字体的FontMetrics对象。从FontMetrics的 getHeight 和 stringWidth(String) 方法中,代码得到字体的垂直和水平尺寸。(译者注:stringWidth(String)得到的应该是参数指定的字符串在使用对应字体时的总的水平长度。)
下面的图片显示了一个FontMetrics对象可以提供的一些有关字体尺寸的信息。
下面是FontMetrics对象的返回字体的垂直大小的信息的方法的一个概要:
int getAscent(), int getMaxAscent()
getAscent 方法返回顶线和基线之间的象素大小。通常,顶线代表大写字母的典型高度。特定的,字体的设计者选择的上行和下行值用来表示恰当地文本“外貌”,或者说墨迹的密度,因此文本就可以像设计者期望的那样显示。上行值通常为几乎所有的字体中的字符提供足够的空间,除了大写字母的accents。getMaxAscent方法计算这些异常高大的字符。
int getDescent(), int getMaxDescent()
getDescent 方法返回基线和底线之间的象素大小。对应大多字体,字体中的字符的最低点都在底线以上。可以在万一的情况下,你可以使用getMaxDescent 方法得到能保证包容所有字符的距离。
int getHeight()
返回两个文本的基线间的象素大小。注重这包括行间距。
int getLeading()
得到两行文本间的暗示的距离的象素大小。明确的说,行间距是上一行的的底线和下一行的顶线间的距离。顺便说一下,leading 的发音为 LEDDing。
注重字体的大小 (Font的getSize方法返回的值)是一个抽象的尺寸。理论上,它对应上行值和下行值的和。然而,实际上,字体的设计者才最终决定一个"12 point"的字体的大小。 例如,12点Times字体通常比12点Helvetica字体稍微短一些。通常情况下,字体大小是以点来衡量的,它大约是1/72英寸。
下面的列表显示了FontMetrics对象提供的返回字体的字符的水平大小的方法。这些方法考虑了每个字符四周的空间。更确切的讲,每个方法返回的 不是某个特定字符(或者多个字符)占据的象素大小,而是 the number of pixels taken up by a particular character (or characters), but the number of pixels by which the current point will be advanced when that character (or characters) is shown. 我们称它为advance width以和字符或者文本的宽度相区分。
int getMaxAdvance()
字体中的最宽的字符的advance width(以象素为单位)。
int bytesWidth(byte[], int, int)
由字节数组表示的文本的advance width。第一个整型参数指定数组中的开始偏移量。第二个整型参数指定数组中最后一个需要检查的位置。
int charWidth(int), int charWidth(char)
指定字符的advance width。
int charsWidth(char[], int, int)
由指定的字符数组表示的文本的advance width。
int stringWidth(String)
指定字符串的advance width。
int[] getWidths()
字体中的前256个字符的advance width。
更多精彩
赞助商链接