在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