文章目录
- 一、AWT 绘图窗口闪烁问题
- 二、完整代码示例
一、AWT 绘图窗口闪烁问题
使用 Graphics 第一次绘图 完成后 , 如果在循环中 持续调用 Canvas#repaint() 函数刷新界面 , 代码如下 :
import java.awt.*;
public class HelloAWT {
public static void main(String[] args) throws InterruptedException {
// Frame 默认的布局管理器就是 BorderLayout
Frame frame = new Frame("AWT 界面编程");
MyCanvas myCanvas = new MyCanvas();
frame.add(myCanvas);
// 自动设置 Frame 窗口合适的大小
frame.setBounds(0, 0, 300, 300);
frame.setVisible(true);
while (true) {
Thread.sleep(1000);
myCanvas.repaint();
}
}
static class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
// 绘制图形
g.setColor(Color.BLACK);
// 绘制线段
g.drawLine(10, 10, 100, 10);
// 绘制矩形
g.drawRect(10, 15, 200, 50);
// 绘制圆形
g.drawOval(50, 100, 100, 100);
}
}
}
此时就会发现 AWT 界面中一直在闪烁 ; 每次刷新都闪烁一次 ;
参考 【Java AWT 图形界面编程】Canvas 组件中使用 Graphics 绘图 ① ( AWT 绘图线程 | Component 绘图函数 ) 博客中的绘图过程分析 ,
调用 Canvas#repaint 函数 后 , 首先将组件隐藏 , 然后调用 Canvas#update 函数 ;
调用 Canvas#update 函数 后 , 首先会清除组件中的内容 , 然后调用 Canvas#paint 函数重新进行绘制 ;
Canvas#update 函数原型如下 :
public void update(Graphics g) {
g.clearRect(0, 0, width, height);
paint(g);
}
清除组件内容调用的是 Canvas#clearRect 函数 ;
调用 Canvas#repaint 函数时 , 会先将屏幕清空 , 然后再重新调用 Canvas#paint 函数进行绘制 , 此时就造成了界面闪烁的现象 ;
为了避免上述闪烁的情况 , 也就是绘制过程中 , 不出现 屏幕清空 的情况 ;
这里 引入 双缓冲 机制 , 建立一个 图片缓冲区 , 用于缓存图片 , 绘制时绘制到图片缓冲区 , 绘制完毕后再将整张图片绘制到界面中 , 这样界面中就不会出现 清空的情况 , 始终都有内容显示 , 这样就避免了图片闪烁的情况 ;
上述主要是 修改 自定义 Canvas 画布组件的 void update(Graphics g) 函数 , 按照如下进行修改 , 即可避免出现窗口闪烁的问题 ;
/**
* 图片缓冲区
*/
private Image mBufferedImage = null;
public void update(Graphics g) {
if(mBufferedImage == null) {
// 如果缓冲区没有创建, 则创建图片缓冲区
mBufferedImage = this.createImage(getWidth(), getHeight());
}
// 获取图片的绘图对象
Graphics buffer = mBufferedImage.getGraphics();
// 向缓冲区中绘制图片
paint(buffer);
// 将缓冲区中的图片绘制到窗口界面中
g.drawImage(mBufferedImage, 0, 0, null);
}
二、完整代码示例
代码示例 :
import java.awt.*;
public class HelloAWT {
public static void main(String[] args) throws InterruptedException {
// Frame 默认的布局管理器就是 BorderLayout
Frame frame = new Frame("AWT 界面编程");
MyCanvas myCanvas = new MyCanvas();
frame.add(myCanvas);
// 自动设置 Frame 窗口合适的大小
frame.setBounds(0, 0, 300, 300);
frame.setVisible(true);
while (true) {
Thread.sleep(1000);
myCanvas.repaint();
}
}
static class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
// 绘制图形
g.setColor(Color.BLACK);
// 绘制线段
g.drawLine(10, 10, 100, 10);
// 绘制矩形
g.drawRect(10, 15, 200, 50);
// 绘制圆形
g.drawOval(50, 100, 100, 100);
}
/**
* 图片缓冲区
*/
private Image mBufferedImage = null;
public void update(Graphics g) {
if(mBufferedImage == null) {
// 如果缓冲区没有创建, 则创建图片缓冲区
mBufferedImage = this.createImage(getWidth(), getHeight());
}
// 获取图片的绘图对象
Graphics buffer = mBufferedImage.getGraphics();
// 向缓冲区中绘制图片
paint(buffer);
// 将缓冲区中的图片绘制到窗口界面中
g.drawImage(mBufferedImage, 0, 0, null);
}
}
}
执行结果 :