Java读书笔记11 图形程序——颜色 字体 图像
《JAVA 2核心技术 卷Ⅰ:基础知识》第七章:图形程序设计,读书笔记第二部分(7.6-7.8)。
主要内容包括:颜色、为文本设定特殊字体、图像。
一.颜色
Graphics2D类的setPaint方法可以为图形环境上的所有后续绘制操作选择颜色。
Color类用于定义颜色,在java.awt.Color中提供了13个预定义的常量,分别表示13种标准颜色。
(JDK 1.4之前的版本颜色名字是用小写,后来采用大写,为了兼容,就大小写都保留了。)
例如:
g2.setPaint(Color.RED); //绘制操作
可以通过提供RGB三色成分来创建一个Color对象,三种颜色成分都是用0~255之间的整型数值表示。
例如:
g2.setPaint(new Color(0,128,128)); //绘制操作
如果使用Graphics对象,而不是Graphics2D对象,就要使用setColor方法设置颜色。
要想设置背景颜色,使用Component类中的setBackground方法。
setForeground方法用来设定在组件上进行绘制时使用的默认颜色。
Color类中的brighter()方法和darker()方法可以分别加亮或者变暗当前的颜色。连续调用可以使效果增强。如:c.brighter().brighter()
SystemColor类中预定义了很多颜色的名字,在这个类中的常量,封装了用户系统的各个元素的颜色。
如SystemColor.window为用户桌面上所有窗口使用的默认颜色。当希望让绘制的用户界面元素与用户桌面上已经存在的其他元素颜色匹配时,使用SystemColor类中的颜色非常有用。
用颜色填充图形,只需要将draw替换为fill就行了。
如:
Rectangle2D rect=…;
g2.setPaint(Color.RED);
g2.fill(rect);
二.为文本设定特殊的字体
计算机上的字体
要想知道某台特定计算机上所允许使用的字体,就需要调用GraphicsEnvironment类中的getAvailableFontFamilyNames方法。这个方法将返回一个字符型数组,其中包含了所有可用的字体名。
GraphicsEnvironment类描述了用户系统的图形环境,为了得到这个类的对象,需要调用静态的getLocalGraphicsEnvironment方法。
下面这个程序将打印出系统上的所有字体名:
/** @version 1.11 2004-06-05 @author Cay Horstmann */ import java.awt.*; public class ListFonts { public static void main(String[] args) { String[] fontNames = GraphicsEnvironment .getLocalGraphicsEnvironment() .getAvailableFontFamilyNames(); for (String fontName : fontNames) System.out.println(fontName); } }
逻辑字体
为了创建一个公共基准,AWT定义了五个逻辑字体名:
SansSerif
Serif
Monospaced
Dialog
DialogInput
这些字体将被映射到客户机上的实际字体。例如,在Windows系统中,SansSerif将被映射到Arial上。
字体映射定义在Java安装的jre/lib子目录中的fontconfig.properties文件中。
在Java以前的版本中,将Helvetica、TimesRoman、Courier、ZapfDingbats作为逻辑字体名,为了向后兼容,现在仍然将这些字体名按照逻辑字体名对待。
使用字体
要想使用某种字体绘制字符,必须首先使用字体名、字体风格、字体大小来创建一个Font类对象,例如:
Font helvb14=new Font(“Helvetica”, Font.BOLD, 14);
第二个参数可以指定字体的风格:常规、加粗、斜体或加粗斜体。
Font.PLAIN、Font.BOLD、Font.ITALIC、Font.BOLD+Font.ITALIC
setFont函数为图形环境选择一种字体。这种字体将被应用于后续的文本绘制操作中。
下面这段代码将使用系统上14号加粗的标准sans serif字体显示字符串“Hello World”:
Font sansbold14= new Font("SansSerif",Font.BOLD,14); g2.setFont(sansbold14); String message = "Hello World!"; g2.drawString(message,75,100);
字符测量
需要精确设定字符串绘制位置时,需要知道字符串占据的宽和高的像素数量,这两个值取决于下面三个因素:
1.使用的字体(如前面所提到的14号加粗的标准sans serif字体)。
2.字符串(如"Hello World!")。
3.绘制字体的设备(如用户屏幕)。
要想得到屏幕设备字体属性的描述对象,需要调用Graphics2D类中的getFontRenderContext方法。它返回一个FontRenderContext类对象。可以直接将这个对象传递给Font类的getStringBounds方法:
FontRenderContext context = g2.getFontRenderContext();
Rectangle2D bounds = f.getStringBounds(message, context);
getStringBounds方法将返回包围字符串的矩形。
getStringBounds方法返回的矩形宽度是字符串水平方向的宽度。矩形的高度是上坡度、下坡度、行间距的总和。该矩形始于字符串的基线,矩形顶部的y坐标为负值。
可以采用下面的方法获得字符串的宽度、高度和上坡度:
double stringWidth = bounds.getWidth(); double stringHeight = bounds.getHeight(); double ascent = -bounds.getY();
如果需要知道下坡度或行间距,可以使用Font类的getLineMetrics方法。这个方法将返回一个LineMetrics类对象,获得下坡度和行间距的方法是:
LineMetrics metrics = f.getLineMetrics(message,context); float descent = metrics.getDescent(); float leading = metrics.getLeading();
程序代码
下面给出的程序将字符串绘制在面板的中央,并绘制出基线。
需要注意到的是drawString函数中,指定的是字符串基线的y坐标。
/** @version 1.32 2004-05-03 @author Cay Horstmann */ import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import javax.swing.*; public class FontTest { public static void main(String[] args) { FontFrame frame = new FontFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } /** A frame with a text message panel */ class FontFrame extends JFrame { public FontFrame() { setTitle("FontTest"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // add panel to frame FontPanel panel = new FontPanel(); add(panel); } public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; } /** A panel that shows a centered message in a box. */ class FontPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; String message = "Hello, World!"; Font f = new Font("Serif", Font.BOLD, 36); g2.setFont(f); // measure the size of the message FontRenderContext context = g2.getFontRenderContext(); Rectangle2D bounds = f.getStringBounds(message, context); // set (x,y) = top left corner of text double x = (getWidth() - bounds.getWidth()) / 2; double y = (getHeight() - bounds.getHeight()) / 2; // add ascent to y to reach the baseline double ascent = -bounds.getY(); double baseY = y + ascent; // draw the message g2.drawString(message, (int) x, (int) baseY); g2.setPaint(Color.GRAY); // draw the baseline g2.draw(new Line2D.Double(x, baseY, x + bounds.getWidth(), baseY)); // draw the enclosing rectangle Rectangle2D rect = new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()); g2.draw(rect); } }
三.图像
读入图像
如果图像存储在本地文件中,就应该调用:
Image image = ImageIO.read(new File(filename));(带扩展名)
如果图像存在英特网的某个位置上,提供URL:
Image image = ImageIO.read(new URL(urlname));
如果图像不可用,read方法将抛出一个IOException。
显示图像
可以使用Graphics类的drawImage方法将图像显示出来:
注意:这个调用可能会在图像还没有绘制完毕就返回。
boolean drawImage(Image img, int x, int y, ImageObserver observer);
绘制一幅非比例图像。
boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer);
绘制一幅比例图像。系统按照比例将图像放入给定宽和高的区域。
xy是图像左上角的坐标,observer是绘制进程中以通告为目的的对象(可能为null)。
其他有用函数
Graphics类中的:
void copyArea(int x, int y, int width, int height, int dx, int dy)
拷贝屏幕中的一块区域。
x和y是原始区域左上角的坐标,width和height是原始区域的宽和高,dx和dy是原始区域到目标区域的水平和垂直距离。
void dispose()
释放图形环境和操作系统资源。必须释放由调用Image.getGraphics这样的方法获得的图形环境,但不要释放由paintComponent获得的图形环境。
java.awt.Component
Image createImage(int width, int height)
创建一个用于双缓冲的脱屏图像缓冲区。
程序代码
/** @version 1.32 2004-05-03 @author Cay Horstmann */ import java.awt.*; import java.awt.event.*; import java.io.*; import javax.imageio.*; import javax.swing.*; public class ImageTest { public static void main(String[] args) { ImageFrame frame = new ImageFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } /** A frame with an image panel */ class ImageFrame extends JFrame { public ImageFrame() { setTitle("ImageTest"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // add panel to frame ImagePanel panel = new ImagePanel(); add(panel); } public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; } /** A panel that displays a tiled image */ class ImagePanel extends JPanel { public ImagePanel() { // acquire the image try { image = ImageIO.read(new File("blue-ball.gif")); } catch (IOException e) { e.printStackTrace(); } } public void paintComponent(Graphics g) { super.paintComponent(g); if (image == null) return; int imageWidth = image.getWidth(this); int imageHeight = image.getHeight(this); // draw the image in the upper-left corner g.drawImage(image, 0, 0, null); // tile the image across the panel for (int i = 0; i * imageWidth <= getWidth(); i++) for (int j = 0; j * imageHeight <= getHeight(); j++) if (i + j > 0) g.copyArea(0, 0, imageWidth, imageHeight, i * imageWidth, j * imageHeight); } private Image image; }