Java 图形事件未按我期望的顺序发生

标签 java graphics repaint

所以我正在制作图形纸牌游戏。每张卡片都是一个 JPanel,带有一个按钮和两个与之关联的图像。我有一个翻转方法,这是单击卡片时我在 Action 监听器中调用的第一个方法。

public void flip()
{
    if(b1.getIcon() == card2) b1.setIcon(card1);
    else b1.setIcon(card2);
    revalidate();
    repaint();
}

但是,由于某种原因,直到我调用此方法后的某个时刻,卡片才会翻转(意味着图标不会改变)。例如,当我在调用 flip 之后放置一个 Thread.sleep 时,我会假设我的程序会在 flip 完成后暂停,但事实并非如此!它在图像尚未切换的情况下 hibernate ,并且仅在 hibernate 时间结束后才切换一些图像。

当我在这个纸牌游戏中让人类玩 AI 时,这会导致一些重大问题,因为 AI 事件发生在纸牌在屏幕上翻转之前,即使我在执行任何 AI 代码之前调用 flip() 也是如此。谁能告诉我这里发生了什么?

最佳答案

Repaint 是对 Swing 的重绘请求,而不是对重绘的调用。在幕后,repaint() 正在将重绘作业发布到事件队列中。除了重绘工作之外,鼠标移动、鼠标点击、键盘 Activity 等内容也发布在那里。 Swing 线程出现并定期执行该队列中的作业以重绘 UI,将鼠标和键盘事件传递给组件等。事实上,swing 线程非常频繁地传递这些事件,但这仅取决于您的 UI 正在做多少工作在那个 Swing 线程上。当它发送鼠标点击、键盘事件和重绘时,它无法从该队列中读取。因此,如果您的代码需要很长时间来响应任何事件,那么 swing 及时响应新事件的能力就会降低或全部被阻止。

这就是为什么如果您使用 Swing 事件分派(dispatch)线程通过网络执行阻塞服务调用,您的 UI 将停止绘制,直到该调用返回。这就是为什么将网络调用等长时间运行的作业移出 Swing 线程并在调用返回时使用 SwingUtilities.invokeLater() 以便您可以更新事件线程上的 UI 很重要。 (invokeLater() 通过将作业发布到我们上面讨论的 Swing 事件队列来完成此操作)。

这也是为什么在 Swing 事件线程上调用 sleep 是一个糟糕的想法的原因。如果您将该线程置于 hibernate 状态,它就无法为队列中的事件提供服务。当 Swing 线程处于 hibernate 状态时,您请求的 repaint() 不会完成。

首先移除你的 sleep 调用。第二。在执行更多逻辑之前,不要编写依赖于绘制完成的代码。 Repaint 和 revalidate 是特殊的调用,Swing 将合并请求以重新绘制/重新验证,因此它不会连续重绘 10 次(浪费重要的 CPU 时间)。

Swing 无法重绘面板,直到您让调用您的线程离开它首先调用您的方法。线程越早离开该方法,您的 repaint() 就会越早发生。

您还没有解释为什么要立即重绘,所以我无法就如何构建代码给您任何建议,因此您不必关心它。但我告诉你,你不应该在意重绘还没有发生。

关于Java 图形事件未按我期望的顺序发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13476862/

相关文章:

java - 无法解析 : Lcom/google/common/collect/ImmutableMap; at com. my.app.di.DaggerMyApplicationComponent.getMapOfClassOfAndProviderOfFactoryOf(

java - 不使用 Intent 移动包 - android

Java - repaint() 方法被调用一次,然后它不显示任何内容

ios - 重绘速度减慢仅在子对象未转换时发生

Java使对象立即出现

Java 32 位 Xmx 与 Java 64 位 Xmx

java - 单个字符串中的多个字符串替换生成所有可能的组合

c# - 如何在调整 PictureBox 大小时使矩形移动

c# - 自定义控件 OnPaint 不触发

MATLAB 旋转 xtick 标签