Java绘图与打印技术全解析
立即解锁
发布时间: 2025-08-19 00:30:38 阅读量: 1 订阅数: 8 


Java编程入门与实践指南
### Java绘图与打印技术全解析
在图形绘制和界面更新的编程领域中,我们常常会遇到诸如闪烁、绘制效率低下等问题。本文将深入探讨一些实用的绘图技术,帮助大家解决这些常见的困扰,同时还会介绍Java中的打印功能。
#### 1. 绘制技术概述
绘图操作往往需要消耗一定的时间,这可能会导致延迟和不理想的结果。我们的目标是尽量减少绘制工作的工作量,并尽可能在用户不可见的情况下完成这些工作。为了更好地理解如何消除闪烁和闪烁问题,我们将从一个表现糟糕的动画应用程序开始分析。
#### 2. 闪烁问题示例:TerribleFlicker
TerribleFlicker应用程序展示了更新显示时可能出现的一些问题。它由一个恒定的背景(棋盘格图案)和一个可拖动的前景小图像组成。当拖动图像时,背景和前景都会反复重绘,从而产生明显的闪烁现象。
以下是TerribleFlicker的代码实现:
```java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TerribleFlicker extends JComponent
implements MouseMotionListener {
int grid = 10;
int imageX, imageY;
Image image;
int imageWidth = 60, imageHeight = 60;
public TerribleFlicker(Image i) {
image = i;
addMouseMotionListener(this);
}
public void mouseDragged(MouseEvent e) {
imageX = e.getX( );
imageY = e.getY( );
repaint( );
}
public void mouseMoved(MouseEvent e) {}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
int w = getSize( ).width / grid;
int h = getSize( ).height / grid;
boolean black = false;
for (int y = 0; y <= grid; y++)
for (int x = 0; x <= grid; x++) {
g2.setPaint(black ? Color.black : Color.white);
black = !black;
g2.fillRect(x * w, y * h, w, h);
}
g2.drawImage(image, imageX, imageY,
imageWidth, imageHeight, this);
}
public static void main(String[] args) {
String imageFile = "L1-Light.jpg";
if (args.length > 0)
imageFile = args[0];
Image i = Toolkit.getDefaultToolkit( ).getImage(
TerribleFlicker.class.getResource(imageFile));
JFrame f = new JFrame("TerribleFlicker");
Container content = new Panel(new BorderLayout( ));
content.add(new TerribleFlicker(i), BorderLayout.CENTER);
f.setContentPane(content);
f.setSize(300, 300);
f.setLocation(100, 100);
f.addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
f.setVisible(true);
}
}
```
运行该应用程序时,指定一个图像文件作为命令行参数,拖动图像,你会明显看到背景和前景的闪烁。
TerribleFlicker存在的主要问题是没有实现一个良好的更新策略。它使用了默认的`update()`方法,该方法会先将显示区域清除为背景色,然后调用`paint()`方法。但实际上,我们的应用程序会自己绘制整个背景,因此可以提供一个更简单的`update()`方法。
以下是改进后的UpdateFlicker示例:
```java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class UpdateFlicker {
public static void main(String[] args) {
String imageFile = "L1-Light.jpg";
if (args.length > 0) imageFile = args[0];
Image i = Toolkit.getDefaultToolkit( ).getImage(
TerribleFlicker.class.getResource(imageFile));
JFrame f = new JFrame("UpdateFlicker");
Container content = new Panel(new BorderLayout( )) {
public void update(Graphics g) { paint(g); }
};
content.add(new TerribleFlicker(i), BorderLayout.CENTER);
f.setContentPane(content);
f.setSize(300, 300);
f.setLocation(100, 100);
f.addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
f.setVisible(true);
}
}
```
这个应用程序通过消除一个不必要的图形操作,表现有所改善,但仍然存在大量的重复绘制。
#### 3. 有限重绘技术
当鼠标拖动时,`TerribleFlicker`调用`repaint()`会重绘整个组件,大部分绘制是不必要的。实际上,`repaint()`还有一个版本允许指定一个矩形区域进行绘制,即裁剪区域。
限制绘制区域的好处主要有两点:
- 绘制操作如果落在裁剪区域之外将不会显示。
- 图形上下文可以识别完全落在裁剪区域之外的绘制操作并直接忽略它们,从而节省时间。
以下是使用有限重绘技术的LimitedFlicker示例:
```java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LimitedFlicker extends TerribleFlicker {
int oldX, oldY;
public LimitedFlicker(Image i) { super(i); }
public void mouseDragged(MouseEvent e) {
imageX = e.getX( );
imageY = e.getY( );
Rectangle r = getAffectedArea(oldX, oldY, imageX, imageY,
imageWidth, imageHeight);
// update just the affected part of the component
repaint(r);
oldX = imageX;
oldY = imageY;
}
private Rectangle getAffectedArea(int oldx, int oldy,
int newx, int newy, int width, int height) {
int x = Math.min(oldx, newx);
int y = Math.min(oldy, newy);
int w = (Math.max(oldx, newx) + width) - x;
int h = (Math.max(oldy, newy) + height) - y;
return new Rectangle(x, y, w, h);
}
public static void main(String[] args) {
String imageFile = "L1-Light.jpg";
if (args.length > 0)
imageFile = args[0];
Image i = Toolkit.getDefaultToolkit( ).getImage(
TerribleFlicker.class.getResource(imageFile));
JFrame f = new JFrame("LimitedFlicker");
Container content = new Panel(new BorderLayout( )) {
public void update(Graphics g) { paint(g); }
};
content.add(new LimitedFlicker(i), BorderLayout.CENTER);
f.setContentPane(content);
f.setSize(300, 300);
f.setLocation(100, 100);
f.addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
f.setVisible(true);
}
}
```
LimitedFlicker通过计算受影响的区域,只重绘该区域,从而提高了绘制效率,但仍然存在闪烁问题。
#### 4. 双缓冲技术
双缓冲技术是解决闪烁问题的强大工具。它的原理是先将绘制内容绘制到一个离屏缓冲区,然后将完成的工作一次性复制到显示器上。
Swing提供了免费的双缓冲支持,我们只需要在Swing容器中使用Swing组件即可。以下是使用双缓冲技术的Smoothie示例:
```java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Smoothie {
public static void main(String[] args) {
String imageFile = "L1-Light.jpg";
if (args.length > 0)
imageFile = args[0];
Image i = Toolkit.getDefaultToolkit( ).getImage(
TerribleFlicker.class.getResource(imageFile));
JFrame f = new JFrame("Smoothie");
Container content = new JPanel(new BorderLayout( )) {
public void update(Graphics g) { paint(g); }
};
content.add(new LimitedFlicker(i)
```
0
0
复制全文
相关推荐










