在swing应用程序中保留键盘布局?

我有一个Java Swing应用程序,它产生了带有文本控件的子对话框。 问题是,当您更改子对话框中的键盘布局时,它将在对话框关闭后立即返回。

我需要的是keboard布局在切换后保留,无论它是在主框架还是在子框架中切换。

这是一个说明问题的SSCCE:

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);
    }
}

好吧,我刚刚解决这个解决方案:

在main()方法中添加一个监听器到java工具箱,如下所示:

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);

它适用于以父窗口生成的所有子对话框作为构造器参数。 关闭事件子对话框的InputContext中的Locale被放入其父窗口的InputContext中。

可能会有更好的方法。


你只是在寻找一种方式有任何改变布局全球影响您的应用程序?

如果是这样,一种方法是创建一个自定义侦听器,让关注布局变化的各种组件注册他们对这些事件的兴趣,然后触发一个变更布局事件,当它发生任何变化时触发所有组件的变化其中。

另一种方法是将布局属性存储在任何组件可访问的对象中,并通过定时器定期更新其布局。 然而,这不太理想,因为与“仅更新事件”操作模式相比,可能会有大量不必要的更新。 我猜你的应用程序用户不会每次更改一次或两次以上的键盘布局(而不是每隔5秒)?

另一种方法是,将键盘布局设置存储在应用程序级别,并在启动时加载。 然后,当发生键盘布局更改时,提示用户重新启动应用程序以使更改全局生效。


是和否:yggdraa的Mar 13的代码在Windows上运行良好,但在Linux上失败。

根本没有Linux的通用解决方案:没有Windows的GetKeyboardLayout()和ActivateKeyboardLayout()那样的东西。 一些依赖于配置的hack可能是可能的,例如解析xset的输出(详细信息在这里)和强制布局,比如在键上/下。

在上面的例子中,eventDispatched()中的输入选择代码被调用得太晚 - 当OS键盘已经切换回系统默认的US时。

一些蛮力尝试也不起作用:第一次按键时,字段焦点处理程序中的myParticularJField.setLocale(myForcedLocale)立即取消。 强制使用顶级(JFrame / JDialog)语言环境也是如此。

更新:

我们在生产环境中只有Windows,因此在Linux下进行这项工作是不切实际的:太多的努力。

以防万一,副产品。 这正确地确定哪个布局当前处于活动状态:默认或替代(“本地”)。 它无法区分几种可选布局:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LinuxKeyboardLayoutStatus {

    public enum LayoutType { DEFAULT, LOCAL }

    public LinuxKeyboardLayoutStatus.LayoutType getCurrentKeyboardLayoutType() throws IOException, InterruptedException {
        String[] command = createCommand();
        Process p = Runtime.getRuntime().exec(command);
        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String l = r.readLine();
        r.close();
        p.waitFor();
        return decodeLayoutType(l);
    }

    protected String[] createCommand() {
        return new String[] { "/bin/sh", "-c", "xset -q | grep LED | awk '{ print $10 }' | cut -c5" };
    }

    protected LinuxKeyboardLayoutStatus.LayoutType decodeLayoutType(String commandOutput) {
        return
            commandOutput != null && !commandOutput.equals("0") ? LayoutType.LOCAL : LayoutType.DEFAULT;
    }

}

更新:

在Ubuntu中,更改回默认布局发生在X窗口级别(DBus事件)。 解决方法:关闭每个窗口的单独布局:设置=>键盘=>布局,取消选中“为每个窗口单独布局”。

链接地址: http://www.djcxy.com/p/58217.html

上一篇: Preserving keyboard layout in swing app?

下一篇: Making Struts send 500 Internal Server Error when exceptions get thrown