Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setting JDialog or JFrame setVisible(true) toggle my IME setting?

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:

  1. run the application.
  2. change your Language to one of Chinese Input methods eg. Chinese (Traditional) - Quick
  3. click the button in the program

My language setting

enter image description here

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


}
like image 945
user2492632 Avatar asked Jun 30 '14 12:06

user2492632


People also ask

What does frame setVisible true do?

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.

What does frame pack do?

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.


2 Answers

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.

like image 175
Jared Avatar answered Oct 16 '22 16:10

Jared


I think it can be related to the fact that Windows 7 remembers the keyboard/language set for each running application:

  1. I open my browser (in this case Chrome). I can see in my taskbar my keyboard set is ES (Spanish).
  2. Then I open any other application. Nothing changes.
  3. I set the focus in the browser again.
  4. I press Alt+Shift, which is a shortcut to change the keyboard set. Now I can see is EN (English)
  5. I click on the other app's window (or I use Alt+TAB). My keyboard set changes to ES
  6. Every time I come back to the browser the keyboard set changes to EN, keeping the ES for rest of applications.

This works also for JVM applications, for example Eclipse, so I think it is not a JVM Locale issue.

like image 23
Pablo Lozano Avatar answered Oct 16 '22 18:10

Pablo Lozano