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