带你学java核心技术图形程序设计:颜色+为文本设定特殊字体+图像
zhezhongyun 2024-12-27 17:46 79 浏览
颜色
使用Graphics2D类的setPaint方法可以为图形环境上的所有后续的绘制操作选择颜色。要想绘制多种颜色,就需要按照选择颜色,绘制图形,再选择颜色,再绘制图形的过程实施。
Color类用于定义颜色。在java.awt.Color类中提供了13个预定义的常量,它们分别表示13种标准颜色,如表7-1所示。
例如:
g2.setPaint(Color.RED);
g2.drawString("Warning!", 100, 100);
注意:在JDK 1.4之前的版本中,标准颜色的名字为小写形式,例如,Color.red。这似乎有些超出寻常,因为标准编码的惯例是采用大写形式书写常量。从JDK 1.4开始,可以采用大写的形式书写标准颜色的名字,不过,为了向后兼容,也可以用小写形式书写。
可以通过提供红、绿和蓝三色成分来创建一个Color对象,以达到定制颜色的目的。三种颜色都是用0~255(也就是一个字节)之间的整型数值表示,调用Color的构造器格式为:
Color(int redness, int greenness, int blueness)
下面是一个定制颜色的例子:
g2.setPaint(new Color(0, 128, 128)); //a dull blue-green
g2.drawString("Welcome!", 75, 125);
注意:除了纯色以外,还可以选择更复杂的“颜料”设置,例如,改变色调(hue)或者图像。有关这方面更加详细的内容请参阅卷II中的高级AWT章节。如果使用Graphics对象,而不是Graphics2D对象,就需要使用setColor方法设置颜色。
要想设置背景颜色,就需要使用Component类中的setBackground方法。Component类是JPanel类的祖先。
MyPanel p = new MyPanel( );
p.setBackground(Color.PINK);
另外,还有一个setForeground方法,它是用来设定在组件上进行绘制时使用的默认颜色。
提示:从名字就可以看出,Color类中的brighter( )方法和darker( )方法的功能,它们分别加亮或变暗当前的颜色。使用brighter方法也是加亮条目的好办法。实际上,brighter( )只微微地加亮一点。要达到耀眼的效果,应该调用这个方法三次:c.brighter( ).brighter( ).brighter( )。
Java在SystemColor类中预定义了很多颜色的名字。在这个类中的常量,封装了用户系统的各个元素的颜色。例如,
p.setBackground(SystemColor.window)
它将把面板的背景颜色设定为用户桌面上所有窗口使用的默认颜色。(无论何时重新绘制窗口,都会填充背景颜色。)当希望让绘制的用户界面元素与用户桌面上已经存在的其他元素的颜色匹配时,使用SystemColor类中的颜色非常有用。表7-2列出了系统颜色的名字和它们的含义。
java.awt.Color 1.0
? Color(int r, int g, int b)
创建一个颜色对象。
参数:r 红色值(0~255)
g 绿色值(0~255)
b 蓝色值(0~255)
java.awt.Graphics 1.0
? void setColor(Color c)
改变当前的颜色。所有后续的绘图操作都使用这个新颜色。
参数:c 新颜色
java.awt.Graphics2D 1.2
? void setPaint(Paint p)
设置这个图形环境的绘制属性。Color类实现了Paint接口。因此,可以使用这个方法将绘制属性设置为纯色。
java.awt.Component 1.0
? void setBackground(Color c)
设置背景颜色。
参数:c 新背景颜色
? void setForeground(Color c)
设置前景颜色。
参数:c 新前景颜色
填充图形
可以选用一种颜色(通常,用当前的绘制颜色)填充闭合图形(例如,矩形或椭圆)的内部。要想填充图形,只需要将draw替换为fill就可以了:
Rectangle2D rect = . . .;
g2.setpaint(Color.RED);
g2.fill(rect); //fills rect with red color
在例7-5的程序中先用红色填充一个矩形,然后
再用暗绿色填充该矩形的内接椭圆,如图7-12所示。
例7-5 FillTest.java
为文本设定特殊字体
在本章开始的“Not a Hello, World”程序中用默认字体显示了一个字符串。实际上,经常希望选用不同的字体显示文本。人们可以通过字体名(font face name)指定一种字体。字体名由“Helvetica”这样的字体家族名(font family name)和一个可选的“Bold”后缀组成。例如,
“Helvetica”和“Helvetica Bold”属于“Helvetica”家族的字体。
要想知道某台特定计算机上所允许使用的字体,就需要调用GraphicsEnvironment类中的getAvailableFontFamilyNames方法。这个方法将返回一个字符型数组,其中包含了所有可用的字体名。
GraphicsEnvironment类描述了用户系统的图形环境,为了得到这个类的对象,需要调用静态的getLocalGraphicsEnvironment方法。下面这个程序将打印出系统上的所有字体名:
在某个系统上,输出的结果为:
后面还有70种左右的字体。
注意:JDK文档认为,后缀“heavy”、“medium”、“oblique”或“gothic”是一个家族内部的变体。根据我们的经验,事实并非如此。“Bold”、“Italic”和“BoldItalic”后缀是一个家族变体,而其他的后缀则不然。
遗憾的是,无法知道用户是否安装了某种特定“外观”的字体。字体名可以商标化,字体设计在一些权限内可以版权化。因此,字体的分发需要向字体的创始者支付特许使用金。当然,与名牌香水有廉价仿制品一样,字体也有外观相似的仿制品。例如,Helvetica 的仿制品就是Windows中被称为Arial的字体。
为了创建一个公共基准,AWT定义了五个逻辑(logical)字体名:
SansSerif
Serif
Monospaced
Dialog
DialogInput
这些字体将被映射到客户机上的实际字体。例如,在Windows系统中,SansSerif将被映射到Arial上。
注意:字体映射定义在Java安装的jre/lib子目录中的fontconfig.properties文件中。有关这个文件的更详细信息请参阅http://java.sun.com/j2se/5.0/docs/guide/intl/fontconfig.html。
早期版本的JDK使用的font.properties文件现在已经作废。
要想使用某种字体绘制字符,必须首先利用指定的字体名、字体风格和字体大小来创建一个Font类对象。下面是构造一个Font对象的例子:
Font helvb14 = new Font("Helvetica", Font.BOLD, 14);
第三个参数是以点的数目计算的字体大小。点的数目是排版中普遍使用的表示字体大小的单位,每英寸 包含72个点。这条语句使用的是14个点的字体。
在Font构造器中,提供字体名的位置也可以给出逻辑字体名称。另外,利用Font构造器的第二个参数可以指定字体的风格(常规、加粗、斜体或加粗斜体),下面是几个字体风格的值:
Font.PLAIN
Font.BOLD
Font.ITALIC
Font.BOLD+Font.ITALIC下面是一个例子:
Font sansbold14 = new Font("SansSerif", Font.BOLD, 14)
注意:在Java以前的版本中,将Helvetica、TimesRoman、Courier和ZapfDingbats作为逻辑字体名。为了向后兼容,现在仍然将这些字体名按照逻辑字体名对待,尽管Helvetica实际上是一种字体名,而TimesRoman和ZapfDingbats根本不是字体名,它们实际的字体名是“Times Roman”和“Zapf Dingbats”。
提示:从JDK 1.3开始,可以读取TrueType字体。这需要一个字体输入流—通常从磁盘文件或者URL读取。(有关流的更详细信息请参阅第12章。)然后调用静态方法Font.createFont:
URL url = new URL("http://www.fonts.com/Wingbats.ttf");
InputStream in = url.openStream( );
Font f = Font.createFont(Font.TRUETYPE_FONT, in);上面定义的字体为常规字体,大小为1。可以使用deriveFont方法定义字体的大小:
Font df = f.deriveFont(14.0F);
警告:deriveFont方法有两个重载版本。一个(有一个float参数)设置字体的大小;另一个(有一个int参数)设置字体风格。所以f.deriveFont(14)设置的是字体风格,而不是大小!(其结果为斜体,因为14的二进制表示的是ITALIC,而不是BOLD。)
Java字体包含了通用的ASCII字符和符号。例如,如果用Dialog字体打印字符'\u2297',那么就会看到 字符。只有在Unicode字符集中定义的符号才能够使用。
下面这段代码将使用系统上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);接下来,将字符串绘制在面板的中央,而不是任意位置。因此,需要知道字符串占据的宽和高的像素数量。这两个值取决于下面三个因素:
? 使用的字体(在前面列举的例子中为sans serif,加粗,14号)。
? 字符串(在前面列举的例子中为“Hello, World”)。
? 绘制字体的设备(在前面列举的例子中为用户屏幕)。
要想得到屏幕设备字体属性的描述对象,需要调用Graphics2D类中的getFontRenderContext方法。
它将返回一个FontRenderContext类对象。可以直接将这个对象传递给Font类的getStringBounds方法:
FontRenderContext context = g2.getFontRenderContext( );
Rectangle2D bounds = f.getStringBounds(message, context);
getStringBounds方法将返回包围字符串的矩形。
为了解释这个矩形的大小,需要清楚几个排版的相关术语。如图7-13所示。基线(baseline)是一条虚构的线,例如,字母“e”所在的底线。上坡度(ascent)是从基线到坡顶(ascenter)的距离。例如,“b”和“k”以及大写字母的上面部分。下坡度(descent)是从基线到坡底(descenter)的距离,坡底是“p”和“g”这种字母的底线。
行间距(leading)是某一行的坡底与其下一行的坡顶之间的空隙(这个术语源于排字机分隔行的引导带)。字体的高度是连续两个基线之间的距离,它等于下坡度+行间距+上坡度。
getStringBounds方法返回的矩形宽度是字符串水平方向的宽度。矩形的高度是上坡度、下坡度、行间距的总和。该矩形始于字符串的基线,矩形顶部的y坐标为负值。因此,可以采用下面的方法获得字符串的宽度、高度和上坡度:
如果需要知道下坡度或行间距,可以使用Font类的getLineMetrics方法。这个方法将返回一个LineMetrics类对象,获得下坡度和行间距的方法是:
下面这段代码使用了所有这些信息,将字符串显示在包围它的面板中央:
为了能够获得中央的位置,可以使用getWidth( )得到面板的宽度。使用bounds.getWidth( )得到字符串的宽度。前者减去后者就是两侧应该剩余的空间。因此,每侧剩余的空间应该是这个差值的一半。高度也是一样。
最后,程序绘制出基线和包围该字符串的矩形。
图7-14给出了屏幕显示结果。例7-6是程序清单。
例7-6 FontTest.java
java.awt.Font 1.0
? Font(String name, int style, int size)
创建一个新字体对象。
参数:name
字体名。不是字体名(“Helvetica Bold”),就是逻辑字体名(“Serif”、“SansSerif”)style
字体风格(Font.PLAIN、Font.BOLD、Font.ITALIC或Font.BOLD+Font.ITALIC)size字体大小(例如,12)
? String getFontName( )
返回字体名,例如,“Helvetica Bold”。
? String getFamily( )
返回字体家族名,例如,“Helvetica”。
? String getName( )
如果采用逻辑字体名创建字体,将返回逻辑名,例如,“SansSerif”;否则,返回字体名。
? Rectangle2D getStringBounds(String s, FontRenderContext context) 1.2返回包围该字符串的矩形。矩形的起点为基线。矩形顶端的y坐标等于上坡度的负值。矩形的高度等于上坡度、下坡度和行间距之和。宽度等于字符串的宽度。
? LineMetrics getLineMetrics(String s, FontRenderContext context) 1.2
返回确定字符串宽度的一个线性metrics对象。
? Font deriveFont(int style) 1.2
? Font deriveFont(float size) 1.2
? Font deriveFont(int style, float size) 1.2
返回一个新字体,除给定大小和字体风格外,其他与原字体一样。
java.awt.font.LineMetrics 1.2
? float getAscent( )
返回字体的上坡度—从基线到大写字母顶端的距离。
? float getDescent( )
返回字体的下坡度—从基线到坡底的距离。
? float getLeading( )
返回字体的行间距—从一行文本底端到下一行文本顶端之间的空隙。
? float getHeight( )
返回字体的总高度—两条文本基线之间的距离(下坡度+行间距+上坡度)。
java.awt.Graphics 1.0
? void setFont(Font font)
为图形环境选择一种字体。这种字体将被应用于后续的文本绘制操作中。
参数:font
字体
? void drawString(String str, int x, int y)
采用当前字体和颜色绘制一个字符串。
参数:str 将要绘制的字符串
x 字符串开始的x坐标
y 字符串基线的y坐标
java.awt.Graphics2D 1.2
? FontRenderContext getFontRenderContext( )
返回这个图形环境中,指定字体特征的字体绘制环境。
? void drawString(String str, float x, float y)
采用当前的字体和颜色绘制一个字符串。
参数:str 将要绘制的字符串
x 字符串开始的x坐标
y 字符串基线的y坐标
图像
到目前为止,已经看到了如何通过绘制直线和图形创建一个简单的图像。而对于照片这样的复杂图像来说,通常都是由扫描仪或特殊的图像处理软件生成的。(正像在卷II中将看到的,逐像素地生成图像,并将结果存储到数组中也是可以的。这种方式通常用于生成不规则碎片的图像。)
一旦图像保存在本地文件或因特网的某个位置上,就可以将它们读到Java应用程序中,并在Graphics对象上进行显示。在JDK 1.4中,读取一个图像十分简单。如果图像存储在本地文件中,就应该调用:
String filename = ". . .";
Image image = ImageIO.read(new File(filename));
否则,应该提供URL:
String urlname = ". . .";
Image image = ImageIO.read(new URL(urlname));
如果图像不可用,read方法将抛出一个IOException。在第11章中,将讨论有关异常处理的问题。
而在目前的例子程序中只捕获异常,并打印出栈的轨迹。
这里的变量image包含了一个封装图像数据的对象引用。可以使用Graphics类的drawImage方法将图像显示出来。
例7-7又前进了一步,它在一个窗口中平铺显示了一幅图像。屏幕显示的结果如图7-15所示。这里采用paintComponent方法来实现平铺显示。它的基本过程为:先在左上角显示图像的一个拷贝,然后使用copyArea将其拷贝到整个窗口:
注意:如果在JDK 1.3或早期版本中加载一幅图像,就应该使用MediaTracker类。媒体跟踪器可以跟踪获得的一幅或多幅图像。(名字“媒体”暗示着这个类可以跟踪音频文件或其他媒体的文件。这预示着未来的发展,当前仅实现了跟踪图像。)
可以使用下列命令将一幅图像添加到跟踪器对象中:
MediaTracker tracker = new MediaTracker(component);
Image img = Toolkit.getDefaultToolkit( ).getImage(name);
int id = 1; //the ID used to track the image loading process
tracker.addImage(img, id);
可以将多个图像添加到一个媒体跟踪器中。每一幅图像都应该有一个不同的ID值,但是可以选择任何一种方便的计数方式。为了等待图像全部加载完毕,可以使用下面这样的代码:
try { tracker.waitForID(id); }
catch (InterruptedException e) {}
如果想获得多幅图像,可以将它们都添加到媒体跟踪器对象,并等到全部加载进来为止。可以使用下列代码实现这项操作:
try { tracker.waitForAll( ); }
catch (InterruptedException e) {}
例7-7列出了图像显示程序的全部源代码。到此为止,我们将结束Java图像编程的讨论。有关更加高级的技术,请参阅卷II中有关2D图形和图像处理的论述。
例7-7 ImageTest.java
java.swing.ImageIO 1.4
? static BufferedImage read(File f)
? static BufferedImage read(URL u)
从给定文件或URL上读取图像。
java.awt.Image 1.0
? Graphics getGraphics( )
返回一个图形环境,以便绘制该图像缓冲区。
? void flush( )
释放该图像缓冲区中保存的所有资源。
java.awt.Graphics 1.0
? boolean drawImage(Image img, int x, int y, ImageObserver observer)
绘制一幅非比例图像。注意:这个调用可能会在图像还没有绘制完毕就返回。
参数:img 将要绘制的图像
x 左上角的x坐标
y 左上角的y坐标
observer
绘制进程中以通告为目的的对象(可能为null)
? boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
绘制一幅比例图像。系统按照比例将图像放入给定宽和高的区域。注意:这个调用可能会在图像还没有绘制完毕就返回。
参数:img 将要绘制的图像
x 左上角的x坐标
y 左上角的y坐标
width 描述图像的宽度
height 描述图像的高度
observer 绘制进程中以通告为目的的对象(可能为null)
? void copyArea(int x, int y, int width, int height, int dx, int dy)
拷贝屏幕的一块区域。
参数:x 原始区域左上角的x坐标
y 原始区域左上角的y坐标
width 原始区域的宽度
height 原始区域的高度
dx 原始区域到目标区域的水平距离
dy 原始区域到目标区域的垂直距离
? void dispose( )
释放图形环境和操作系统资源。必须释放由调用Image.getGraphics这样的方法获得的图形环境,但不要释放由paintComponent获得的图形环境。
java.awt.Component 1.0
? Image createImage(int width, int height)
创建一个用于双缓冲的脱屏图像缓冲区。
参数:width 图像的宽度
height 图像的高度
java.awt.MediaTracker 1.0
? MediaTracker(Component c)
跟踪在给定组件中显示的图像。
? void addImage(Image image, int id)
将一个图像添加到被跟踪的图像列表中。当图像添加完毕后,图像加载进程将启动。
参数:image 被跟踪的图像
id 稍后引用该图像的标识符
? void waitForID(int id)
等待指定ID的图像加载完毕。
? void waitForAll( )
等待所有被跟踪的图像都加载完毕。
觉得文章不错的话,可以转发关注小编一下!!!
明天更新事件处理基础、动作、AWT事件继承层次、AWT的语义事件和低级事件、低级事件类型。
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
