Java图形事件不按我期望的顺序发生 [英] Java graphics events not occurring in the order I expect them to

查看:108
本文介绍了Java图形事件不按我期望的顺序发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

但是,由于某种原因,卡片没有翻转(意味着图标没有改变),直到我调用此方法后的某个点。例如,当我在调用flip之后放置一个Thread.sleep时,我会认为我的程序在翻转完成后会暂停,但它不会!它睡觉的图像尚未切换,只有在睡眠时间结束后才将它们切换一些。



当我有人操作时,这会导致一些主要问题这个纸牌游戏中的人工智能,因为在扑克牌在屏幕上翻转之前AI事件正在发生,即使我在执行任何AI代码之前调用flip()。任何人都可以告诉我这里发生了什么吗?

解决方案

Repaint是一个请求Swing重绘而不是呼叫重绘。在封面下,repaint()将重绘作业发布到事件队列中。随着重绘工作,像鼠标移动,鼠标点击,键盘活动等也张贴在那里。 Swing线程周而复始地从该队列中执行作业来重新绘制UI,向组件传递鼠标和键盘事件等。实际上,swing线程经常提供这些事件,但这取决于您的UI在做什么工作在那个Swing线程上。当它不提供鼠标点击,键盘事件和重绘时,它无法从该队列中读取。所以如果你的代码需要很长时间才能回应任何事件,那么swing对于新事件的及时响应的能力就会降低,或者全部被阻止。



这就是为什么如果你执行通过网络使用Swing事件调度线程阻塞服务调用,直到该调用返回,您的UI停止绘图。这就是为什么它重要的是移动长时间运行的作业,如网络调用关闭Swing线程,并在调用回来时使用SwingUtilities.invokeLater(),以便您可以更新Event线程上的UI。 (invokeLater()通过在我们上面提到的Swing事件队列中发布一个工作来实现这一点)。

这也是为什么在Swing中调用睡眠是一个可怕的想法事件线程。如果您让该线程进入睡眠状态,则无法为队列中的事件提供服务。并且您要求的repaint()不会在Swing线程处于睡眠状态时完成。



首先删除您的睡眠呼叫。第二。在执行更多逻辑之前,不要编写依赖绘画的代码来完成。重绘和重新验证是特殊调用,Swing会将请求合并为重绘/重新验证,因此它不会在连续重绘10次(浪费重要的cpu​​时间)。



Swing无法重新绘制面板,除非您让调用线程的线程保留它首次调用的方法。线程越早离开该方法越早重绘()将发生。

你没有解释为什么你要重绘立即发生,所以我不能给你任何关于如何构造你的代码的建议,所以你不关心它。但我告诉你,你不应该在意重绘还没有发生。


So I'm making a graphical card game. Each card is a JPanel with a button and two images associated with it. I have a flip method, which is the first thing I call in my action listener when a card is clicked on.

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

However, for some reason the card doesnt flip (meaning the icons don't change) until some point after I call this method. For example, when I put a Thread.sleep after I call flip, I would assume that my program would pause after flip is completed, but it doesnt! It sleeps with the images not yet switched, and only switches them some at point after the sleep time has ended.

This is causing some major problems when I have a human play an AI in this card game, because AI events are happening before cards flip on the screen, even though I am calling flip() before I do any AI code. Can anyone clue me in as to what is going on here?

解决方案

Repaint is a request to Swing to redraw not a call to redraw. Under the covers repaint() is posting a repaint job onto a queue of events. Along with that repaint job things like mouse moves, mouse clicks, keyboard activites, etc are posted there too. The Swing thread comes by and periodically executes jobs from that queue to redraw the UI, deliver mouse and keyboard events to components, etc. In fact the swing thread delivers these events quite frequently, but it just depends on how much work your UI is doing on that Swing thread. When it's out delivering mouse clicks, keyboard events, and redraws it can't read from that queue. So if your code takes a long time to repsond to any event the ability for swing to respond timely to new events is reduced or all together blocked.

That's why if you execute a blocking service call over the network with the Swing event dispatch thread your UI stops drawing until that call returns. This is why its important to move long running jobs like network calls off the Swing Thread, and use SwingUtilities.invokeLater() when the call comes back so you can update the UI on the Event thread. (invokeLater() does this by posting a job onto the Swing event queue we talked about above).

This is also why it's a terrible idea to call sleep on the Swing event thread. If you put that thread to sleep it can't service events from the queue. And the repaint() you requested isn't going to be done while the Swing thread is sleeping.

First remove your sleep call. Second. Don't write code that depends on painting to finish before executing more logic. Repaint and revalidate are special calls, and Swing will combine requests to repaint/revalidate so it doesn't redraw 10 times in a row (wasting vital cpu time).

Swing can't redraw your panel until you let the thread that called you leave the method it first called you back on. The sooner the thread leaves that method the sooner your repaint() will happen.

You haven't explained why you want the repaint to happen immediately so I can't give you any advice on how to structure your code so you don't care about it. But I'm telling you, you shouldn't care that the repaint hasn't happened yet.

这篇关于Java图形事件不按我期望的顺序发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆