Java更改内容窗格

Java更改内容窗格,java,swing,keylistener,contentpane,Java,Swing,Keylistener,Contentpane,我最近在做一个游戏,遇到了一个我无法解决的问题。我的问题是删除JFrame的内容窗格并将其设置为其他内容。虽然这样做有效,但内容窗格类中的KeyListener不起作用,除非我将计算机上的主窗口更改为其他窗口,然后返回JFrame 我用比原来更少的代码复制了这个问题: import java.awt.*; import java.awt.event.*; import javax.awt.swing.*; public class TheFrame extends JFrame{ p

我最近在做一个游戏,遇到了一个我无法解决的问题。我的问题是删除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();
        }
    }
}

为了交换容器的内容,无论是JFrice的内容面板还是任何JPAND,考虑使用一个卡布局,因为这个工具是专门为这个任务构建的。 请注意,此代码:

sp = new SecondPanel();
removeAll();
revalidate();
setContentPane(sp);
不应在paintComponent方法内部找到。这种方法不在我们的直接控制之下,只能用于绘画和绘画。另外,不调用super的方法,您已经打破了绘画链

另外,使用键绑定代替KeyListener,您的功能应该可以正常工作


例如,请看一下我今天为另一个用户创建的类似CardLayout代码

所以在做其他事情之前,这

public void paintComponent(Graphics g){
    if(test == true){
        sp = new SecondPanel();
        removeAll();
        revalidate();
        setContentPane(sp);
    }
}
这太糟糕了!首先,您正在断开绘制链,而不是调用super.paintComponent;其次,您正在从绘制周期内更改组件的状态,这将触发新的重新绘制请求,并将一次又一次地调用您的paintComponent

绘制用于绘制组件的当前状态,仅此而已。永远不要在任何绘制方法中更改任何组件的状态

<>而不是尝试使用Edv/Adt,而是考虑使用一个CARDFLASH,请参阅。这将允许您根据需要从集中控制点在第一个面板和第二个面板之间切换

KeyListener是一个变化无常的情妇,它需要所有的关注,所有的时间。仅当注册到的组件可聚焦且具有焦点时,它才会引发关键事件。更好的解决方案是使用key bindings API,该API旨在克服此限制,并为您提供对触发相关操作所需的焦点级别的控制

有关更多详细信息,请参阅