为什么设置 JDialog 或 JFrame setVisible(true) 会切换我的 IME 设置?

2022-09-02 13:51:24

我发现,当我在Java swing应用程序中显示一个或一个新的时,应用程序将在Windows 7中将我的中文输入法从半字节模式切换到全字节模式。JDialogJFrame

为什么调用对话框或框架方法会切换我的 IME 设置?setVisible(true)

有谁知道代码有什么问题,或者它是Java的一个错误?

重现问题的过程:

  1. 运行应用程序。
  2. 将您的语言更改为中文输入法之一,例如。中文(繁体) - 快速
  3. 单击程序中的按钮

我的语言设置

enter image description here

我发现了一个类似的问题 Java中Windows 7输入法自动切换字符宽度

添加默认区域设置后,它仍然不起作用

import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Locale;

public class MainWindow {

private JFrame frame;
private Locale l;

/**
 * Create the application.
 */
public MainWindow() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {

    l = new Locale("zh", "zh_TW");

    frame = new JFrame();
    frame.setLocale(l);
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {

            JDialog d = new JDialog(frame, "Run", true);
            d.getContentPane().add(new JLabel("dsad"));
            d.setMinimumSize(new Dimension(150, 100));
            d.setLocationRelativeTo(null);
            d.setLocale(l);
            d.setVisible(true);

        }
    });
    frame.getContentPane().add(btnNewButton, BorderLayout.CENTER);
}

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                MainWindow window = new MainWindow();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}


}

答案 1

根据Oracle文档,从我如何理解这个问题来看,这似乎与我预期的一样:

应用程序的默认区域设置通过三种方式确定。首先,除非您显式更改了缺省值,否则 Locale.getDefault() 方法将返回首次加载时最初由 Java 虚拟机 (JVM) 确定的区域设置。也就是说,JVM 从主机环境确定缺省语言环境。主机环境的区域设置由主机操作系统和在该系统上建立的用户首选项确定。

在您的问题中,应用程序启动,Windows 中的默认值已更改,这意味着已设置 JVM 语言环境。特定帧的区域设置已设置,但创建新帧时会根据默认区域设置设置(JDialog 和 JFrame 都会发生这种情况):

 protected void dialogInit() {
     enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK);
     setLocale( JComponent.getDefaultLocale() );
     setRootPane(createRootPane());
     setRootPaneCheckingEnabled(true);
     if (JDialog.isDefaultLookAndFeelDecorated()) {
         boolean supportsWindowDecorations =
         UIManager.getLookAndFeel().getSupportsWindowDecorations();
         if (supportsWindowDecorations) {
             setUndecorated(true);
             getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
         }
     }
     sun.awt.SunToolkit.checkAndSetPolicy(this, true);
 }

由于您在Windows中设置了默认区域设置,因此人们会认为JComponent.getDefaultLocale()将返回Windows区域设置。getDefaultLocale() 本身返回当前应用程序上下文(VM 区域设置)的区域设置。调用以下方法将为当前上下文设置区域设置:

javax.swing.JComponent.setDefaultLocale(locale);

这将设置 VM 的默认区域设置(它实际上调用

SwingUtilities.appContextPut(defaultLocale, l);

这使得正在发生的事情更加明显)。

如果设置 defaultLocale 可以解决问题,我想在调用链中的其他位置,默认Locale 的调用方式会导致 Windows 更改设置。


如果这不能给你预期的功能,我能想到的唯一建议你研究的另一个属性是InputContext类:

提供用于控制文本输入功能(如输入法和键盘布局)的方法。有两种方法同时处理输入法和键盘布局:selectInputMethod 允许客户端组件按区域设置选择输入法或键盘布局,getLocale 允许客户端组件获取当前输入法或键盘布局的区域设置。


答案 2

我认为这可能与Windows 7记住每个正在运行的应用程序的键盘/语言集这一事实有关:

  1. 我打开浏览器(在本例中为 Chrome)。我可以看到在我的任务栏中,我的键盘集是ES(西班牙语)。
  2. 然后我打开任何其他应用程序。没有任何变化。
  3. 我再次在浏览器中设置焦点。
  4. 我按Alt + Shift,这是更改键盘集的快捷方式。现在我可以看到是EN(英语)
  5. 我单击其他应用的窗口(或使用 Alt+TAB)。我的键盘集更改为 ES
  6. 每次我回到浏览器时,键盘集都会更改为EN,为其余应用程序保留ES。

这也适用于JVM应用程序,例如Eclipse,所以我认为这不是JVM Locale问题。


推荐