I made some modifications to your code, sorry, but it made testing SOooo much easier...
The import change that I can see is in the update method. Basically I simply called revalidate
on the frame
Revalidate states
Revalidates the component hierarchy up to the nearest validate root.
This method first invalidates the component hierarchy starting from this component up to the nearest validate root. Afterwards, the component hierarchy is validated starting from the nearest validate root.
This is a convenience method supposed to help application developers avoid looking for validate roots manually. Basically, it's equivalent to first calling the invalidate() method on this component, and then calling the validate() method on the nearest validate root.
I think that last part is what you were missing in you own code.
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.setSize(400, 400);
this.setVisible(true);
setLayout(new BorderLayout());
update();
}
public void update() {
System.out.println("NEXT: " + 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();
getContentPane().removeAll();
add(simplePanel);
revalidate();
}
public class SimplePanel extends JPanel {
public SimplePanel(Color c) {
setFocusable(true);
setLayout(null);
setBackground(c);
setVisible(true);
requestFocusInWindow();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "A");
am.put("A", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("a");
System.out.println("KEY: " + Thread.currentThread().getName());
SimpleSim.getInstance().update();
}
});
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
SimpleSim.getInstance().initialize();
}
});
}
}
Also, I'd suggest you take advantage of the key bindings API instead of using KeyListener
. It will solve some of the focus issues ;)
UPDATE
After some time testing various permutations, we've come to the conclusion that the major issue is related to a focus problem.
While the SimplePanel
was focusable, nothing was giving it focus, meaning that the key listener fails to be triggered.
Added simplePanel.requestFocusInWindow
AFTER it was added to the frame seems to have allowed the key listener to remain active.
From my own testing, with out a call to revalidate
the panels did not update.