【问题标题】:Java Application : repaint isn't executed in While Loop?Java 应用程序:重绘不在 While 循环中执行?
【发布时间】:2011-07-22 23:01:28
【问题描述】:

我有这个Thread 应该更新游戏的元素,即重绘,等待一段时间然后再做一次,问题是它不会重绘。我已经测试了所有其他组件,它们都可以工作,但是即使我在循环中调用repaint(),paint 方法也只调用一次(因为组件是绘制的)。这是我的循环代码:

Thread t = new Thread(){
public void run()
    {
        mouse.init();
        while(true)
        {                                       
         mouse.Refresh();//Adds Dirty Regions in the RepaintManager   
        SwingUtilities.invokeLater(new Runnable() {    
       @Override 
       public void run() {              
          //What here? 
       }
    });


        }            
    }
};

无需查看线程或任何东西,它会循环。

这是绘制方法:

   @Override
public void paint(Graphics g)
{

            EndTime = System.currentTimeMillis();//For the FPS Counter
    Time = EndTime - StartTime;
    FPS = (byte) (1000/Time);   
    TotalFPS += FPS;
    TotalFrame++;   
            JPT.AverageFPs.setText( "" + TotalFPS/TotalFrame);
            JPT.CurrentFPS.setText( "" + FPS);
    StartTime = System.currentTimeMillis();

    g.clearRect(0,0,dim.width,dim.width); 


    for(int x = 0; x < Variables.Width; x++)
    {
        for(int y = 0; y < Variables.Height; y++)
        {
            if(Variables.Map[x][y] == 0)
            { 
                g.setColor(new Color(0x613F37));
                g.drawLine(x, y, x, y);
            }
            else if(Variables.Map[x][y] == 1)
            { 
                g.setColor(Color.black);
                g.drawLine(x, y, x, y);
            }
            else if(Variables.Map[x][y] == 2)
            { 
                g.setColor(new Color(0xDEDEDE));
                g.drawLine(x, y, x, y);
            }

        }
    }

        g.setColor( new Color(0.5f, 0.5f, 0.5f, 0.5f));
        g.fillRect(Variables.CurrentX, Variables.CurrentY, Variables.Zoom, Variables.Zoom);





}

非常感谢。

我还想指出,我之前将这个游戏作为 Applet 制作,它的工作原理很吸引人,但现在我需要它作为应用程序。

【问题讨论】:

  • 你为什么要重绘一个令人讨厌的数量?
  • @Moonbeam:如果这是一个令人讨厌的数量,我不想知道你可能会对我的一些代码说些什么。嗯.. FPS 计算不应该在绘制方法之外吗?精彩资源:goo.gl/3Wf1f
  • 变量名和方法名以大写字母开头是违反Java约定的。例如,Variable 似乎是一个类而不是一个对象。
  • 可能是这样,但我刚刚做到了,因为它更新了 FPS 标签,这就像“绘画”,但无论如何

标签: java swing repaint


【解决方案1】:

试试paintImmediately(0, 0, getWidth(), getHeight());

【讨论】:

  • 您必须从 EDT 调用它。查找从不同线程调用paintImmediately()。
  • @paranoid-android if(SwingUtilities.isEventDispatchThread) {...} +1
【解决方案2】:

这是因为RepaintManager 将多个请求折叠成单个重绘组件树的成员。

【讨论】:

  • 这是真的,但我相信paintImmediately 如果你使用得当,它会强制更新。
【解决方案3】:

我认为您的数据在线程之间没有同步(没有足够的代码来确定这种情况是否困难)。

repaint 在 Swing EDT 上调用,update.UpdateGravity() 在主线程中调用。我猜你的update 改变了Variable,但是你有没有同步这个数据结构,以便 Swing EDT 看到更新的值?

编辑

这是你应该做的:

variables = update.updateGravity();  // runs in your main thread
SwingUtilities.invokeLater(new Runnable() {    
   @Override public void run() {
       yourCustomSwingComponent.update(variables);   // will run on the Swing EDT
   }
}

并且yourCustomSwingComponent 包含您拥有的paint() 方法。 Swing 中有一条规则,任何 Swing 组件的状态都只能从 Swing EDT 中修改(或读取)。

您应该阅读有关 Swing 和多线程的信息。实际上,您必须了解多线程才能使用 Swing。

【讨论】:

  • 我现在没有添加超过一个线程,我只是想让它工作,然后让它变得更好
  • 在对我的代码进行了更多研究之后,我意识到你是对的,即使变量改变了,也会画出同样的东西(有点进步,因为之前没有画过一次)
  • 如果您使用的是 Swing,那么您至少使用了两个线程。 Swing 在 Swing 事件调度线程 (EDT) 中运行。
  • 您的代码给出了我的错误,但感谢您为我指明方向。是的,在那之后我开始阅读多线程,但并不那么容易。
  • 在painter类中可以成功改变和访问变量,但在外面不行
【解决方案4】:

没有直接回答这个问题,但看看一些现有的 Java2D 动画库可能会非常有用。例如,Trident 最初由 Kirill Grouchnikov 开发。如果有理由不使用它,至少检查一下来源并借用一些想法会很有用。

另外,Swing Timer 可能对实现基于时间的 Swing 相关操作有一些兴趣。

【讨论】:

  • @MasterMind555 这就是为什么使用现成的、经过良好测试的库可能更容易的原因。
猜你喜欢
  • 2018-12-12
  • 1970-01-01
  • 2014-09-10
  • 2017-06-28
  • 1970-01-01
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多