2013-05-31 97 views
0

我正試圖在JFrame上設置一個簡單的時間報價器。我能夠顯示計數器的初始值,但後續更改不會在JFrame上更新。任何推動我對錯誤的答案,將不勝感激。我認爲這是重繪()沒有得到所謂的問題,但我不是結了錯誤,或者什麼,如果我嘗試把它JFrame repaint();如何用線程信息更新JFrame?

package com.game.ryan; 
import java.awt.Dimension; 
import javax.swing.JFrame; 
class Screen extends JFrame{ 


private Dimension d = new Dimension(800,600); 
private JFrame f; 

public Screen(){ 
    f = new JFrame(); 
    f.setIgnoreRepaint(false); 
    f.setResizable(false); 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    f.setMinimumSize(d); 
    f.setLocationRelativeTo(null); 
    f.add(new MyPanel()); 
    f.pack(); 
    f.setVisible(true); 
} 

public static void main(String[] args){ 
    Screen s = new Screen(); 
} 

} 

我也有。

package com.game.ryan; 

import java.awt.Graphics; 

import javax.swing.JPanel; 

public class MyPanel extends JPanel{ 

private OneThread ot = new OneThread(); 
private int counter = ot.getThreadCounter(); 

public MyPanel(){ 
    Thread t1 = new Thread(new OneThread()); 
    t1.start(); 

} 

public void paintComponent(Graphics g){ 
    g.drawString("TIME: ", 10, 20); 
    g.drawString(Integer.toString(counter), 50, 20);   
} 
} 

和終於

package com.game.ryan; 

public class OneThread implements Runnable{ 

private int counter = 45; 

public OneThread(){ 

} 

@Override 
public void run() { 

    for(int x = 0; x >= 0; x++){ 
     try{ 
      Thread.sleep(1000); 
      counter++; 
      x++; 
      System.out.println(counter); 

     }catch(Exception e){ 
      e.printStackTrace(); 
     } 
    }  
} 

public int getThreadCounter(){ 
    return counter; 
} 
} 

我越來越增加計數器在控制檯上,所以我猜那部分工作正常。

預期的結果是計數器在JFrame中正確顯示(每1000毫秒更新一次)。

回答

2

我沒有看到任何地方你告訴UI它應該更新自己。

你也正在走很長的路,以複製API中已有的內容。

擺動和線程需要仔細考慮。 Swing使用單線程模型來管理UI的所有更新。預計所有使用UI的迭代都將在線程的上下文中完成(AKA The Event Dispatching Thread)。

這意味着無論何時您想從任何其他線程創建或更新UI,都需要將呼叫同步回EDT。

雖然有多種方式來實現這一點,在使用javax.swing.Timer

import java.awt.BorderLayout; 
import java.awt.EventQueue; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.text.DateFormat; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class LabelClock { 

    public static void main(String[] args) { 
     new LabelClock(); 
    } 

    protected static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm.ss"); 
    private JLabel clock; 

    public LabelClock() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       clock = new JLabel(); 
       tick(); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new GridBagLayout()); 
       frame.add(clock); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

       Timer timer = new Timer(500, new ActionListener() { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         tick(); 
        } 
       }); 
       timer.setRepeats(true); 
       timer.setCoalesce(true); 
       timer.start(); 
      } 
     }); 
    } 

    protected void tick() { 
     clock.setText(DATE_FORMAT.format(new Date())); 
    } 

} 
+0

'SwingUtiltities .invokeLater'委託給'EventQueue.invokeLater',所以在這方面沒有什麼... – MadProgrammer

+0

非常感謝你們。我一直都很沮喪地看着影片,並決定嘗試一些東西。我想你得從某個地方開始。 –

2

你不妨重新考慮你的設計:

  • 一個原始變量保存的值,就​​是這樣。如果將基元所保存的值分配給另一個變量,稍後更改原始變量將不會影響另一個變量所持有的值。例如,代碼中的任何內容都不會更改由JPanel持有的計數器變量所持有的值。
  • 請注意,即使您的計劃成功,您也有兩個完全獨立的OneThread對象,並且更改其中一個的狀態對另一個沒有影響。
  • 更好地讓你的GUI監聽變量的變化,然後讓你的線程改變變量的狀態,然後通知所有監聽器這個變化。 PropertyChangeListener可以很好地工作。
  • 請注意,Swing Timer將更容易實現後臺線程。
+1

+1最簡單的,你的情況謝謝你說的一切,我想...第一;) – MadProgrammer