2012-10-17 79 views
1

我正在製作一個使用swing的遊戲畫布,並決定使用JTextField來輸入用戶名和密碼。鍵入閃爍黑色的JTextField

我正在緩衝圖像,然後將其渲染到屏幕上,而不是直接在面板上實時繪製所有內容。

我已經遇到了一個問題,雖然,我畫的背景,並已我的兩個文本字段設置爲不透明的,但似乎每次我去輸入內容的文本字段的它閃爍一個黑盒子,其中JTextField是。

它發生在我的用戶名和密碼字段。任何想到這可能是什麼原因?

其他有用的信息:每當我點擊一個文本框,這兩個組件在第一個字符將會變成黑色時閃爍。

編輯 - 我剛剛注意到登錄按鈕我也閃爍黑色當MOUSE_ENTEREDMOUSE_EXIT

public class GamePanel extends JPanel implements Runnable { 


public GamePanel(int width, int height) { 
    this.pWidth = width; 
    this.pHeight = height; 

    setController(new LoginGameController(this)); 

    setPreferredSize(new Dimension(pWidth, pHeight)); 
    setBackground(Color.BLACK); 

    setFocusable(true); 
    requestFocus(); // the JPanel now has focus, so receives key events 

    // create game components 

    addMouseListener(this); 
    addKeyListener(this); 

    setLayout(null); 

    startGame(); 
} 
private void startGame() 
    // initialise and start the thread 
    { if (animator == null) { 
     animator = new Thread(this); 
     animator.start(); 
    } 
    } 

public void run() { 
    while(true) { 
      gameUpdate(); 
      if(getGraphics() != null){ 
       gameRender(); // render the game to a buffer 
       paintScreen(); // draw the buffer on-screen 
      } 
      try { 
      Thread.sleep(28); 
      } catch (InterruptedException e) {} 
    } 
} 

private void paintScreen() { 
    Graphics2D g = (Graphics2D) getGraphics(); 

    if ((g != null) && (img != null)) 
      g.drawImage(img, 0, 0, null); 

    Toolkit.getDefaultToolkit().sync(); 
    g.dispose(); 
} 

private void gameRender() { 
    if(getWidth() > 0 && getHeight() > 0) 
     img = createImage(getWidth(), getHeight()); 

    if(img != null) { 
     Graphics2D g = (Graphics2D) img.getGraphics(); 
     g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
     g.setColor(Color.BLACK); 
     g.fillRect(0, 0, pWidth, pHeight); 

     getController().render(img); 

     paintComponents(img.getGraphics()); 


    } 
} 

} 

下面是文本字段:(從一個單獨的類完全調用到的GamePanel使用getPanel()...)

//Setup Login fields 
    usernameTF = new JTextField(); 
    usernameTF.setOpaque(false); 
    usernameTF.getCaret().setBlinkRate(0); 
    usernameTF.setForeground(Color.WHITE); 
    usernameTF.setBounds(USERNAME_FIELD); 
    usernameTF.setBorder(null); 
    getPanel().add(usernameTF); 

    passwordTF = new JPasswordField(); 
    passwordTF.setOpaque(false); 
    passwordTF.getCaret().setBlinkRate(0); 
    passwordTF.setForeground(Color.WHITE); 
    passwordTF.setBounds(PASSWORD_FIELD); 
    passwordTF.setBorder(null); 
    getPanel().add(passwordTF); 

    loginBtn = new JButton(); 
    loginBtn.setOpaque(false); 
    loginBtn.setBackground(null); 
    loginBtn.setBorder(null); 
    loginBtn.setBounds(LOGIN_BUTTON); 
    loginBtn.addMouseListener(getPanel()); 
    getPanel().add(loginBtn); 

謝謝!

+1

這聽起來像是一個不透明和/所有繪畫的問題。想要粘貼一些示例代碼,以便我們可以停止猜測 – MadProgrammer

+1

看起來您的代碼中存在一個錯誤。我敢打賭,儘管我希望我錯了,但你必須展示一些才能得到體面的回答。最好是[sscce](http://sscce.org)。 –

+0

你的代碼讓我有點擔心,是否有可能看到至少主要的渲染實現以及如何構建UI,請 – MadProgrammer

回答

3

最基本的問題是,當你更新你的圖形時,你規避了Swings重繪過程並且不遵守EDT。

JComponent#getGraphics是一個臨時/暫存緩衝區,將在下一次重繪時重新繪製。另外,如果你沒有創建圖形,你不應該處理它!

public void run() { 
    while(true) { 
      gameUpdate(); 
      if(getGraphics() != null){ 
       gameRender(); // render the game to a buffer 
       try { 
        SwingUtilities.invokeAndWait(new Runnable() { 
         public void run() { 
          paintScreen(); // draw the buffer on-screen 
         } 
        }); 
       } catch (Exception exp) { 
        exp.printStackTrace(); // please clean this up 
       } 
      } 
      try { 
      Thread.sleep(28); 
      } catch (InterruptedException e) {} 
    } 
} 

我不知道這是否會解決它,但它不能傷害。 (這會影響你的FPS,你應該考慮到過了多長時間畫,你想等待多久)

Alternativly,而不是叫paintScreen(),你可以調用repaint(或有paintScreen做)和重寫paintComponent方法來繪製緩衝區。

這將允許Swing正確恢復對繪製過程的控制。

+0

只是想讓你知道,我接受了你的建議,並使其成爲我在面板中重寫paint(Graphics g)方法的工具,它偶爾會出現閃光,效果更好。但是,我確實知道爲什麼會這樣。我認爲img字段在調用paint(Graphics)方法時沒有完成痛苦,因此它們未被同步。不過,我非常感謝你的幫助! – cdog5000

+0

@cdog:不,不要重寫'paint(...)'否則你會失去雙緩衝並獲得非常不連貫的動畫。而是像MadProgrammer已經推薦的那樣重寫JPanel的'paintComponent(...)'方法(!),並且不要忘記調用super方法。 –

+0

有一種方法來禁用重繪過程,但我現在找不到它。 –

2

窗口或組件至少有三種重新繪製方法。

  1. 按需從操作系統中丟失一部分窗口緩衝區。
  2. 當圖書館組件改變其狀態時,按需提供。
  3. 通過操作自己的幀緩衝區手動。

通常,下面的途徑活性:

操作系統可以請求特定的矩形被更新。這是由工具包拾取的。此外,組件可以通過其repaint方法將其更改標示給工具包。該工具包不斷收集合並傳入重繪請求一段時間,然後要求窗口重新繪製一個特定的矩形。該窗口的默認操作是通過調用其自身的paintComponent方法來繪製自己,該方法不與實體兒童重疊,然後遞歸地繪製其組件。

如果你做你自己的渲染,工具包也在做它。由於您沒有覆蓋您的paintComponent,因此此方法運行時,它將作爲默認值。默認的操作是什麼都不做。工具包然後拾取空幀緩衝區並將按鈕(不繪製其背景)塗在它上面。

您可以禁用該工具包的渲染過程並自己執行所有渲染(獲取一個緩衝區,將其繪製,然後提交)。您可以調用setIgnoreRepaint(true)方法來忽略操作系統的請求。