Java 小程序开发:AWT 可移植性与图形绘制
1. 使用 AWT 实现可移植性
在 Java 小程序开发中,使用 Swing 组件的小程序可能与某些浏览器不兼容。若要确保小程序能在所有支持 Java 的浏览器中兼容,可使用 AWT 组件替代 Swing 组件。
Java 提供了两个用于创建 GUI 组件的类库,即 AWT 和 Swing。AWT 是 Java 最早版本就包含的原始类库,而 Swing 是 Java 2 引入的改进类库。之前学习的 GUI 应用程序和本章的小程序大多使用 Swing 类来创建组件。
部分浏览器不直接支持小程序中的 Swing 类,运行使用 Swing 组件的小程序需要安装插件。不过,安装 Sun JDK 时会自动安装该插件。若已安装 JDK,编写并运行使用 Swing 的小程序通常不会有问题。但如果编写的小程序要供他人在其计算机上运行,不能保证他们都有所需插件,此时应使用 AWT 类创建小程序组件。幸运的是,AWT 组件类与 Swing 类非常相似,若已掌握 Swing 的使用,学习 AWT 并不困难。
以下是一些常见的 AWT 类及其对应的 Swing 类:
| AWT 类 | 描述 | 对应的 Swing 类 |
| — | — | — |
| Applet | 用作所有小程序的超类,与 JApplet 对象不同,Applet 对象没有内容面板 | JApplet |
| Frame | 创建可作为窗口显示的框架容器,与 JFrame 对象不同,Frame 对象没有内容面板 | JFrame |
| Panel | 创建面板容器 | JPanel |
| Button | 创建可点击的按钮 | JButton |
| Label | 创建显示文本的标签 | JLabel |
| TextField | 创建用户可输入的单行文本字段 | JTextField |
| Checkbox | 创建可选择或取消选择的复选框 | JCheckBox |
Swing 类的构造函数和方法设计得与 AWT 对应类相似,且事件处理方式相同,这使得使用这两类类都很方便,无需学习不同的语法。例如,下面是一个将
TempConverter
小程序重写为使用 AWT 组件的示例代码:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
/**
* The AWTTempConverter class is an applet that converts
* Fahrenheit temperatures to Celsius.
*/
public class AWTTempConverter extends Applet {
private Panel fPanel; // To hold a text field
private Panel cPanel; // To hold a text field
private Panel buttonPanel; // To hold a button
private TextField fahrenheit; // Fahrenheit temperature
private TextField celsius; // Celsius temperature
/**
* init method
*/
public void init() {
// Build the panels.
buildFpanel();
buildCpanel();
buildButtonPanel();
// Create a layout manager.
setLayout(new GridLayout(3, 1));
// Add the panels to the applet.
add(fPanel);
add(cPanel);
add(buttonPanel);
}
/**
* The buildFpanel method creates a panel with a text
* field in which the user can enter a Fahrenheit
* temperature.
*/
private void buildFpanel() {
// Create the panel.
fPanel = new Panel();
// Create a label to display a message.
Label message1 = new Label("Fahrenheit Temperature:");
// Create a text field for the Fahrenheit temp.
fahrenheit = new TextField(10);
// Create a layout manager for the panel.
fPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
// Add the label and text field to the panel.
fPanel.add(message1);
fPanel.add(fahrenheit);
}
/**
* The buildCpanel method creates a panel that
* displays the Celsius temperature in a
* read-only text field.
*/
private void buildCpanel() {
// Create the panel.
cPanel = new Panel();
// Create a label to display a message.
Label message2 = new Label("Celsius Temperature:");
// Create a text field for the Celsius temp.
celsius = new TextField(10);
// Make the text field read-only.
celsius.setEditable(false);
// Create a layout manager for the panel.
cPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
// Add the label and text field to the panel.
cPanel.add(message2);
cPanel.add(celsius);
}
/**
* The buildButtonPanel method creates a panel with
* a button that converts the Fahrenheit temperature
* to Celsius.
*/
private void buildButtonPanel() {
// Create the panel.
buttonPanel = new Panel();
// Create a button with the text "Convert".
Button convButton = new Button("Convert");
// Add an action listener to the button.
convButton.addActionListener(new ButtonListener());
// Add the button to the panel.
buttonPanel.add(convButton);
}
/**
* Private inner class that handles the action event
* that is generated when the user clicks the convert
* button.
*/
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
double ftemp, ctemp; // To hold the temperatures
// Get the Fahrenheit temperature and convert it
// to a double.
ftemp = Double.parseDouble(fahrenheit.getText());
// Calculate the Celsius temperature.
ctemp = (5.0 / 9.0) * (ftemp - 32);
// Display the Celsius temperature.
celsius.setText(String.format("%.1f", ctemp));
}
}
}
修改内容主要包括:
- 将
JApplet
、
JPanel
、
JLabel
、
JTextField
和
JButton
类替换为
Applet
、
Panel
、
Label
、
TextField
和
Button
类。
- 移除
import javax.swing.*;
语句。
要在浏览器中运行该小程序,需将
TempConverter.html
文件中的
APPLET
标签修改为:
<applet code="AWTTempConverter.class" width=300 height=150>
</applet>
2. 图形绘制
除了显示按钮和标签等标准组件,Java 还允许在组件上绘制线条和图形,如矩形、椭圆形和弧形。在绘制图形之前,需要了解 XY 坐标系,它用于指定图形的位置。
在组件中,每个像素的位置由 X 坐标和 Y 坐标确定,通常表示为
(X, Y)
。组件左上角像素的坐标通常为
(0, 0)
,X 坐标从左到右递增,Y 坐标从上到下递增。
每个组件都有一个继承自
Graphics
类的内部对象,该对象有许多用于在组件表面绘制图形的方法。以下是一些常用的
Graphics
类方法:
| 方法 | 描述 |
| — | — |
|
void setColor(Color c)
| 将此对象的绘图颜色设置为参数指定的颜色 |
|
Color getColor()
| 返回此对象的当前绘图颜色 |
|
void drawLine(int x1, int y1, int x2, int y2)
| 在组件上绘制一条从坐标
(x1, y1)
到坐标
(x2, y2)
的线,线将以当前绘图颜色绘制 |
|
void drawRect(int x, int y, int width, int height)
| 在组件上绘制矩形的轮廓,矩形的左上角将位于坐标
(x, y)
,
width
参数指定矩形的宽度(以像素为单位),
height
指定矩形的高度(以像素为单位),矩形将以当前绘图颜色绘制 |
|
void fillRect(int x, int y, int width, int height)
| 绘制填充的矩形,参数与
drawRect
方法相同,矩形将用当前绘图颜色填充 |
|
void drawOval(int x, int y, int width, int height)
| 在组件上绘制椭圆形的轮廓,椭圆形的形状和大小由包围它的不可见矩形确定,矩形的左上角将位于坐标
(x, y)
,
width
参数指定矩形的宽度(以像素为单位),
height
指定矩形的高度(以像素为单位),椭圆形将以当前绘图颜色绘制 |
|
void fillOval(int x, int y, int width, int height)
| 绘制填充的椭圆形,参数与
drawOval
方法相同,椭圆形将用当前绘图颜色填充 |
|
void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
| 绘制弧形,弧形被视为椭圆形的一部分,椭圆形的形状和大小由包围它的不可见矩形确定,矩形的左上角将位于坐标
(x, y)
,
width
参数指定矩形的宽度(以像素为单位),
height
指定矩形的高度(以像素为单位),弧形从
startAngle
开始,到
arcAngle
结束,弧形将以当前绘图颜色绘制 |
|
void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
| 绘制填充的弧形,参数与
drawArc
方法相同,弧形将用当前绘图颜色填充 |
|
void drawPolygon(int[] xPoints, int[] yPoints, int numPoints)
| 在组件上绘制封闭多边形的轮廓,
xPoints
数组包含每个顶点的 X 坐标,
yPoints
数组包含每个顶点的 Y 坐标,
numPoints
参数指定多边形的顶点数 |
|
void fillPolygon(int[] xPoints, int[] yPoints, int numPoints)
| 绘制填充的多边形,参数与
drawPolygon
方法相同,多边形将用当前绘图颜色填充 |
|
void drawString(String str, int x, int y)
| 使用当前字体绘制传入的字符串,字符串的左下角将绘制在传入的
x
和
y
坐标处 |
|
void setFont(Font f)
| 设置当前字体,供
drawString
方法使用 |
要调用这些方法,需要获取组件的
Graphics
对象引用。一种方法是重写
paint
方法,可在继承自
JApplet
、
JFrame
或任何 AWT 类(如
Applet
和
Frame
)的类中重写该方法。
paint
方法负责在屏幕上显示或“绘制”组件,当组件首次显示或需要重新显示时会自动调用。以下是一个绘制线条的小程序示例:
import javax.swing.*;
import java.awt.*;
/**
* This class is an applet that demonstrates how lines
* can be drawn.
*/
public class LineDemo extends JApplet {
/**
* init method
*/
public void init() {
// Set the background color to white.
getContentPane().setBackground(Color.white);
}
/**
* paint method
* @param g The applet's Graphics object.
*/
public void paint(Graphics g) {
// Call the superclass paint method.
super.paint(g);
// Draw a red line from (20, 20) to (280, 280).
g.setColor(Color.red);
g.drawLine(20, 20, 280, 280);
// Draw a blue line from (280, 20) to (20, 280).
g.setColor(Color.blue);
g.drawLine(280, 20, 20, 280);
}
}
要运行该小程序,可在
LineDemo.html
文件中添加以下标签:
<applet code="LineDemo.class" width=300 height=300>
</applet>
3. 面板上的绘制
前面的示例都是将整个
JApplet
窗口作为绘图画布,有时可能希望将绘图空间限制在窗口内的较小区域,如面板。要在面板上绘图,只需获取面板的
Graphics
对象引用,然后使用该对象的方法进行绘制,绘制的图形将仅显示在面板上。
获取
JPanel
组件的
Graphics
对象引用的方法与前面的示例类似,但对于
JPanel
对象,应重写其
paintComponent
方法,这适用于除
JApplet
和
JFrame
之外的所有 Swing 组件。
paintComponent
方法的作用与
paint
方法相同,当组件需要重新显示时会自动调用,调用时会将组件的
Graphics
对象作为参数传入。以下是一个在面板上绘图的示例:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* This class displays a drawing panel and a set of
* check boxes that allow the user to select shapes.
* The selected shapes are drawn on the drawing panel.
*/
public class GraphicsWindow extends JApplet {
// Declare an array of check box components
private JCheckBox[] checkBoxes;
// The following titles array contains the
// titles of the check boxes.
private String[] titles = { "Line", "Rectangle",
"Filled Rectangle",
"Oval", "Filled Oval",
"Arc", "Filled Arc" };
// The following will reference a panel to contain
// the check boxes.
private JPanel checkBoxPanel;
// The following will reference an instance of the
// DrawingPanel class. This will be a panel to draw on.
private DrawingPanel drawingPanel;
/**
* init method
*/
public void init() {
// Build the check box panel.
buildCheckBoxPanel();
// Create the drawing panel.
drawingPanel = new DrawingPanel(checkBoxes);
// Add the check box panel to the east region
// and the drawing panel to the center region.
add(checkBoxPanel, BorderLayout.EAST);
add(drawingPanel, BorderLayout.CENTER);
}
/**
* The buildCheckBoxPanel method creates the array of
* check box components and adds them to a panel.
*/
private void buildCheckBoxPanel() {
// Create the panel.
checkBoxPanel = new JPanel();
checkBoxPanel.setLayout(new GridLayout(7, 1));
// Create the check box array.
checkBoxes = new JCheckBox[7];
// Create the check boxes and add them to the panel.
for (int i = 0; i < checkBoxes.length; i++) {
checkBoxes[i] = new JCheckBox(titles[i]);
checkBoxes[i].addItemListener(
new CheckBoxListener());
checkBoxPanel.add(checkBoxes[i]);
}
}
/**
* A private inner class to respond to changes in the
* state of the check boxes.
*/
private class CheckBoxListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
drawingPanel.repaint();
}
}
}
import javax.swing.*;
import java.awt.*;
/**
* This class creates a panel that example shapes are
* drawn on.
*/
public class DrawingPanel extends JPanel {
// Declare a check box array.
private JCheckBox[] checkBoxArray;
/**
* Constructor
*/
public DrawingPanel(JCheckBox[] cbArray) {
// Reference the check box array.
checkBoxArray = cbArray;
// Set the background color to white.
setBackground(Color.white);
// Set the preferred size of the panel.
setPreferredSize(new Dimension(300, 200));
}
/**
* paintComponent method
* @param g The panel's Graphics object.
*/
public void paintComponent(Graphics g) {
// Call the superclass paintComponent method.
super.paintComponent(g);
// Draw the selected shapes.
if (checkBoxArray[0].isSelected()) {
g.setColor(Color.black);
g.drawLine(10, 10, 290, 190);
}
if (checkBoxArray[1].isSelected()) {
g.setColor(Color.black);
g.drawRect(20, 20, 50, 50);
}
if (checkBoxArray[2].isSelected()) {
g.setColor(Color.red);
g.fillRect(50, 30, 120, 120);
}
if (checkBoxArray[3].isSelected()) {
g.setColor(Color.black);
g.drawOval(40, 155, 75, 50);
}
if (checkBoxArray[4].isSelected()) {
g.setColor(Color.blue);
g.fillOval(200, 125, 75, 50);
}
if (checkBoxArray[5].isSelected()) {
g.setColor(Color.black);
g.drawArc(200, 40, 75, 50, 0, 90);
}
if (checkBoxArray[6].isSelected()) {
g.setColor(Color.green);
g.fillArc(100, 155, 75, 50, 0, 90);
}
}
}
在这个示例中,
GraphicsWindow
类创建了一个包含复选框的面板和一个绘图面板,当用户选择复选框时,会在绘图面板上绘制相应的图形。通过调用
repaint
方法可以强制调用
paint
或
paintComponent
方法,以更新绘图。
综上所述,Java 提供了丰富的功能来开发小程序和进行图形绘制,通过合理使用 AWT 和 Swing 组件以及
Graphics
对象,可以创建出功能强大且美观的应用程序。
4. 图形绘制的更多细节
4.1 绘制不同形状的示例分析
在前面的内容中,我们已经了解了使用
Graphics
对象绘制各种基本图形的方法,下面对更多具体示例进行分析。
矩形绘制
RectangleDemo
类展示了如何绘制矩形,包括绘制黑色轮廓矩形和红色填充矩形。代码如下:
import javax.swing.*;
import java.awt.*;
/**
* This class is an applet that demonstrates how
* rectangles can be drawn.
*/
public class RectangleDemo extends JApplet {
/**
* init method
*/
public void init() {
// Set the background color to white.
getContentPane().setBackground(Color.white);
}
/**
* paint method
* @param g The applet's Graphics object.
*/
public void paint(Graphics g) {
// Call the superclass paint method.
super.paint(g);
// Draw a black unfilled rectangle.
g.setColor(Color.black);
g.drawRect(20, 20, 120, 120);
// Draw a red filled rectangle.
g.setColor(Color.red);
g.fillRect(160, 160, 120, 120);
}
}
在这个示例中,
drawRect
方法用于绘制矩形的轮廓,
fillRect
方法用于绘制填充的矩形。通过设置不同的颜色和坐标,可以绘制出不同样式的矩形。
椭圆形绘制
OvalDemo
类展示了如何绘制椭圆形,包括绘制黑色轮廓椭圆形和绿色填充椭圆形。代码如下:
import javax.swing.*;
import java.awt.*;
/**
* This class is an applet that demonstrates how
* ovals can be drawn.
*/
public class OvalDemo extends JApplet {
/**
* init method
*/
public void init() {
// Set the background color to white.
getContentPane().setBackground(Color.white);
}
/**
* paint method
* @param g The applet's Graphics object.
*/
public void paint(Graphics g) {
// Call the superclass paint method.
super.paint(g);
// Draw a black unfilled oval.
g.setColor(Color.black);
g.drawOval(20, 20, 120, 75);
// Draw a green filled oval.
g.setColor(Color.green);
g.fillOval(80, 160, 180, 75);
}
}
绘制椭圆形时,需要指定一个包围它的不可见矩形的左上角坐标、宽度和高度。通过调整这些参数,可以绘制出不同形状和大小的椭圆形。
弧形绘制
ArcDemo
类展示了如何绘制弧形,包括绘制未填充和填充的弧形。代码如下:
import javax.swing.*;
import java.awt.*;
/**
* This class is an applet that demonstrates how
* arcs can be drawn.
*/
public class ArcDemo extends JApplet {
/**
* init method
*/
public void init() {
// Set the background color to white.
getContentPane().setBackground(Color.white);
}
/**
* paint method
* @param g The applet's Graphics object.
*/
public void paint(Graphics g) {
// Call the superclass paint method.
super.paint(g);
// Draw a black unfilled arc from 0 degrees
// to 90 degrees.
g.setColor(Color.black);
g.drawArc(0, 20, 120, 120, 0, 90);
// Draw a red filled arc from 0 degrees
// to 90 degrees.
g.setColor(Color.red);
g.fillArc(140, 20, 120, 120, 0, 90);
// Draw a green unfilled arc from 0 degrees
// to 45 degrees.
g.setColor(Color.green);
g.drawArc(0, 120, 120, 120, 0, 45);
// Draw a blue filled arc from 0 degrees
// to 45 degrees.
g.setColor(Color.blue);
g.fillArc(140, 120, 120, 120, 0, 45);
}
}
绘制弧形时,除了指定包围它的矩形的信息外,还需要指定弧形的起始角度和结束角度。角度以度为单位,0 度位于 3 点钟位置。
多边形绘制
PolygonDemo
类展示了如何绘制多边形,这里绘制了一个填充的八边形。代码如下:
import javax.swing.*;
import java.awt.*;
/**
* This class is an applet that demonstrates how a
* polygon can be drawn.
*/
public class PolygonDemo extends JApplet {
/**
* init method
*/
public void init() {
// Set the background color to white.
getContentPane().setBackground(Color.white);
}
/**
* paint method
* @param g The applet's Graphics object.
*/
public void paint(Graphics g) {
int[] xCoords = {60, 100, 140, 140, 100, 60, 20, 20 };
int[] yCoords = {20, 20, 60, 100, 140, 140, 100, 60 };
// Call the superclass paint method.
super.paint(g);
// Set the drawing color.
g.setColor(Color.red);
// Draw the polygon.
g.fillPolygon(xCoords, yCoords, 8);
}
}
绘制多边形时,需要提供两个数组,分别包含每个顶点的 X 坐标和 Y 坐标,以及顶点的数量。如果最后一个点与第一个点不同,会自动连接这两个点来封闭多边形。
4.2 字符串绘制与字体设置
在 Java 中,可以使用
drawString
方法绘制字符串,并使用
setFont
方法设置字符串的字体。
GraphicStringDemo
类展示了如何绘制字符串并创建一个类似停车标志的效果。代码如下:
import javax.swing.*;
import java.awt.*;
/**
* This class is an applet that demonstrates how a
* string can be drawn.
*/
public class GraphicStringDemo extends JApplet {
/**
* init method
*/
public void init() {
// Set the background color to white.
getContentPane().setBackground(Color.white);
}
/**
* paint method
* @param g The applet's Graphics object.
*/
public void paint(Graphics g) {
int[] xCoords = {60, 100, 140, 140, 100, 60, 20, 20 };
int[] yCoords = {20, 20, 60, 100, 140, 140, 100, 60 };
// Call the superclass paint method.
super.paint(g);
// Set the drawing color.
g.setColor(Color.red);
// Draw the polygon.
g.fillPolygon(xCoords, yCoords, 8);
// Set the drawing color to white.
g.setColor(Color.white);
// Set the font and draw "STOP".
g.setFont(new Font("SansSerif", Font.BOLD, 35));
g.drawString("STOP", 35, 95);
}
}
在这个示例中,首先绘制了一个八边形,然后设置字体为加粗的 35 点无衬线字体,并在八边形上绘制字符串 “STOP”。
5. 强制重绘与图形绘制总结
5.1 强制重绘
在某些情况下,可能需要强制调用组件的
paint
或
paintComponent
方法。可以通过调用
repaint
方法来实现,其方法签名如下:
public void repaint()
repaint
方法会清除组件的表面,然后调用
paint
或
paintComponent
方法。例如,在
GraphicsWindow
类的
CheckBoxListener
类中,当用户点击复选框时,调用
drawingPanel.repaint()
方法来更新绘图面板上的图形。
5.2 图形绘制总结
在 Java 中进行图形绘制,主要步骤如下:
1. 获取组件的
Graphics
对象引用,可以通过重写
paint
方法(适用于
JApplet
、
JFrame
或 AWT 类)或
paintComponent
方法(适用于
JPanel
等 Swing 组件)。
2. 在重写的方法中,首先调用父类的相应方法,确保组件正确显示。
3. 使用
Graphics
对象的各种方法绘制图形,如
drawLine
、
drawRect
、
fillRect
等。
4. 可以使用
setColor
方法设置绘图颜色,使用
setFont
方法设置字体。
5. 如果需要强制更新图形,可以调用
repaint
方法。
以下是一个简单的流程图,展示了图形绘制的基本流程:
graph TD;
A[获取Graphics对象引用] --> B[调用父类方法];
B --> C[设置绘图颜色和字体];
C --> D[绘制图形];
D --> E{是否需要强制更新};
E -- 是 --> F[调用repaint方法];
E -- 否 --> G[结束];
F --> D;
综上所述,Java 提供了丰富的工具和方法来实现小程序的可移植性和图形绘制。开发者可以根据具体需求选择合适的组件和方法,创建出功能丰富、界面美观的应用程序。无论是使用 AWT 组件确保兼容性,还是使用
Graphics
对象进行图形绘制,都需要深入理解其原理和使用方法,才能充分发挥 Java 的优势。
超级会员免费看
43

被折叠的 条评论
为什么被折叠?



