2014-12-03 68 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代码。