I have a Java Swing application wich spawns child dialogs with text controls. And the problem is that when you change keyboard layout in child dialog, it changes back right after the dialog is closed.
What I need is the keboard layout to stay after being switched whether it was switched in the main frame or in a child frame.
Here is a SSCCE that illustrates the problem:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class InheritInputContext {
public static void main(String[] arg) {
final MainFrame mainFrame = new MainFrame();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
mainFrame.setPreferredSize(new Dimension(300, 400));
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
});
}
}
class MainFrame extends JFrame {
MainFrame() {
setLayout(new BorderLayout());
JTextArea textArea = new JTextArea();
add(textArea, BorderLayout.CENTER);
JButton dialogBtn = new JButton("Dialog");
add(dialogBtn, BorderLayout.SOUTH);
dialogBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ChildDialog cd = new ChildDialog(MainFrame.this);
cd.setPreferredSize(new Dimension(200, 200));
cd.setLocationRelativeTo(MainFrame.this);
cd.pack();
cd.setVisible(true);
}
});
}
}
class ChildDialog extends JDialog {
ChildDialog(Window w) {
super(w);
JTextArea textArea = new JTextArea();
getContentPane().add(textArea);
}
}
Ok, I just settled with this solution:
Added a listener to java toolkit in main() method like this:
AWTEventListener awtWindowListener = new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
if (event instanceof WindowEvent) {
if (WindowEvent.WINDOW_CLOSED == event.getID()
|| WindowEvent.WINDOW_CLOSING == event.getID()) {
Window child = ((WindowEvent) event).getWindow();
Window parent = SwingUtilities.getWindowAncestor(child);
if (parent == null) return;
InputContext childIC = child.getInputContext();
parent.getInputContext().selectInputMethod(childIC.getLocale());
}
}
}
};
Toolkit.getDefaultToolkit().addAWTEventListener(awtWindowListener, AWTEvent.WINDOW_EVENT_MASK);
It works on all child dialogs generated with parent window as constructor parameter. On close event Locale from InputContext of child dialog is put into InputContext of it's parent window.
May be there is some better way though.