Java更改内容窗格

时间:2014-12-03 22:59:41

标签: java swing keylistener contentpane

我最近一直在制作游戏并遇到了一个我无法解决的问题。我的问题是删除JFrame的内容窗格并设置为其他内容。虽然这样做,但内容窗格的类中的KeyListener不起作用,除非我将计算机上的主窗口更改为其他内容然后返回到JFrame。

我用比原来少的代码复制了这个问题:

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();
        }
    }
}

2 个答案:

答案 0 :(得分:4)

要交换容器的内容,无论是JFrame的contentPane还是任何JPanel,请考虑使用CardLayout,因为此工具是专门为此作业构建的。

请注意以下代码:

sp = new SecondPanel();
removeAll();
revalidate();
setContentPane(sp);
永远不应该在paintComponent方法中找到

。这种方法不在我们的直接控制之下,应仅用于绘画和绘画。同样,通过不调用超级方法,你已经破坏了绘画链。

此外,使用键绑定代替KeyListeners,您的功能应该有效。

例如,请查看我今天为另一个similar question创建的类似CardLayout代码。

答案 1 :(得分:4)

所以在此之前,这......

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

这非常糟糕!首先,你打破了油漆链(不是调用super.paintComponent),其次,你是在油漆周期内改变组件的状态,这将触发一个新的重绘请求,并会调用你的paintComponent一次又一次......

绘画用于绘制组件的当前状态,仅此而已。 从不从任何paint方法 EVER

中更改任何组件的状态

请考虑使用remove,而不是尝试使用add / CardLayout,请参阅How to Use CardLayout。这将允许您根据需要在集中控制点之间切换第一个和第二个面板。

KeyListener是一个善变的情妇,它一直都想要所有的关注。如果注册的组件是可聚焦的并且具有焦点,它将仅引发关键事件。更好的解决方案是使用密钥绑定API,该API旨在克服此限制,并为您提供对触发相关操作所需的关注级别的控制级别。

有关详细信息,请参阅How to Use Key Bindings