Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preserving keyboard layout in swing app?

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);
    }
}
like image 302
yggdraa Avatar asked Mar 12 '12 13:03

yggdraa


2 Answers

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.

like image 147
yggdraa Avatar answered Sep 29 '22 16:09

yggdraa


Are you just looking for a way to have any layout change affect your application globally?

If so, one approach is to create a custom listener, have the various components that care about the layout change register their interest in such events, and then fire off a change layout event that triggers the change in all components when it's changes in any one of them.

Another way to do it would be store the layout properties in an object that's accessible to any of the components, and have them update their layout periodically via a timer. This would be less desirable, however, because there would probably be lots of needless updates vs. the "only update on event" mode of operation. I'm guessing users of your application won't be changing their keyboard layout more than once or twice per session (as opposed to every 5 seconds)?

Another, third way, to do this is to have the keyboard layout settings stored at the application level, and loaded at startup. Then, when a keyboard layout change happens, prompt the user to restart the app for the changes to take effect globally.

like image 35
jefflunt Avatar answered Sep 29 '22 15:09

jefflunt