简体   繁体   English

从Java中的另一个类调用重绘?

[英]Call repaint from another class in Java?

I'm probably doing this wrong, so please be nice. 我可能做错了,所以请你好。 I'm developing a Java game, and I'm at the stage of testing character movement / animation. 我正在开发一个Java游戏,我正处于测试角色移动/动画的阶段。

The "person" can move up down left and right on a grid. “人”可以在网格上向左和向下移动。 The class the grid is drawn in is the gamePanel class. 绘制网格的类是gamePanel类。 The buttons are in the gameControlPanel class. 按钮位于gameControlPanel类中。

I have a button which spawns a person on the grid. 我有一个按钮,可以在网格上生成一个人。 I then have a button to move the person up down left and right. 然后,我有一个按钮,可以将人向左和向下移动。

When the move up button is pressed, it calls the move up method from the person class. 按下向上移动按钮时,它会调用person类中的move up方法。 (At the moment, I'm only testing one "person" at a time.) In that method is the following code... (目前,我一次只测试一个“人”。)在那个方法中是以下代码......

int move = 10;
while(move!=0)
{
    setTopLeftPoint(new Point((int)getTopLeftPoint().getX(),
                              (int)getTopLeftPoint().getY() - 3));

    try
    {
        Thread.sleep(300);
    } catch (InterruptedException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
    move-=1;
}

The problem is that I can't seem to call the repaint method for the gamePanel class from within the Person class. 问题是我似乎无法从Person类中调用gamePanel类的重绘方法。 To get around this, I created a timer in the gamePanel class which repaints every 20ms. 为了解决这个问题,我在gamePanel类中创建了一个计时器,它每20ms重新绘制一次。

When I press the up button after the person is spawned, the button remains pressed down until the cycles of the while loop have been completed, and then the circle representation of the person is displayed in the grid square above. 当人物产生后按下向上按钮时,按钮保持按下直到while循环完成循环,然后人物的圆圈表示显示在上面的网格方框中。

I will try to answer any questions regarding this. 我将尝试回答有关此问题的任何问题。

repaint() does not immediately repaint the GUI. repaint()不会立即重新绘制GUI。 Rather, it posts a message to the AWT thread telling it to paint at the next convenient opportunity. 相反,它向AWT线程发布消息,告诉它在下一个方便的机会画画。 When it gets the chance, it will repaint your app. 当它有机会时,它会重新绘制你的应用程序。 However, if you do this in an event handler, then the AWT thread is already busy and you need to exit the handler to give control back to the AWT handler. 但是,如果在事件处理程序中执行此操作,则AWT线程已经忙,您需要退出处理程序以将控制权交还给AWT处理程序。

As a general rule of thumb, you don't want to do any long-running calculations on the AWT thread (including in event handlers) since these will stop the app from responding to other events until your calculations are done. 作为一般经验法则,您希望在AWT线程上(包括在事件处理程序中)执行任何长时间运行的计算,因为这些将阻止应用程序响应其他事件,直到您的计算完成为止。 This will often appear to the user as stuck buttons like you described. 对于用户来说,这通常会显示为您所描述的卡住按钮。 To get around this, use a SwingWorker which can do the calculations on a separate thread. 要解决这个问题,请使用可以在单独的线程上进行计算的SwingWorker

Finally, something to be aware (but not necessarily to change) is that timers and sleeps do not guarantee when they will awaken. 最后,需要注意的事情(但不一定要改变)是定时器和睡眠并不保证什么时候它们会被唤醒。 Rather, they guarantee that they will not waken before the amount of time elapses, but can theoretically sleep indefinitely. 相反,他们保证在经过一段时间之前不会唤醒,但理论上可以无限期地睡觉。 Also, not all machines have 1 ms timer resolution. 此外,并非所有机器都具有1 ms定时器分辨率。 In particular, on many windows machines the timers only have 55 ms resolution, so a 20 ms timer may give weird results. 特别是,在许多Windows机器上,定时器只有55毫秒的分辨率,因此20毫秒的定时器可能会产生奇怪的结果。

If you want to repaint at a certain interval, javax.swing.Timer is probably the class for you. 如果你想以一定的间隔重新绘制, javax.swing.Timer可能就是你的类。 In the specific case of repaint you can call it from a non-EDT thread, but you may get yourself into difficulty as you are now dealing with multiple threads. repaint的特定情况下,您可以从非EDT线程调用它,但是您可能会遇到困难,因为您现在处理多个线程。

I don't have much experience making games but having a loop to control all animation is a fundamental aspect of game programming. 我没有太多制作游戏的经验,但拥有一个控制所有动画的循环是游戏编程的一个基本方面。 Most simple 2d games only have 1 loop to render most of its animation. 大多数简单的2D游戏只有1个循环来渲染它的大部分动画。

In my experience a good way to render a whole bunch of stuff is to have a collection of all the entities in your game in one place and just loop over this collection passing the Graphics object to each entity. 根据我的经验,渲染一大堆东西的好方法是在一个地方拥有游戏中所有实体的集合,然后循环遍历此集合,将Graphics对象传递给每个实体。

This will allow each entity to draw itself onto the graphics object. 这将允许每个实体将自己绘制到图形对象上。 Although this is just one way to do it. 虽然这只是一种方法。

synchronized ( entities ) {
    for ( Entity e : entities ) {
        e.draw( g );
        e.doAction();
    }
}

Is the button press handled by the event-dispatch thread of your GUI? 按下按钮是否由GUI的事件派发线程处理?

If this is a case, then the repaint method on the GUI will not fire until the event dispatch thread ends (ie when the button is released and it breaks out of the loop). 如果是这种情况,那么GUI上的重绘方法将不会触发,直到事件调度线程结束(即当按钮被释放并且它突然出现循环时)。 I had this problem recently, and the best solution I can suggest is to make the class with the movement algorithm threadable and fire off a thread when the keypress is detected. 我最近遇到了这个问题,我建议的最好的解决方案是使用移动算法的类可以线程化,并在检测到按键时触发线程。 This allows the event-dispatch thread to finish and therefore allows the gui to repaint. 这允许事件派发线程完成,因此允许gui重绘。

For more information on threading see Starting a thread . 有关线程的更多信息,请参阅启动线程

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM