I found that when I show a JDialog
or a new JFrame
in my Java swing application will toggle my Chinese Input Method from half-byte mode to full-byte mode in Windows 7.
Why does calling the dialog or frame setVisible(true)
method toggle my IME setting?
Does anyone knows what's wrong with the code, or it's a bug of Java?
Procedure to reproduce the problem:
My language setting
I have found a similar question Automatic toggling of character width by Windows 7 input methods in Java
and after adding the default locale, it's still not working
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();
}
}
});
}
}
The setVisible(true) method makes the frame appear on the screen. If you forget to do this, the frame object will exist as an object in memory, but no picture will appear on the screen.
The pack() method is defined in Window class in Java and it sizes the frame so that all its contents are at or above their preferred sizes. An alternative to the pack() method is to establish a frame size explicitly by calling the setSize() or setBounds() methods.
According to the Oracle documentation, it seems as though this is behaving as I would expect, from how I understood the question:
The default locale of your application is determined in three ways. First, unless you have explicitly changed the default, the Locale.getDefault() method returns the locale that was initially determined by the Java Virtual Machine (JVM) when it first loaded. That is, the JVM determines the default locale from the host environment. The host environment's locale is determined by the host operating system and the user preferences established on that system.
In your question, the default was changed in Windows after the application was started, which means the JVM locale was already set. The locale for a specific frame was set, but the creation of a new frame sets the locale based on the default locale (which happens for both JDialog and 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);
}
Since you are setting the default locale in Windows, one would think that JComponent.getDefaultLocale() would return the Windows locale. getDefaultLocale() itself returns the locale of the current application context (the VM locale). Calling the below method will set the locale for the current context:
javax.swing.JComponent.setDefaultLocale(locale);
That sets the default locale for the VM (it actually calls through to
SwingUtilities.appContextPut(defaultLocale, l);
which makes it slightly more apparent what is happening).
If setting the defaultLocale fixes the problem, I imagine that somewhere else in the call chain the defaultLocale is getting called in a manner that causes Windows to change the setting.
If that doesn't give you the expected functionality, the only other property I can think to suggest that you look into is the InputContext class:
Provides methods to control text input facilities such as input methods and keyboard layouts. Two methods handle both input methods and keyboard layouts: selectInputMethod lets a client component select an input method or keyboard layout by locale, getLocale lets a client component obtain the locale of the current input method or keyboard layout.
I think it can be related to the fact that Windows 7 remembers the keyboard/language set for each running application:
This works also for JVM applications, for example Eclipse, so I think it is not a JVM Locale issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With