【问题标题】:Java applet blinking on MacJava 小程序在 Mac 上闪烁
【发布时间】:2012-05-06 15:44:32
【问题描述】:

这个问题很奇怪。该问题并非在每个平台上都会出现。它发生在我使用 MacOSX 的 Google Chrome 中,但它不会发生在 Safari 中。对于使用 Windows 的朋友来说,在 Google Chrome 上它可以完美运行。我还有一个使用 MacOSX 的朋友,对他来说,它在 Chrome、Safari 和 Firefox 上闪烁。我们都有 MacOSX Lion。我没有看到任何链接。 请大家测试一下并报告它是否发生,以及您的平台是什么(最多应该在 30 秒内发生)?


我找到了this thread on Oracle's forums。显然,这是 MacOSX 上的一个众所周知的问题,因为 Java 创建了一个子进程,而 Safari 不允许将此作为​​安全功能。然而,这个问题也出现在 Mac 上的 Chrome 和 Firefox 中(对于我来说,Safari 上没有)。想想看……我很高兴听到任何人对此的看法。


我目前正在制作一个小型 Java 俄罗斯方块游戏,我的问题是在小程序版本(扩展 JApplet)中屏幕偶尔会闪烁。当我在计算机上的 JFrame 中运行它时,一切正常。

这个小程序可以在这个网站上查看和使用:http://mtetris.herokuapp.com/(我不是要宣传或推广任何东西,我只是把它放出来,让人们可以真正看到问题所在)。

(还有另一个问题是,当小程序没有自动加载时,它没有正确获得鼠标焦点——即当浏览器阻止它并询问用户是否允许加载它时。如果“启动级别”数字没有正确突出显示,这就是原因。)

以下是我尝试过的未能解决闪烁问题的方法:

  • 将小程序的背景、根窗格、内容窗格以及小程序中的每个组件设置为黑色。
  • 覆盖小程序的paint() 方法并在其中进行双缓冲(我在当前代码中对此部分进行了注释,因为它没有任何改进)
  • 覆盖小程序的update()方法,直接在里面调用paint()(这个问题现在已经修复according to the method description in the official documentation

整个源代码可以在 github this page 上找到。扩展 JApplet 的类是 TetrisApplication。源代码还不是很干净,所以很抱歉。


这就是我实现双缓冲的方式

public class TetrisApplication extends JApplet {

    //  the dimension of the applet
    private Dimension dimension;
    // image used for double buffering
    Image offscreen;
    // the second buffer
    Graphics bufferGraphics;

    public void init() {
        super.init();
        dimension = getSize();
        offscreen = createImage(dimension.width, dimension.height);
        bufferGraphics = offscreen.getGraphics();
        ...
    }

    public void paint(Graphics g){
        bufferGraphics.clearRect(0, 0, dimension.width, dimension.height);
        super.paint(bufferGraphics);
        g.drawImage(offscreen, 0, 0, this);
    }
    ...
}

【问题讨论】:

  • 我假设现在已经修复了?我玩了你的游戏大约 10 分钟,没有看到任何闪烁。
  • @Danation 非常感谢您测试它。请参阅我上面的编辑 2(在帖子的开头)。问题不会发生在每个人身上。我完全不明白。
  • 我在尝试打开游戏页面时总是出错,为什么会这样,这就是我得到的ERROR,这些DETAILS
  • @nIcEcOw 拖动选择控制台的内容,可以复制。 OP 你在代码中使用getResourceAsStream 吗?至于显示的错误,即使是受信任的小程序也不允许退出 VM。您是否启动任何帧,并设置默认关闭操作?否则这个电话是从哪里来的?
  • @nIcEcOw 刚刚修复了这个问题,这是由于输入流并不总是支持标记/重置(加载音频数据时)。见here。你能再试一次,看看是否能解决问题?

标签: java swing japplet flicker


【解决方案1】:

为了更平滑的绘制,覆盖JPanelpaintComponent()方法,默认是双缓冲的。这个answer 讨论了一个例子。

【讨论】:

  • 我认为这就是我所做的,但我不确定我是否完全理解你。我在 JPanels 的 paintComponent() 中进行自定义绘画,如您所见here(我在其中绘制游戏板、棋子和块)、here(侧面板)。我不会覆盖小程序的paint() 方法,您可以查看here。我做得对吗?
【解决方案2】:

要停止轻弹,您需要对绘图表面进行双重缓冲。您确定您第一次正确实施了吗?

也许这会有所帮助:https://gamedev.stackexchange.com/questions/18661/how-do-i-prevent-flickering-when-drawing-to-a-jpanel

【讨论】:

  • 感谢您的回答。但是,我完全使用您的源代码来实现双缓冲。我刚刚编辑了我的帖子,这样你就可以看到我做了什么,你能检查一下它是否正确?再次感谢
  • @Rez 遗憾的是我不知道 swing api,这只是一个有根据的猜测。
【解决方案3】:

我注意到在GameController 中您正在使用后台线程(在SwingWorker 中)来更新状态。我怀疑在paint()GamePanel 期间发生更新时您可能遇到同步问题。

更好的方法可能是将所有内容推送到 EDT,使用 java.swing.Timer 触发每一帧并导致状态更新,然后使用 repaint()。那么就没有同步问题了。

【讨论】:

  • 好的,我要试试这个,看看是否有帮助,谢谢。我知道这可能会导致同步问题,但是我看不出它会如何导致闪烁(这意味着出现全白屏幕)?我所期望的是,一块可以部分绘制在一个位置,部分绘制在另一个位置(因为可以在绘制过程中更新状态)但没有空白屏幕?
  • 我只是按照你的建议去做——在 EDT 中使用 Swing Timers 做所有事情。它没有解决问题:-(。我在 github 上更新了我的代码(所以如果你愿意,你可以检查我是否做对了)并在我提供的站点上更新了小程序。但是我会保留我的我认为像这样的游戏(全部在 EDT 中),因为它的效果即使不是更好也一样好。所以,谢谢你:)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
  • 2010-10-12
  • 2014-06-11
  • 1970-01-01
  • 2012-08-27
  • 2015-05-29
相关资源
最近更新 更多