2012-03-12 2 views
7

У меня есть приложение Java Swing, которое порождает дочерние диалоги с элементами управления текстом. И проблема в том, что когда вы меняете раскладку клавиатуры в дочернем диалоге, она меняется сразу после закрытия диалога.Сохранение раскладки клавиатуры в приложении swing?

Что мне нужно - это расположение кедра, которое должно оставаться после переключения, было ли оно переключено в основном кадре или в детском кадре.

Вот 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); 
    } 
} 
+1

Вы говорите о раскладке клавиатуры операционной системы? Немного смущен здесь. –

ответ

2

Хорошо, я просто поселился с этим решением:

Добавлен слушателем 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); 

Он работает на все дочерние диалогах сгенерированных родительского окна, как конструктор. При закрытии события Locale из InputContext дочернего диалога помещается в InputContext родительского окна.

Может быть, есть лучший способ.

1

Вы просто ищете способ, чтобы иметь любое изменение расположение влияет на применение в глобальном масштабе?

Если да, то один подход заключается в создании пользовательского прослушивателя, чтобы различные компоненты, которые заботятся о смене макета, регистрировали свою заинтересованность в таких событиях, а затем запускали событие изменения макета, которое запускает изменение всех компонентов, когда оно изменения в любом из них.

Другой способ сделать это - сохранить свойства макета в объекте, доступном для любого из компонентов, и периодически обновлять их расположение через таймер. Однако это было бы менее желательно, потому что, вероятно, было бы много ненужных обновлений по сравнению с режимом «только обновления в событии». Я предполагаю, что пользователи вашего приложения не будут менять раскладку клавиатуры более одного или двух раз за сеанс (в отличие от каждых 5 секунд)?

Другим, третьим способом, является установка параметров компоновки клавиатуры на уровне приложения и загрузка при запуске. Затем, когда происходит изменение раскладки клавиатуры, попросите пользователя перезапустить приложение, чтобы изменения вступили в силу во всем мире.

+0

Да, я ищу способ сохранить любое изменение макета, сделанное в приложении, чтобы избежать необходимости менять макет снова и снова в каждом новом диалоговом окне. Сейчас я изучаю возможность использования AWTEventListener на уровне приложения, чтобы избежать написания дополнительного кода для каждого дочернего кадра. – yggdraa

+0

Обновление по таймеру не может быть и речи, это будет перегрузка. Вопрос о перезагрузке приложений тоже не может быть изменен, пользователю необходимо постоянно меняться между двумя языками. – yggdraa

+0

Я посмотрел в NetBeans и IntellijIdea тоже, есть одно и то же. Вы открываете «Настройки», например, меняете язык ввода, закрываете «Настройки», а макет клавиатуры возвращается к тому, каким он раньше был. В других приложениях (браузерах, mssql, блокнот) изменение раскладки клавиатуры является составной частью приложения. – yggdraa

1

Да и нет: код yggdraa от 13 марта отлично работал на Windows, но не удался в Linux.

Не может быть универсального решения для Linux: никаких таких функций, как Windows GetKeyboardLayout() и ActivateKeyboardLayout(). Могут быть возможны некоторые зависящие от конфигурации хаки, такие как анализ вывода xset (details here) и форсирование макета, скажем, по клавише вверх/вниз.

В приведенном выше примере код выбора входа в eventDispatched() вызывается слишком поздно - когда клавиатура ОС уже переключилась обратно на системный стандарт по умолчанию.

Несколько попыток грубой силы также не работают: myParticularJField.setLocale (myForcedLocale) из обработчика фокуса поля сразу же отменяется при первом нажатии клавиши. То же самое для принудительной локализации верхнего уровня (JFrame/JDialog).

Update:

У нас есть только 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; 
    } 

} 

Update:

В Ubuntu, изменение обратно в расположение по умолчанию происходит на уровне окна X (Dbus событий). Обходной путь: для отключения отдельных макетов для каждого окна: Настройки => Клавиатура => Макеты, снимите флажок «Отдельный макет для каждого окна».