zoukankan      html  css  js  c++  java
  • Java swing JFrame用repaint出现闪烁的问题解决

    这几天用swing写登录页面背景动图的时候发现一直会有闪烁(我的类是继承JFrame),就来搜原因后发现好像是因为repaint会调用update()方法中的清屏操作导致闪烁。

    我当时看的是这个文章

    穆梓先生-java 双缓冲技术解决屏幕闪烁问题

    于是按照他的方法重写了update方法,却发现问题没解决

    public void paint(Graphics g) {
    		g.drawImage(skyImag.getImage(), skyX, skyY, null);
    		g.drawImage(groundImag, groundX, groundY, null);
    		g.drawImage(dinosaurImag.getImage(), dinoX, dinoY, null);
    	}
    public void update(Graphics g) {
    		System.out.println("==1==");//这个是我拿来测试会不会调用的输出信息
    		if (groundImag == null) {
    			System.out.println("==2==");
    			//这句话从没输出过,说明了JFrame不会执行清屏操作,即groundImag != null,而Frame跟JPanel好像会执行清屏操作
    			groundImag = this.createImage(500, 500); // 新建一个图像缓存空间,这里图像大小为800*600,为了使这句话没问题,我把我的对象从ImagIcon对象改成Imag对象
    			}
    			Graphics gImage = groundImag.getGraphics(); // 把它的画笔拿过来,给gImage保存着
    			paint(gImage); // 将要画的东西画到图像缓存空间去
    			g.drawImage(groundImag, 0, 0, null); // 然后一次性显示出来
    		
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    于是我又继续查文章,我发现没什么人用JFrame出现闪烁现象(我上次写飞机大战都没闪烁的说!),所以我查文章的时候放大范围,只要是Java swing编程出现闪烁的文章我都看一遍过去,终于让我看到这个大佬的文章

    ydcun-双缓冲原理在awt和swing中实现消除闪烁的方法

    就是他做的测试,让我知道原来在JFrame中repaint()的时候update()方法就没被调用到,JFrame消除闪烁是在update()中“直接调用了paint()函数而没有clearRect(),也就是清屏的方法,这里他试图不通过清屏来阻止闪烁的发生。”

    所以到底是哪一步出问题了。。paint()方法已经被我重写了是不会有清屏操作的,问题感觉只能出在repaint()上,看了repaint()的代码好像也没发现类似清屏的代码,我能力有限,还在学习中,有大佬知道咋回事就求赐教一下QWQ,为了方便大家找repaint()有没有问题我就把代码贴上来吧

    public void repaint(long tm, int x, int y, int width, int height) {
            if (this.peer instanceof LightweightPeer) {
                // Needs to be translated to parent coordinates since
                // a parent native container provides the actual repaint
                // services.  Additionally, the request is restricted to
                // the bounds of the component.
                if (parent != null) {
                    if (x < 0) {
                        width += x;
                        x = 0;
                    }
                    if (y < 0) {
                        height += y;
                        y = 0;
                    }
    
                    int pwidth = (width > this.width) ? this.width : width;
                    int pheight = (height > this.height) ? this.height : height;
    
                    if (pwidth <= 0 || pheight <= 0) {
                        return;
                    }
    
                    int px = this.x + x;
                    int py = this.y + y;
                    parent.repaint(tm, px, py, pwidth, pheight);
                }
            } else {
                if (isVisible() && (this.peer != null) &&
                    (width > 0) && (height > 0)) {
                    PaintEvent e = new PaintEvent(this, PaintEvent.UPDATE,
                                                  new Rectangle(x, y, width, height));
                    SunToolkit.postEvent(SunToolkit.targetToAppContext(this), e);
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    接下来我继续说说我是怎么解决这个问题的,在ydcun大佬那边是有讲他的解决方案的,我还没试过(因为凌晨3点了都!我写完立马睡觉!),我当时(凌晨2点)就想着既然不会去调用update(),那我手动调用不就好了?

    于是

    public void paint(Graphics g) {
    		g.drawImage(skyImag.getImage(), skyX, skyY, null);
    		g.drawImage(groundImag, groundX, groundY, null);
    		g.drawImage(dinosaurImag.getImage(), dinoX, dinoY, null);
    		update(getGraphics());//跟JPanel不同,JFrame的repaint方法不会自动调用update方法。所以我这边直接让它调用了。
    		//而且参数不能用g得用getGraphics()
    
    	}
    
    	public void update(Graphics g) {
    //		System.out.println("==1==");
    //		if (groundImag == null) {
    //			//System.out.println("==2==");
    
    //			groundImag = this.createImage(500, 500); }// 新建一个图像缓存空间,这里图像大小为800*600
    			//Image对象在这边也会出问题
    			//报getGraphics() not valid for images created with createImage(producer)
    			//得改成BufferedImage,但是我懒得改,所以我直接全注释了
    			
    //			Graphics gImage = groundImag.getGraphics(); // 把它的画笔拿过来,给gImage保存着
    //			paint(gImage); // 将要画的东西画到图像缓存空间去
    //			g.drawImage(groundImag, 0, 0, null); // 然后一次性显示出来
    
    	}
    	//为了实现动画效果我写了个计时器来repaint()
    	public void startTimeTask() {
    		Timer timer = new Timer();
    		TimerTask task = new TimerTask() {
    			@Override
    			public void run() {
    				skyMove();
    				groundMove();
    				dinoMove();
    				repaint();
    			}
    		};
    		timer.schedule(task, 10, 20);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    对,我调用了一个什么东西都没有的update()方法,就解决了闪烁的问题。。。但是如果我调用系统的update()

    public void update(Graphics g) {
            paint(g);
        }
    
    • 1
    • 2
    • 3

    就会更闪烁然后报错
    Java HotSpot(TM) 64-Bit Server VM warning: Potentially dangerous stack overflow in ReservedStackAccess annotated method sun.java2d.d3d.D3DBlitLoops.IsoBlit(Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/image/BufferedImage;Ljava/awt/image/BufferedImageOp;Ljava/awt/Composite;Lsun/java2d/pipe/Region;Ljava/awt/geom/AffineTransform;IIIIIDDDDZ)V [1] Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:714) at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:937) at java.base/java.util.concurrent.locks.ReentrantLock$Sync.lock(ReentrantLock.java:153) at java.base/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:322) at java.desktop/sun.awt.SunToolkit.awtLock(SunToolkit.java:195) at java.desktop/sun.java2d.pipe.RenderQueue.lock(RenderQueue.java:112) at java.desktop/sun.java2d.d3d.D3DBlitLoops.IsoBlit(D3DBlitLoops.java:313) at java.desktop/sun.java2d.d3d.D3DTextureToSurfaceScale.Scale(D3DBlitLoops.java:768) at java.desktop/sun.java2d.pipe.DrawImage.scaleSurfaceData(DrawImage.java:1001) at java.desktop/sun.java2d.pipe.DrawImage.renderImageScale(DrawImage.java:647) at java.desktop/sun.java2d.pipe.DrawImage.tryCopyOrScale(DrawImage.java:319) at java.desktop/sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:258) at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:76) at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1027) at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3425) at java.desktop/sun.awt.image.ImageRepresentation.drawToBufImage(ImageRepresentation.java:813) at java.desktop/sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:1034) at java.desktop/sun.java2d.pipe.ValidatePipe.copyImage(ValidatePipe.java:186) at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3425) at java.desktop/sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3401) at cn.zhetech.BackImag.paint(UserLogin2.java:276) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283) at java.desktop/javax.swing.JFrame.update(JFrame.java:469) at cn.zhetech.BackImag.paint(UserLogin2.java:283)

    窗口也关不掉,只能从控制台强制停止运行。。。

    等日后有大佬评论教我了或者我自己学习到了再补充一下这个原因,碎觉,溜了||ヽ( ̄▽ ̄)ノミ|Ю,狗命要紧

    如果文章有帮到你或者给你提供了思路,那就送我个赞呗(◦˙▽˙◦),不然我就默认每个浏览的都是想点然后忘了(自欺欺人,bushi)
    懂得都懂

    原文章:https://blog.csdn.net/qq_38677092/article/details/112092928

  • 相关阅读:
    快速排序
    归并排序
    python module的结构
    HTTPResponse.read([amt]):只能read一次
    本地文件上传到远程服务器
    HTTP POST发消息
    64. 最小路径和-python
    322.零钱兑换-python
    把二叉树打印成多行 -python
    按之字形顺序打印二叉树 -python
  • 原文地址:https://www.cnblogs.com/tfil/p/14228201.html
Copyright © 2011-2022 走看看