上篇博客探讨了关于“如何显示一个窗口”。那么这篇来探讨“绘制内容”的基础知识。
在 Java 中,框架被设计为放置组件的容器,可以将菜单栏和其他的用户界面元素放置在其中。通常情况下,应该在另一组件上绘制信息,并将这个组件添加到框架中。
JFrame 有四层面板。其中的根面板、层级面板和玻璃面板人们并不关心;它们是用来组织菜单栏和内容窗格以及实现观感的。Swing 程序员最关心的是 内容窗格 (content pane)。
调用
frame.add(c);直接将一个绘制消息的组件添加到框架中。
绘制一个组件,需要定义一个扩展于 JComponent 的类,并覆盖其中的 paintComponent 方法。PaintComponent 方法中有一个 Graphics 类型的参数,这个参数保存着用于绘制图像和文本的设置,例如,设置的字体或当前的颜色。在 Java 中,所有绘制都必须使用 Graphics 对象,其中包含了绘制图案、图像和文本的方法。
下面方法给出了如何创建一个能够进行绘制的组件:
class MyComponent extends JComponent { public void paintComponent(Graphics g) { code for drawing } }无论何种原因,只要窗口需要重新绘制(例如,用户在扩大窗口或极小化窗口后,又恢复窗口的大小时会引发重新绘图),事件处理器就会通告组件,从而引发执行所有组件的 paintComponent 方法。
一定不要自己调用 paintComponent 方法。在应用程序需要重新绘图时,这个方法将被自动地调用,不要人为地干预这个自动的处理过程。
从上述代码段中可以看到,paintComponent 方法只有一个 Graphics 类型的参数。对于屏幕显示来说,Graphics 对象的度量单位是像素。坐标 ( 0 , 0 ) 指出所绘制组件表面的左上角。
显示文本是一种特殊的绘图。在 Graphics 类中有一个 drawString 方法,调用的语法格式为:
g.drawString(text,x,y)在这里,打算在原始窗口大约水平 1/4,垂直 1/2 的位置显示字符串 “Not a Hello,World program”。现在,尽管不知道应该如何度量这个字符串的大小,但可以将字符串的开始位置定义在坐标 (75,100)。这意味着字符串的第一个字符位于从左到右 75 个像素,从上到下 100 个像素的位置(实际上,文本的基线位于像素 100 的位置,有关文本的度量方式将在稍后阐述)。因此,paintComponent 方法的书写内容如下所示:
class NotHelloWorldComponent extends JComponent { public static final int MESSAGE_X = 75; public static final int MESSAGE_Y = 100; public void paintComponent(Graphics g) { g.drawString("Not a Hello, World program", MESSAGE_X, MESSAGE_Y); ... }最后,组件告诉用户它应该多大。覆盖 getPreferredsize 方法,返回一个有首选宽度和高度的 Dimension 类对象:
class NotHelloWorldComponent extends JComponent { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } }在框架中填入一个或多个组件时,如果你只想使用他们的首选大小,可以调用 pack 方法而不是 setSize 方法:
class NotHelloWorldFrame extends JFrame{ public NotHelloWorldFrame() { add(new NotHelloWorldComponent()); pack(); } }下面是完整代码:
package notHelloWorld; import javax.swing.*; import java.awt.*; public class NotHelloWorld { public static void main(String[] args) { EventQueue.invokeLater(() -> { JFrame frame = new NotHelloWorldFrame(); frame.setTitle("NotHelloWorld"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }); } } /** * A frame that contains a message panel */ class NotHelloWorldFrame extends JFrame{ public NotHelloWorldFrame() { add(new NotHelloWorldComponent()); pack(); } } /** * A component that displays a message */ 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("Not a Hello, World program", MESSAGE_X, MESSAGE_Y); } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } }显示结果截图: