javaGUI绘图频闪

关于JavaGUI中的频闪问题解决


今天参照B站的视频课 IT黑马javaGui教学里的p37-p40写了一个简单的桌面绘画程序,照着敲了一遍,基本功能没有问题的。但是频闪问题很头疼,有强迫症,有点不甘心。老师没交代,只好学生自己解决了,毕竟讲究面向百度,面向CSDN的年代了。

先附上我自己实现的原来代码:

package Component;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

/**
 * 位图案例:绘画板块
 * 设计步骤:
 * 1.右键弹出框,选择三原色(红、绿、蓝)
 * 2.设置BufferedImage作为图片,画图即是不断修改图片。将图片画出在Canvas上即可。
 * 3.解析绘图逻辑,利用鼠标拖动事件,传入拖动前位置与本次位置进行绘图
 *
 * @author yanjq
 **/
public class DrawDemo2 {
    String className = Thread.currentThread().getStackTrace()[1].getClassName();
    Frame frame = new Frame(className.split("\\.")[1]);

    private final int AREA_WIDTH = 500;
    private final int AREA_HEIGHT = 400;
    private final String RED = "红色";
    private final String GREEN = "绿色";
    private final String BLUE = "蓝色";

    PopupMenu popupMenu = new PopupMenu();
    MenuItem colorRedMI = new MenuItem(RED);
    MenuItem colorGreenMI = new MenuItem(GREEN);
    MenuItem colorBlueMI = new MenuItem(BLUE);

    private Color nowColor = Color.BLACK;//记录当前颜色
    private int preX = -1;//记录上一次鼠标的位置X,用于绘图
    private int preY = -1;//记录上一次鼠标的位置Y,用于绘图

    //注意传入的最后一个参数
    BufferedImage bufferedImage = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_RGB);

    //获取画笔
    Graphics g = bufferedImage.getGraphics();
    MyCanvas myCanvas = new MyCanvas();

    private class MyCanvas extends Canvas {
        @Override
        public void paint(Graphics g) {
            //参数理解:1.需要绘制的图片,绘制的起点,观察者暂未使用
            g.drawImage(bufferedImage, 0, 0, null);
        }
    }

    private void insertListener() {
        //1.菜单项目事件
        ActionListener actionListener = e -> {
            switch (e.getActionCommand()) {
                case RED:
                    nowColor = Color.RED;
                    break;
                case GREEN:
                    nowColor = Color.GREEN;
                    break;
                case BLUE:
                    nowColor = Color.BLUE;
                    break;
            }
        };
        colorRedMI.addActionListener(actionListener);
        colorGreenMI.addActionListener(actionListener);
        colorBlueMI.addActionListener(actionListener);

        myCanvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {//鼠标抬起事件
                if (e.isPopupTrigger()) { //2.鼠标右击菜单事件
                    popupMenu.show(myCanvas, e.getX(), e.getY());
                }

                //重置鼠标初始位置
                preX = -1;
                preY = -1;
            }
        });

        //3.鼠标拖动事件
        myCanvas.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {//鼠标拖动事件
                //设置画笔颜色,进行划线
                if (preX > 0 && preY > 0) {
                    g.setColor(nowColor);
                    g.drawLine(preX, preY, e.getX(), e.getY());
                }

                //若未有记录,则记录当前位置p
                preX = e.getX();
                preY = e.getY();
                myCanvas.repaint();
            }
        });
    }

    private void init() {
        insertListener();
        //组装视图
        popupMenu.add(colorRedMI);
        popupMenu.add(colorGreenMI);
        popupMenu.add(colorBlueMI);

        //设置画板初始颜色,若未设置,则默认背景为黑色(#000)
//        g.setColor(Color.WHITE);
//        g.fillRect(0, 0, AREA_WIDTH, AREA_HEIGHT);

        myCanvas.add(popupMenu);
        myCanvas.setPreferredSize(new Dimension(AREA_WIDTH, AREA_HEIGHT));

        frame.add(myCanvas);
        frame.pack();
        frame.setVisible(true);
    }


    public static void main(String[] args) {
        new DrawDemo2().init();
    }
}

基本功能没有太大毛病,但是频闪很严重,这是为什么呢?
大概看了大佬之前的研究结果,参考的以下两篇博客

javaGUi频闪
javaGUi频闪双缓冲解决

再参照老师之前课程里的教学,自己截图的笔记(调用关系图):

调用关系图
猜想大概是repaint()方法里调用的update自带的清屏所致。
下面做简单调试:
在类中的repaint()处以及Canvas中的updte()处做断点。
全黑的效果明显一点。

运行程序:
在这里插入图片描述

选择红色画笔,在画布上拖动鼠标,repaint()处F7步入,发现跳转到Canvas中的update()方法

public void update(Graphics g) {
        g.clearRect(0, 0, width, height);
        paint(g);
    }

F8执行clearRect()方法后,屏幕出现白屏
在这里插入图片描述
然后再F8执行paint(),屏幕瞬间全黑,并出现画线。
在这里插入图片描述
因此大概猜到原因了,是因为Canvas中update调用了clearRect(0, 0, width, height)导致的闪烁。我也不明白设计的初衷是什么。

既然知道问题原因了,那么尝试解决,就是在MyCanvas中重写update。

修改代码如下:

private class MyCanvas extends Canvas {
        @Override
        public void paint(Graphics g) {
            //参数理解:1.需要绘制的图片,绘制的起点,观察者暂未使用
            g.drawImage(bufferedImage, 0, 0, null);
        }

		//重写update,防止闪烁
        @Override
        public void update(Graphics g) {
            paint(g);
        }
    }

重新运行程序,一发入魂,屏幕闪烁问题解决了。清清爽爽。

第一次写博客,算不上自己的研究成果,但是问题解决了,而且感觉自己去源码中调试程序很有收获,也算锻炼了自己解决问题的思路吧。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值