【问题标题】:Java Changing Content PaneJava 更改内容窗格
【发布时间】:2014-12-03 22:59:41
【问题描述】:

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

【问题讨论】:

    标签: java swing keylistener contentpane


    【解决方案1】:

    所以首先,这个...

    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

    【讨论】:

      【解决方案2】:

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

      注意这段代码:

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

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

      此外,使用键绑定代替 KeyListeners,您的功能应该可以工作。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多