0

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

2 回答 2

4

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

请注意,此代码:

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

永远不应该在 paintComponent 方法中找到。这种方法不是我们直接控制的,应该是绘画和绘画。同样通过不调用 super 的方法,你已经打破了绘画链。

此外,不要使用 KeyListeners,而是使用 Key Bindings,您的功能应该可以工作。

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

于 2014-12-03T23:06:18.243 回答
4

所以在此之前,这...

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

这非常糟糕!首先,您正在破坏绘制链(而不是调用super.paintComponent),其次,您正在从绘制周期内更改组件的状态,这将触发一个新的重绘请求,paintComponent并一次又一次地调用您的...... .

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

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

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

有关更多详细信息,请参阅如何使用键绑定

于 2014-12-03T23:07:29.660 回答