2015-07-21 57 views
0

显示图像所以我试图显示一个图像(ball),我最终将控制用户输入。要知道,图像只是使用线程的睡眠方法在间隔内显示。使用EventDispatchThread vs

我做了2班,一个扩展JPanel和其他扩展JFrame。 的JPanel子类看起来是这样的:

public class BallPanel extends JPanel { 
    private Image ball; 
    private int x,y; 
    public BallPanel(){ 
     try { 
      ball=ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\ball.png")); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     x=10; 
     y=10; 
     Thread thread = new Thread() { 
      @Override 
      public void run(){ 
        loop(); 
     } 
     }; 
     thread.start(); 
    } 
    public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     g.drawImage(ball,x,y,null); 
    } 
    public void loop(){ 
     while(true){ 
      repaint(); 
      try { 
       Thread.sleep(10); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

在循环方法我称之为sleep方法,以允许repaint被称为过间隔。然后,在构造函数中调用loop()

JFrame子类看起来是这样的:

public class BallFrame extends JFrame { 

    public BallFrame(){ 
     setVisible(true); 
     setSize(800,800); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setContentPane(new BallPanel()); 
    } 
    public static void main(String args[]){ 
     //SwingUtilities.invokeLater(new Runnable() { 
      // @Override 
       // public void run() { 
        new BallFrame(); 
       // } 
    //}); 

} 
} 

现在有趣的,或者是令人困惑的事情是,当我运行的代码,因为它是在这里显示,与注释掉的匿名内部类,球并不总是出现。有时我需要在显示球之前重新调整帧的大小(例如,调用repaint)。但是,当我通过使用匿名内部类的调度线程调用它时,每次运行代码时都会出现球。这是什么原因?

+0

1)见[检测/修复一个代码块的吊闭括号](http://meta.stackexchange.com/q/251795/ 155 831)对于一个问题,我不能再纠缠于此。 2)为了更快地获得更好的帮助,请发布[MCVE](http://stackoverflow.com/help/mcve)(最小完整可验证示例)或[SSCCE](http://www.sscce.org/)(简称,自包含,正确的例子)。 3)例如获取图像的一种方法是热链接到[本问答](http://stackoverflow.com/q/19209650/418556)中看到的图像。 –

回答

2

它与美国东部时间内的用户界面启动或没有关系(尽管您应该引起这可能会导致很多其他奇怪和有趣的问题),而且更多的是与您之前拨打setVisible的事实有关已经建立了用户界面的内容。

这可能是系统试图获得EDT启动并运行,操作系统调用它的建立之前响应之间的竞争条件的例子。

在这两种情况下,你应该从美国东部时间内启动UI,并呼吁setVisible最后。

Swing可能懒得更新UI,这实际上是一个故意的设计选择以及一个好主意。您并不总是希望在每次更改后都更新UI(如添加/删除组件),因此它将一些控件交给开发人员决定何时最好到revalidate容器层次结构和请求repaint s

我也避免使用Thread来更新UI的状态,因为这可能会导致脏画面,因为Swing使用被动呈现方法(在感觉需要时绘画),并考虑使用从EDT内更新的Swing Timer使用BufferStrategy和采用活性渲染方法,然后可以控制

+0

在最后一段中,您是指BallPanel构造函数中的线程还是循环方法中的sleep()调用,还是两者都引用? –

+0

我一般指的是使用一个'Thread',它根本什么也不做,但它可能会修改'paintComponent'可能需要的一些变量,以便更新UI的状态,这可能会产生另一种竞争条件。 – MadProgrammer