Java基础教程-第十章-图形程序设计(详尽版)
第十章-图形程序设计
1. Java中怎么创建一个顶层窗口—(创建窗体)
1.1 窗体or顶层窗口是什么?
在 Java 中,顶层窗口(就是没有包含在其他窗口中的窗口)被称为窗体(frame)。在AWT 库中有一个称为 Frame 的类,用于描述顶层窗口。这个类的 Swing 版本名为 JFrame,它扩展于 Frame 类。[当前Java的GUI程序一般都是使用Swing类来设计]
AWT:Java最早用来设计GUI程序的类库
GUI:GUI是图形用户界面
Swing:基于AWT架构之上,能力更加强大的用户界面组件类,是JFC的一部分
JFC:是Java的一个基础类库,JFC 特性不仅仅包含了 Swing 组件,而且还包含了一个可访问性 API、一个 2D API 和一个可拖放 API。
1.2 顶层窗口的一个示意图
1.3 创建一个顶层上述顶层窗口的代码示例
import javax.swing.*;// 01
import java.awt.*;/*** @Description* 顶层框架的基本实现* @Date 2023/3/9 16:32**/
public class SimpleFrameTest {public static void main(String[] args) {EventQueue.invokeLater(() ->{ // 03SimpleFrame frame = new SimpleFrame();frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 04frame.setVisible(true);});}}
class SimpleFrame extends JFrame {private static final int DEFAULT_WIDTH = 300; // 02private static final int DEFAULT_HEIGHT = 200;public SimpleFrame(){setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);}}
1.3.1 运行效果
- 如上图效果一致
1.3.2 代码分析:
01:
import javax.swing.*;
Swing 类位于 javax.swing 包中。包名 javax 表示这是一个 Java 扩展包,而不是核心包。
02:
private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200;
在默认情况下,窗体的大小为 0x0 像素,这种窗体没有什么实际意义。这里定义了一个子类 SimpleFrame,它的构造器将窗体大小设置为 300x200 像素。这是SimpleFrame 和 JFrame 之间唯一的差别。
03:
EventQueue.invokeLater(() ->{
所有的 Swing 组件必须由事件分派线程 (event dispatch thread) 进行配置,线程将
鼠标点击和按键控制转移到用户接口组件。下面的代码片断是事件分派线程中的执行代码:EventQueue.invokeLater(() ->{
statements
});
! 目前不需理解,此内容会在14章的笔记中详细讨论,只需要简单地将其看作启动一个 Swing 程序的
神奇代码即可。04:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
此代码是定义一个用户关闭这个框架时的响应动作。对于这个程序而言,只让程序简单地退出即可。
2. 怎么改变窗口的大小,位置等属性—(窗口)?
2.1 窗口有哪些方法可以改变其属性?
JFrame 类本身只包含若干个改变窗口外观的方法。当然,通过继承,从 JFrame 的各个超类中继承了许多用于处理窗口大小和位置的方法。其中最重要的有下面几个:
- setLocation 和 setBounds 方法用于设置窗口的位置。
- seticonimage 方法用于告诉窗口系统在标题栏、任务切换窗口等位置显示哪个图标。
- setTitle 用于改变标题栏的文字。
- setResizable 利用一个 boolean 值确定窗口的大小是否允许用户改变。
2.2 JFrame类的继承层次
2.3 怎么通过获取窗口的类的“属性”来设置属性?
组件类的很多方法是以获取 /设置方法对形式出现的,例如,Frame 类的下列方法:
public String getTitleO
public void setTitle(String title)
这样的一个获取/设置方法对被称为一种属性。属性包含属性名和类型。将 get 或 set 之后的第一个字母改为小写字母就可以得到相应的属性名。【我们设置的框架类中会含有一些属性来表达框架的 ”属性“,例如: Frame 类有一个名为 title 且类型为 String 的属性。我们通过方法获取该属性,设置该属性来改变框架的外在属性 ( 从概念上讲,title 是框架的一个属性。当设置这个属性时,希望这个标题能够改变用户屏幕上的显示。当获取这个属性时,希望能够返回已经设置的属性值。)】
注意:在上述方法中,有个例外: 对于类型为 boolean 的属性,获取方法由 is 开头。例如,
下面两个方法定义了 locationByPlatform 属性:
public boolean isLocationByPlatform()
public void setLocationByPl atform(bool ean b)
2.4 怎么来确定一个合适的窗口大小?
对于专业应用程序来说,应该检查屏幕的分辨率,并根据其分辨率编写代码重置框架的大小
2.4.1 怎么获取屏幕的分辨率?
调用 Toolkit 类的静态方法
getDefhultToolkit
得到一个 Toolkit 对象 ( Toolkit 类相当于一个“基地”,包含大量与原生窗口系统交互的方法 )。然后,调用Toolkit 类的
getScreenSize
方法,这个方法以 Dimension 对象的形式返回屏幕的大小。Dimension 对象同时用公有实例变量 width 和 height 保存着屏幕的宽度和高度。Toolkit kit = Toolkit.getDefaultToolkit () ;Dimension screenSize = kit.getScreenSizeO;int screenwidth = screenSize.width;int screenHeight = screenSize.height;
然后可以使用屏幕大小的一个适当的百分数指定窗体的大小 如:将框架大小设定为上面取值的 50%,
setSize(screenwidth / 2, screenHeight / 2);
另外,还提供一个图标。由于图像的描述与系统有关,所以需要再次使用工具箱加载图像。然后,将这个图像设置为框架的图标。
Image img = new Inagelcon("icon.gif").getlmage0;setlconlmage(img);
- 注意:set类设置代码都需放在JFrame的继承类的构造器的代码块中
2.4.2 代码示例
import javax.swing.*;
import java.awt.*;/*** @Description* 设置一个大小合适的框架* @Date 2023/3/9 17:44**/
public class SizeFrameTest {public static void main(String[] args) {EventQueue.invokeLater(() ->{JFrame frame = new SizedFrame();frame.setTitle("SizedFrame");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);});}
}
class SizedFrame extends JFrame {//获取屏幕分辨率Toolkit kit = Toolkit.getDefaultToolkit();Dimension screenSize = kit.getScreenSize();public int screenWidth = screenSize.width;int screenHeight = screenSize.height;Image img = new ImageIcon("icon.gif").getImage();public SizedFrame(){//设置框架宽高和图标setSize(screenWidth / 2 , screenHeight / 2);setIconImage(img);}}
2.4.3 效果演示:
2.5 关于窗口属性设置的相关API
java.awt.Component 1.0
boolean isVisible( )
void setVisible(boolean b)
获取或设置visible属性。组件最初是可见的,但类似JFrame的顶层组件例外。
void setSize(int width , int height)
将组件大小调整为给定的宽度和高度
void setLocatioin(int x ,int y)
将组件移到一个新的位置,如果这个组件不是顶层组件,x和y坐标是容器坐标;否则如果组件是顶层组件(例如:JFrame),x和y坐标就使用屏幕坐标。
void setBoundsf (int x, int y, int width, int height)
移动并调整组件的大小。
Dimension getSize( )
void setSize(Dimension d)
获取或设置当前组件的 size 属性。
java.awt.Window
void setLocationByPlatform(boolean b)
获取或设置 locationByPlatform 属性。这个属性在窗口显示之前设置时,由平台选择一个合适的位置
java.awt.Frame
boolean isResizable()
void setResizable(boolean b)
获取或设置resizable 属性。设置了这个属性时 (属性值为 true), 用户可以调整窗体的大小。
String getTitle()
void setTitle(String s)
获取或设置 title 属性,这个属性确定窗体标题栏中的文字。
Image getlconlmagef( )
void setlconlmage(lmage image)
获取或设置 iconimage 属性,这个属性确定窗体的图标。窗口系统可能会将这个图标显
示为窗体装饰的一部分或者显示在其他位置
java.awt.Toolkit
static Toolkit getDefaultToolkit( )
返回默认的工具箱。
Dimension getScreenSize( )
返回用户屏幕的大小。
javax.swing.ImageIcon
ImageIcon(String filename)
构造一个图标,其图像存储在一个文件中。
Image getlmage( )
获得该图标的图像。
3. 怎么在窗口中显示信息?—(Java窗口)
3.1 怎么在窗口中显示信息?
在解决这个问题前,需要先了解一些关于JFrame的知识
3.1.1 窗体(顶层窗口)本质是什么?
在 Java 中,窗体实际上设计为组件的容器,如菜单栏和其他用户界面元素。在通常情况下,应该在添加到窗体的另一个组件上绘制信息。
3.1.2 JFrame的结构是什么样的?
可以看到,在 JFrame 中有四层窗格。其中的根窗格、层级窗格 和玻璃窗格人们并不太关心;它们要用来组织菜单栏和内容窗格以及实现观感。Swing 程序员最关心的是内容窗格 ( contentpane)。添加到窗体的所有组件都会自动添加到内容窗格中
现在我们了解到在窗口显示信息其实就是在内容窗格的某个组件上显示信息,所有我们来了解怎么将一个组件添加到窗体中
3.1.3 怎么添加组件到窗体中?
要在一个组件上绘制消息,需要定义一个扩展 JComponent 的类,并覆盖其中的paintComponent 方法。
paintcomponent 方法有一个 Graphics 类型的参数,Graphics 对象保存着用于绘制图像和文本的一组设置,例如,你设置的字体或当前的颜色。在 Java 中,所有的绘制都必须通过
Graphics 对象完成,其中包含了绘制图案、图像和文本的方法。例如:
class MyComponent extends JComponent {public void paintComponent (Graphics g){code for drawing} }
- paintcomponent 方法只有一个 Graphics 类型的参数。对于屏幕显示来说,Graphics 对象的度量单位是像素。坐标 (0,0 ) 指示所绘制组件的左上角。Graphics 类有很多绘制方法,显示文本是一种特殊的绘制。
Graphics类显示文本的方法如下:
g.drawString(HNot a Hello, World program", MESSAGE_X, MESSAGE_Y);
- 最后,**组件要告诉用户它会有多大。**覆盖 getPreferredSize 方法,返回一个有首选宽度和高度的 Dimension 类对象: ( Dimension是Java的一个类,封装了一个构件的高度和宽度。 )
public class NotHelloWorldComponent extends JComponent {private static final int DEFAULT_WIDTH = 300;private static final int DEFAUL_HEIGHT = 200;……public Dimension getPreferredSize( ){return new Dimension!DEFAULT_WIDTH, DEFAULT_HEIGHT);} }
- 在窗体中填入一个或多个组件时,如果你只想使用它们的首选大小,可以调用 pack 方法而不是 setSize 方法:
class NotHeUoWorldFrame extends JFrame {public NotHelloWorldFrame(){add(new NotHelloWorldComponent());pack();} }
对JComponent类的 paintComponent 方法的一点说明
绝对不要自己调用 paintComponent 方法。只要应用的某个部分需要重新绘制,就会自动调
用这个方法,不要人为地干预这个自动的处理过程。
哪些动作会触发这个自动响应呢?例如,用户扩大窗口时,或者极小化窗口后又恢复窗口的大小时,就会引发绘制。如果用户弹出了另外一个窗口,并且这个窗口覆盖了一个已有的窗口,然后让这个上层窗口消失,此时被覆盖的那个窗口已被破坏,需要重新绘制 (图形系统不保存下层的像素)。当然,窗口第一次显示时需要处理一些代码,指定如何绘制以及在哪里绘制初始的元素 。
3.1.3.1 代码示例:
import javax.swing.*;
import java.awt.*;/*** @Description* 在窗口显示文字* @Date 2023/3/10 17:47**/
public class NotHelloWorld {public static void main(String[] args) {EventQueue.invokeLater(()->{var frame = new NoteHelloWorldFrame();frame.setTitle("Hello");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);});}}
//包含了消息面板的框架
class NoteHelloWorldFrame extends JFrame{public static final int DEFFAULT_WIDTH = 500;public static final int DEFFAULT_HEIGHT = 800;public static final int MESSAGE_X = 200;public static final int MESSAGE_y = 200;public NoteHelloWorldFrame(){add(new NotHelloWorldComponent());setBounds(MESSAGE_X,MESSAGE_y,DEFFAULT_WIDTH,DEFFAULT_HEIGHT);}}//显示消息的组件
class NotHelloWorldComponent extends JComponent{public static final int MESSAGE_X = 75;public static final int MESSAGE_Y = 100;private static final int DEFAULT_WIDTH = 300;private static final int DEFAULT_HEIGHT = 200;public void paintComponent(Graphics g){g.drawString("Hello World!",MESSAGE_X,MESSAGE_Y);}public Dimension getPreFerredSize(){return new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT);}}
3.1.3.2 运行效果
3.2 相关API
java.awt.Component
void repaint ( )
“尽可能快地”重新绘制组件。
Dimension getPreferredSize( )
覆盖这个方法,以返回这个组件的首选大小。
java.swing.JComponent
void paintComponent(Graphics g)
覆盖这个方法来描述需要如何绘制组件。
java.awt.Window
void pack()
调整窗口大小,要考虑其组件的首选大小。
4. 怎么绘制一些2D图形—(Swing)
4.1 怎么绘制2D图形?
- 先了解一点前置内容
从 Java 版本 1.0 以来,Graphics 类就包含绘制直线、矩形和椭圆等方法。但是,这些绘制图形的操作能力非常有限。所以我们将使用 Java 2D 库的图形类。
要想使用 Java 2D 库绘制图形,需要获得 Graphics2D 类的一个对象。这个类是 Graphics 类的子类。自从 Java 1.2 版本以来,paintComponent 等方法会自动地接收一个 Graphics2D 类对象。只需要使用一个类型强制转换,如下所示:
public void paintComponent(Graphics g) {Graphics2D g2 = (Graphics2D) g; }
Java 2D 库采用面向对象的方式组织几何图形。具体来说,它提供了表示直线、矩形和椭圆的类:
Line2D ; Rectangle2D ; Ellipse2D
这些类都实现了 Shape 接口。
具体操作:
首先要创建一个实现了 Shape 接口的类的对象,然后调用 Graphics2D类的 draw 方法。例如,
Rectangle2D rect = . . . ; g2.draw(rect);
【总结:我们关于2D图形的绘制的代码操作都在继承了 JConponent 的子类的 paintComponent 方法体中,然后创建一个想要绘制的图形对应的java类库的类,最后把该类作为Graphics2D 类的对象的draw方法的参数就可以了】
4.1.1 关于2D图形类库浮点型作为坐标的问题解析
Java 2D 库针对像素采用的是浮点坐标,而不是整数坐标。内部计算都采用单精度 float。
因此将 double 值转换成 float 值时必须进行强制类型转换
这样的代码会报错
float f = 1.2; //
ERROR
必须
float f = 1.2F; // OK
加F后缀才不会报错且
float f = r.getWidth(); // ERROR
这样的代码也会报错,因为 getWidth 方法的返回类型是 double。
补救方法是加个强制类型转换。
为了解决这个麻烦:
2D 库的设计者决定为每个图形类提供两个版本:
一个是为那些想节省空间的程序员提供的版本,要使用 float 类型的坐标;
另一个是为那些懒惰的程序员提供的版本,会使用 double 类型的坐标
举例: Rectangle2D 类,这是一个抽象类,有两个具体子类,这两个具体子类也是静态内部类:
Rectangle2D.Float
Rectangle2D.Double当构造一个 Rectangle2D.Float 要为坐标提供 float 数。而构造 Rectangle2D.Double 对象时,应该提供 double 数。
var floatRect = new Rectangle2D.Float(10.0F, 25.0F, 22.5F, 20.0F); var doubleRect = new Rectangle2D.Double(10.0, 25.0, 22.5, 20.0);
【总结:简单的说,一般情况我们直接用double类型的2D类来使用,就不用考虑任何问题,但构造的图形过多时,就要使用float类型的2D类来节省空间,这时要注意F后缀和类型转换等问题】
4.2 2D图形类库的继承关系
4.3 圆形,矩形,此矩形的内接椭圆,对角线的代码示例
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;/*** @Description* 圆形,矩形,此矩形的内接椭圆,对角线图形描绘* @Date 2023/3/10 20:52**/
public class DrawTest {public static void main(String[] args) {EventQueue.invokeLater(()->{var frame = new DrawFrame();frame.setTitle("DrawTest");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);});}}class DrawFrame extends JFrame{public DrawFrame(){add(new DrawComponent());pack();}}class DrawComponent extends JComponent{private static final int DEFAULT_WIDTH = 400;private static final int DEFAULT_HEIGHT = 400;public void paintComponent(Graphics g){var g2 = (Graphics2D)g;//画一个矩形double leftX = 100;double topY = 100;double width = 200;double height = 150;var rect = new Rectangle2D.Double(leftX,topY,width,height);g2.draw(rect);//画一个该矩形的内接椭圆var ellipse = new Ellipse2D.Double();ellipse.setFrame(rect);g2.draw(ellipse);//画一个对角线g2.draw(new Line2D.Double(leftX,topY,leftX+width,topY+height));//画一个圆心和上述矩形中心一致的圆double centerX = rect.getCenterX();double centerY = rect.getCenterY();double radius = 150;var circle = new Ellipse2D.Double();circle.setFrameFromCenter(centerX,centerY,centerX+radius,centerY+radius);g2.draw(circle);}public Dimension getPreferredSize(){return new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT);}}
4.3.1 运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HK6Ch4ej-1681618765969)(img/1678454177231.png)]
4.5 相关API
java.awt.geom.RectangularShape
double getCenterX( )
double getCenterY( )
double getMinX( )
double getMinY( )
double getMaxX( )
double getMaxY( )
返回闭合矩形的中心,以及最小、最大 x 和y 坐标值。
double getWidth( )
double getHeight( )
返回闭合矩形的宽和高。
double getX( )
double getY( )
返回闭合矩形左上角的 x 和y 坐标
java.awt.geom.Rectangle2D.Double
Rectangle2D.Double(double x, double y, double w, double h)
利用给定的左上角、宽和高,构造一个矩形。
java.awt.geom.Ellipse2D.Double
Ellipse2D.Doublet double x, double y, double w, double h)
利用有给定左上角、宽和高的外接矩形,构造一个椭圆。
java.awt.geom.point2D.Double
Point2D.Double(double x, double y)
利用给定坐标构造一个点。
java.awt.geom.Line2D.Double
Line2D.Double(Point2D start, Point2D end)
Line2D.Double(double startX, double startY, double endX, double endY)
使用给定的起点和终点,构造一条直线。
5. 怎么在窗口中使用颜色?—(Swing)
5.1 怎么对文字,图形,背景设置颜色?
- 使用 Graphics2D 类的 setPaint 方法可以为图形上下文上的所有后续的绘制操作选择颜色。
例如:g2.setPaint(Color.RED); g2.drawString( "Warning! ", 190, 100);
- 可以用一种颜色填充一个封闭图形 (例如,矩形或椭圆) 的内部。为此,只需要将调用draw 替换为调用 fill:
Rectangle2D red = . . . ; g2.setPaint(Color.RED); g2.fill(rect); // fills rect with red
- 要想用多种颜色绘制,就需要选择一个颜色、绘制图形、再选择另外一种颜色、再绘制图形
5.1.1 fill 方法的一个注意点:
【 fill 方法会在右侧和下方少绘制一个像素。例如,如果绘制一个 new Rectangle2D.Double(0, 0, 10, 20), 绘制的矩形将包括 x = 10 和 y = 20 的像素。如果填充这个矩形,则不会绘制 x = 10 和 y = 20 的像素。 】
5.2 Java中关于颜色的定义类—Color
Color 类用于定义颜色。在)3V石1m<010「类中提供了13个预定义的常量,它们分别表示13 种标准颜色。
BLACK, BLUE, CYAN, DARK GRAY, GRAY, GREEN, LIGHT GRAY,MAGENTA, ORANGE, PINK, RED, WHITE, YELLOW
5.2.1 利用RGB创建一种颜色的Color类对象
可以提供三色分量来创建 Color 对象,从而指定一个定制颜色。红、绿和蓝三种颜色取值为 01255 之间的整数:
g2.setPaint (new Color(0, 128, 128)); // a dull blue-green g2.drawString( "Welcome ! ", 75, 125)
5.3 怎么设置背景颜色
- 使用 Component 类中的 setBackground 方法。Component 类是 JComponent类的祖先
var component = new MyComponentf); component. setBackground(Color. PINK) ;
- 还有一个 setForeground 方法,它用来指定在组件上进行绘制时使用的默认颜色。
5.4 相关API
java.awt.Color
Color(int r, int g, int b)
用给定的红、绿、蓝分量 (取值为 0 255 ) 创建一个颜色对象
java.awt.Graphics2D
Paint getPaint( )
void setPaint(paint p)
获取或设置这个图形上下文的绘制属性。Color 类实现了 Paint 接口。因此,可以使用这个方法将绘制属性设置为纯色。
void fill(Shape s)
用当前的颜料填充图形。
java.awt.Component
Color getForeground()
Color getBackground()
void setForeground (Color c)
void setBackground(Color c)
获取或设置前景或背景颜色
6.怎么在GUI程序中设置字体?—(Swing)
6.1 Java中关于字体的说明【前置知识说明】
- 如果你想用不同的字体显示文本。可以通过字体名 ( font face name) 指定一种字体。字体名由
字体族名 (font family name, 如 “Helvetica” ) 和一个可选的后缀 (如 “Bold”) 组成。例如:“Helvetica” 和 “Helvetica Bold” 都属于名为 “Helvetica” 字体族的字体。
6.1.1 怎么知道计算机中有哪些可用的字体?
可以调用 GraphicsEnvironment 类的 getAvailableFontilyNames 方法。这个方法将返回一个字符串数组,其中包含了所有可用的字体名。
GraphicsEnvironment 类描述了用户系统的图形上下文,为了得到这个类的对象,需要调用静态的 getLocalGraphicsEnvironment 方法。下面这个程序将打印出你的系统上的所有字
体名:import java.awt.*; public class ListFonts {public static void main(String[] args){String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment ().getAvailableFontFamilyNames ();for (String fontName : fontNames)System.out.printin( fontName);} }
6.1.1.1 java中一些可用的字体名
AWT 定义了 5 个逻辑 (logical) 字体名:
SansSerif
Serif
Monospaced
Dialog
Dialoginput说明: 这些字体名总是被映射到客户机上的某些实际字体。例如,在 Windows 系统中,SansSerif 将被映射到 Arialo。
Oracle JDK 总是包含 3 个字体族,名为“Lucida Sans",“Lucida Bright” .“Lucida Sans Typewriter”.
6.2 如何使用某种字体绘制字符?【正式流程】
- 此段内容为方便理解依旧会穿插一些理论知识【大致了解就好】
- 首先必须创建一个 Font 类的对象。需要指定字体名、字体风格和字体大小。下面是构造一个 Font 对象的例子:
var sansboldl4 = new Font ("SansSerif", Font.BOLD, 14);
代码解析:
1. 在Font的构造器的第二个参数字体风格的意思为: (常规、加粗、斜体或加粗斜体) 等属性的设置,其参数展示如下:
Font.PLAIN (常规)
Font.BOLD(加粗)
Font.ITALIC(斜体)
Font.BOLD + Font.ITALIC (粗斜体)2. 第三个参数是以点数目计算的字体大小。排版中普遍使用点数指示字体大小,每英寸包含 72 个点。
- 下面这段代码将使用系统中 14 点加粗的标准 sans serif 字体显示字符串 “Hello, World”:
var sansboldl4 = new Font ("SansSerif", Font.BOLD, 14);g2.setFont(sansboldl4);var message = "Hello, World!";g2.drawstring(message, 75, 100);
代码解析:
- 按上创建一个Font对象
- 前几节的笔记我们知道消息的展示是通过Graphics的对象来展示,使用我们调用此类的对象的setFont方法来将我们创建好的字体对象作为参数赋予给它
- 然后我们创建一个字符串来包含我们的信息
- 最后调用Graphics对象的drawstring方法即可
6.2.1 怎么将字符串居中显示?
- 内包含许多原理解释性说明,如感觉不好理解,那则了解代码层次也可
6.2.1.1 关于字符串大小的排版知识
- 基线(baseline) 是一条虚构的线,例如,字母 “e” 所在的底线。
- 上坡度 (ascent) 是从基线到坡顶(ascenter) 的距离 (坡顶是 “b” “k” 或大写字母的上面部分)。
- 下坡度 (descent) 是从基线到坡底(descenter) 的距离 (坡底是 “p” “g” 等字母的下面部分)。
- 行间距 ( leading) 是某一行的坡底与其下一行的坡顶之间的空隙
- 字体的高度是连续两个基线之间的距离,它等于下坡度 + 行间距 + 上坡度。
要字符串居中,需要知道 字符串占据的宽和高的像素数。这两个值取决于下面三个因素:
- 使用的字体 (在这个例子中为 sans serif, 加粗,14 点);
- 字符串 (在这个例子中为 “Hello,World");
- 绘制字体的设备 (在这个例子中为用户屏幕)。
要想得到表示屏幕设备字体属性的对象 , 需要调用 Graphics2D 类中的getFontRenderContext方法。 它将返回一个 FontRenderContext 类的对象。可以直接将这个对象传递给 Font 类的 getStringBounds 方法:
FontRenderContext context = g2.getFontRenderContext ( ); Rectangle2D bounds = sansboldl4.getStringBounds (message, context);
getStringBounds 方法将返回包围字符串的矩形
通过前面了解到的排版知识,我们可以知道的是:这个矩形的宽度是字符串水平方向的宽度。矩形的高度是上坡度、下坡度和行间距的总和。这个矩形始于字符串的基线,矩形顶部的y 坐标为负值。
因此,可以使用下面的方法获得字符串的宽度、高度和上坡度:
double stringwidth = bounds・getWidth(); double stringHeight = bounds.getHeight(); double ascent = -bounds.getYf);
- 如果需要知道下坡度或行间距,可以使用 Font 类的 getLineMetrics 方法。这个方法将返回一个 LineMetrics 类的对象.,获得下坡度和行间距的方法是:
LineMetrics metrics = f.getLineMetrics (message, context); float descent = metrics.getDescentO; float leading = metrics.getLeadingf);
【很明显,看到这还很有可能看不懂到底让字体居中的原理到底是啥,所以我会以更通俗的话来表达:
首先我们要明白让字体居中的本质是让字体坐标(以左上角的坐标来确定)值恰好是其居中的坐标值,所以我们为了求出这个坐标值,引入了一个矩形概念,这个矩形是将这个字符串包起来的。
然后,我们可以获取这个矩形的长,设为x1,和高,设为y1,组件容器,(也就是显示这个文字的页面)的宽设为x2,高设为y2,
让(x1-x2)/ 2 = 此矩形在中心时的最左端的X坐标值
让(y1-y2)/ 2 = 此矩形在中心时最顶端的Y坐标值
- 下有图解 】
6.3 总结性的代码示例
- 该程序目的是:将字符串在窗体中居中,并绘制了基线和包围这个字符串的矩形。
import javax.swing.*;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Dimension2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;/*** @Description* @Date 2023/3/11 10:40**/
public class FontTest {public static void main(String[] args) {EventQueue.invokeLater(()->{var frame = new FontFrame();frame.setTitle("FontTest");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);});}}
//创建顶层窗口类
class FontFrame extends JFrame {public FontFrame (){add(new FontCompenent());pack();}}
//创建一个消息显示在中心的组件类
class FontCompenent extends JComponent {private static final int DEFAULT_WIDTH = 300;private static final int DEFAULT_HEIGHT = 200;public void paintComponent(Graphics graphics) {var graphics02 = (Graphics2D) graphics;var message = "Hello World!";var font = new Font("Serif", Font.BOLD, 36);graphics02.setFont(font);//获取message的大小矩形盒子FontRenderContext context = graphics02.getFontRenderContext();Rectangle2D bounds = font.getStringBounds(message, context);//获得该矩形处中心位置时,左边长离组件容器最左段的距离,和顶端离组件容器顶端的距离double x = (getWidth() - bounds.getWidth()) / 2;double y = (getHeight() - bounds.getHeight()) / 2;double ascent = -bounds.getY();//以双倍精度返回框架矩形左上角的Y坐标,此坐标值为矩形顶端到基线的距离double baseY = y + ascent;//矩形的基线坐标System.out.println(y);System.out.println(ascent);System.out.println(baseY);//绘制消息graphics02.drawString(message,(int) x,(int) baseY);graphics02.setPaint(Color.LIGHT_GRAY);//绘制基线graphics02.draw(new Line2D.Double(x, baseY, x + bounds.getWidth(),baseY));//绘制外围矩形var rect = new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight());graphics02.draw(rect);}public Dimension getPreferredSize() {return new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT);}}
6.3.1 运行结果
6.4 相关API
java.awt.Font
Font(String name, int style, int size)
创建一个新字体对象。字体名可以是具体的字体名 (例如,“Helvetica Bold”), 或者逻
辑字体名 (例如,“SeriFSansSerif”)。字体风格可以是 Font.PLAIN、Font.BOLD、Font.ITALIC
或 Font.BOLD+Font.ITALICString getFontName()
获得字体名, 例如,“Helvetica Bold”。
String getFamily()
获得字体族名, 例如,“Helvetica”。String getName()
如果采用逻辑字体名创建字体,将获得逻辑字体名,例如,”SansSerif" ;否则,获得
字体名。Rectangle2D getStringBounds(String s, FontRenderContext context)
返回包围这个字符串的矩形。矩形的起点为基线。矩形顶端的y 坐标等于上坡度的负
值。矩形的高度等于上坡度、下坡度和行间距之和。宽度等于字符串的宽度。LineMetrics getLineMetrics(String s, FontRenderContext context)
返回确定字符串宽度的一个度量对象。
Font deriveFont(int style)
Font deriveFont(float size)
Font deriveFont(int style, float size)
返回一个新字体,除了有给定的大小和字体风格外,其余与原字体一样
java.awt.font.LineMetrics
float getAscent()
获得字体的上坡度——从基线到大写字母顶端的距离。
float getDescent()
获得字体的下坡度——从基线到坡底的距离。
float getLeading()
获得字体的行间距——从一行文本底端到下一行文本顶端之间的空隙C
float getHeight()
获得字体的总高度——两条文本基线之间的距离 (下坡度 + 行间距 + 上坡度)。
java.awt.Graphics2D
FontRenderContext getFontRenderContext()
获得这个图形上下文中指定字体特征的字体绘制上下文。
void drawString(String str, float x, float y)
采用当前的字体和颜色绘制一个字符串。
java.swing.JComponent
FontMetrics getFontMetrics(Font f)
获取给定字体的字体度量对象。FontMetrics 类是 LineMetrics 类的前身
java.awt.FontMetrics
FontRenderContext getFontRenderContextf )
返回字体的字体绘制上下文
7 怎么在GUI程序中显示图像?—(java_Swing)
7.1 怎么在窗口显示图像?
首先,需要读取到需要显示的图像文件
- 使用 Imageicon 类从文件读取图像:
Image image = new Imageicon(filename) .getlmagef );
- 现在变量 image 包含一个封装了图像数据的对象的引用。可以使用 Graphics 类的 drawlmage 方法显示这个图像。
public void paintComponent (Graphics g) {g.drawlmage(image, x, y, null); }
- 可以再进一步,在一个窗口中平铺显示图像。结果如图 10-11 所示。这里采用 paint・
Component 方法来实现平铺显示。首先在左上角显示图像的一个副本,然后使用 copyArea 调用将其复制到整个窗口:for (inti = 0;i * imageWidth <= getWidth(); i++)for (int j = 0; j * iuageHeight <= getHeight(); j++)if (i + j > 0)g. copyArea(0,;G imageWidth, imageHeight, i * imageWidth, j * imageHeight);
7.2 相关API
java.awt.Graphics
boolean drawlmage(Image img, int x, int y, Imageobserver observer)
boolean drawlmage(Image img, int x, int y, int width, int height, Imageobserver observer)
绘制一个不缩放或缩放的图像。注意:这个调用可能会在图像绘制完毕前就返回。会
向 imageobserver 对象通知绘制的进展。这在很久以前是一个很有用的特性。不过现在
只需要传递 null 作为观察者就可以了。void copyArea(int x, int y, int width, int height, int dx, int dy)
复制屏幕的一个区域。dx 和 dy 是原始区域到目标区域的距离。
Java基础教程-第十章-图形程序设计(详尽版)相关推荐
- Java基础教程-刘刚-专题视频课程
Java基础教程-2704人已学习 课程介绍 Java基础教程是一套入门Java开发语言的课程,它是由浅入深的介绍Java基础内容,包括Java介绍.基本类型及运算符.控制执行流程.字 ...
- Java基础教程:反射基础
Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射. 反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时 ...
- Java基础教程:多线程基础(3)——阻塞队列
Java基础教程:多线程基础(3)--阻塞队列 快速开始 引入问题 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 模 ...
- Java基础教程:面向对象编程[2]
Java基础教程:面向对象编程[2] 内容大纲 访问修饰符 四种访问修饰符 Java中,可以使用访问控制符来保护对类.变量.方法和构造方法的访问.Java 支持 4 种不同的访问权限. default ...
- Java基础教程(12)--深入理解类
一.方法的返回值 当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...
- Java基础教程:Lambda表达式
Java基础教程:Lambda表达式 引入Lambda Java 是一流的面向对象语言,除了部分简单数据类型,Java 中的一切都是对象,即使数组也是一种对象,每个类创建的实例也是对象.在 Java ...
- Java基础教程:注解
Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...
- java基础教程(一)
Java 开发环境配置 在进行Java开发之前,需要先安装Java开发工具包(JDK)和集成开发环境(IDE).以下是Java开发环境的配置和搭建步骤: 下载JDK:访问Oracle官方网站,选择适合 ...
- Java基础学习——第十章 枚举类注解
Java基础学习--第十章 枚举类&注解 一.枚举类(enum) 1. 枚举类的概念 枚举类:类的对象只有有限个,确定的 线程状态:创建.就绪.运行.阻塞.死亡 当需要定义一组常量时,强烈建议 ...
最新文章
- 发布CodeBuild.Net代码自动生成器 V2008 2.01(Vs2008)和架构实例源码Demo
- .NET Core 中生成验证码
- 网络协议 3 - 从物理层到 MAC 层
- 公基会考计算机知识,公基计算机基础知识汇总70.doc
- (转)马云的江湖 PK 史玉柱的兵法
- 10上wsl位置迁移_AppGet作者:WSL是微软的神奇之举,但Windows 7开源永不可能
- 唐宇迪学习笔记2:Python数据分析处理库——pandas
- distpicker动态赋值问题
- micro/微店API接口(item_search-根据关键词取商品列表)
- 关于Movie Studio插入素材格式问题
- php theexcerpt,WordPress获取文章摘要函数the_excerpt详解
- UE4中VR项目的打包和发布
- html中siblings方法,jQuery使用siblings获取某元素所有同辈(兄弟姐妹)元素用法示例...
- 将秒针声音加入JAVA_喜马拉雅联合秒针系统发布声音流广告报告
- 区块链钱包—BTC Java版离线签名交易
- 面试经历-201106
- 保障4-0521任务打卡
- 功率放大器设计方案(包含原理图+PCB+BOM表)
- 什么样的企业需要私有化部署?
- 蓝桥杯2017年第八届蓝桥杯