與此相似的問題已多次提出。見例如here和here。Swing ContentPane在使用(重新)驗證,重新繪製後未更新
但我真的想明白爲什麼它是我的代碼不起作用。正如在這個問題的其他版本中已經回答的那樣,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
時,它在主線程中被調用。下一次在美國東部時間召開。我已經嘗試使用invokeLater()調用update(),那也不起作用。我發現了一種使用不同設計模式的解決方法,但我真的很想理解爲什麼這樣做不起作用。
而且,簡單的類來運行:
public class Run {
public static void main(String[] args){
SimpleSim.getInstance().initialize();
}
}
注:看似冗餘呼叫驗證並重新繪製的JFrame做的目的是試圖安撫貼我提供的第二個鏈接,其中指出在意見即: 在最高受影響的組件上調用validate()。這可能是Java渲染週期中最泥濘的一點。對無效的調用將組件及其所有祖先標記爲需要佈局。驗證調用執行組件及其所有後代的佈局。一個工作「上」,另一個工作「下」。您需要調用樹中最高組件的驗證,這些組件將受到您的更改的影響。 我以爲這會導致它的工作,但無濟於事。
儘管我沒有相反的證據(除了'main'方法),但所有與UI的交互都必須在EDT的上下文中執行。你可能會這樣做,但你做的幾個陳述關注我。如果你開始的時候很好,小心,那麼請隨時忽略這個聲明...... – MadProgrammer