然而,我真的很想了解为什么我的代码不起作用。正如在这个问题的其他版本中所回答的那样, CardLayout 可能就足够了,但在我的情况下,我不确定它是否理想。无论如何,我感兴趣的是从概念上理解为什么这不起作用。
我有一个 JFrame,它的内容窗格监听关键事件。当在内容窗格中按下某个键时,内容窗格会告诉 JFrame 使用新的内容窗格更新自身。这是问题的一个简单示例:
此代码是完全可编译的。您可以复制粘贴它并按原样运行它。
这是我的 JFrame:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class SimpleSim extends JFrame{
private static SimpleSim instance = null;
public static SimpleSim getInstance(){
if(instance == null){
instance = new SimpleSim();
}
return instance;
}
private SimpleSim(){}
public void initialize(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setExtendedState(Frame.MAXIMIZED_BOTH);
this.pack();
this.setVisible(true);
update();
}
public void update(){
System.out.println("SIMPLE_SIM UPDATE THREAD: " + Thread.currentThread().getName());
Random rand = new Random();
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
SimplePanel simplePanel = new SimplePanel(new Color(r, g, b));
JPanel contentPane = (JPanel) this.getContentPane();
contentPane.removeAll();
contentPane.add(simplePanel);
contentPane.revalidate();
contentPane.repaint();
validate();
repaint();
}
}
这是我的 JPanel,用作我的内容窗格:
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class SimplePanel extends JPanel implements KeyListener {
public SimplePanel(Color c){
setFocusable(true);
setLayout(null);
setBackground(c);
setVisible(true);
this.addKeyListener(this);
}
public void keyTyped(KeyEvent keyEvent) {
if(keyEvent.getKeyChar() == 'a'){
System.out.println("a");
System.out.println("SIMPLE_PANEL KEY PRESS THREAD: " + Thread.currentThread().getName());
SimpleSim.getInstance().update();
}
}
public void keyPressed(KeyEvent keyEvent) {
}
public void keyReleased(KeyEvent keyEvent) {
}
}
奇怪的是,它在您第一次按 时起作用a
,但在之后不起作用。我的猜测是这里发生了线程问题。我可以看到update
第一次调用它是在主线程上调用的。下次在 EDT 上调用它。我尝试使用 invokeLater() 调用 update() ,但也没有用。我找到了使用不同设计模式的解决方法,但我真的很想了解为什么这不起作用。
此外,运行简单的类:
public class Run {
public static void main(String[] args){
SimpleSim.getInstance().initialize();
}
}
注意:对验证和重新绘制 JFrame 的看似多余的调用是为了试图安抚发布在我提供的第二个链接上的建议,该链接指出: 在受影响最大的组件上调用 validate()。这可能是 Java 渲染周期中最混乱的部分。对 invalidate 的调用将组件及其所有祖先标记为需要布局。对 validate 的调用执行组件及其所有后代的布局。一个“向上”工作,另一个“向下”工作。您需要在树中将受您的更改影响的最高组件上调用 validate。我认为这会导致它工作,但无济于事。