2014-12-03 100 views
0

我最近一直在製作遊戲,遇到了一個我無法解決的問題。我的問題是刪除JFrame的內容窗格並將其設置爲其他內容。雖然這起作用,但內容窗格類中的KeyListener不起作用,除非我將計算機上的主窗口更改爲其他內容,然後返回到JFrame。Java更改內容窗格

我的代碼比什麼是少量複製的問題本來是:

import java.awt.*; 
import java.awt.event.*; 
import javax.awt.swing.*; 

public class TheFrame extends JFrame{ 

    private JButton play; 
    private FirstPanel fp; 
    private SecondPanel sp; 

    public TheFrame(){ 

     setSize(800, 600); 
     setLocationRelativeTo(null); 
     setResizable(false); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 

     fp = new FirstPanel(); 
     setContentPane(fp); 

     setVisible(true); 
    } 

    public static void main(String args[]){ 

     TheFrame tf = new TheFrame(); 
    } 

    class FirstPanel() extends JPanel{ 

     private boolean test = false; 

     public FirstPanel(){ 

      play = new JButton("play"); 
      play.addActionListener(new PlayListener()); 
      add(play); 
     } 

     public void paintComponent(Graphics g){ 

      if(test == true){ 

       sp = new SecondPanel(); 
       removeAll(); 
       revalidate(); 
       setContentPane(sp); 
      } 
     } 

     class PlayListener implements ActionListener{ 

      public void actionPerformed(ActionEvent e){ 

       test = true; 
       repaint(); 
      } 
     } 
    } 
} 

這裏也是該類SecondPanel代碼:

import java.awt.*; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 
import javax.swing.*; 

public class SecondPanel extends JPanel implements KeyListener{ 

    private int draw = 0; 

    public SecondPanel(){ 

     addKeyListener(this); 

    } 

    public void paintComponent(Graphics g){ 

     super.paintComponent(g); 

     g.drawString("press f to draw circles", 90, 40); 

     if(draw > 0){ 

      for(int i = 0; i < draw; i++){ 

       g.drawOval((i*100)+100, (i*100)+100, 100, 100); 
      } 
     } 
    } 

    public void keyTyped(KeyEvent e){ 

     if(e.getKeyChar() == 'f' || e.getKeyChar() == 'F'){ 
      draw++; 
      repaint(); 
     } 
    } 
} 

回答

4

所以任何事情之前,這個...

public void paintComponent(Graphics g){ 
    if(test == true){ 
     sp = new SecondPanel(); 
     removeAll(); 
     revalidate(); 
     setContentPane(sp); 
    } 
} 

這非常糟糕!首先,你正在打破塗料鏈(不打電話給super.paintComponent),其次,你正在改變塗料週期內的組件狀態,這將觸發一個新的重新繪製請求,並會一次又一次地調用你的paintComponent。 ...

繪畫是繪畫組件的當前狀態,僅此而已。 NEVER從任何paint方法EVER

,而不是試圖用remove/add,可以考慮使用CardLayout而是看How to Use CardLayout內改變任何組件的狀態。這將允許您從中央控制點根據您的需要在第一個和第二個面板之間切換。

KeyListener是一個反覆無常的情婦,它一直都在關注它。它只會引發關鍵事件,如果它註冊的組件具有可聚焦性和焦點。一個更好的解決方案是使用鍵綁定API,該API旨在克服這個限制,併爲您提供對觸發相關操作所需的焦點級別的控制級別。

有關更多詳細信息,請參見How to Use Key Bindings

4

要交換容器的內容,無論是JFrame的contentPane還是任何JPanel,都可以考慮使用CardLayout,因爲此工具專門爲此作業構建。

注意,此代碼:

sp = new SecondPanel(); 
removeAll(); 
revalidate(); 
setContentPane(sp); 

應該永遠是一個方法的paintComponent裏面找到。這種方法不在我們的直接控制之下,應該只用於繪畫和繪畫。同樣,通過不叫超級的方法,你已經打破了繪畫鏈。

此外,而不是KeyListeners,使用密鑰綁定,並且您的功能應該工作。

例如,請查看我今天爲另一個similar question創建的類似CardLayout代碼。