2012-03-12 32 views
7

我有一個Java Swing應用程序,它產生了帶有文本控件的子對話框。問題是,當您更改子對話框中的鍵盤佈局時,它將在對話框關閉後立即返回。在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); 
    } 
} 
+1

你是說操作系統的鍵盤佈局?有點困惑在這裏。 – 2012-03-12 14:26:56

回答

2

好吧,我剛剛塵埃落定該解決方案:

增加了一個監聽器Java工具箱中的main()方法是這樣的:

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中。

雖然可能有一些更好的方法。

1

你只是在尋找一種方式有任何佈局改變全球影響您的應用程序?

如果是這樣,一種方法是創建一個自定義偵聽器,讓關注佈局更改的各種組件註冊他們對這些事件的興趣,然後觸發一個更改佈局事件,當所有組件發生更改時觸發更改其中任何一個的變化。

另一種方法可以將佈局屬性存儲在任何組件可訪問的對象中,並讓他們定期通過定時器更新其佈局。然而,這不太理想,因爲與「僅更新事件」操作模式相比,可能會有大量不必要的更新。我猜你的應用程序用戶不會每次更改一次或兩次以上的鍵盤佈局(而不是每隔5秒)?

另一種方法是將鍵盤佈局設置存儲在應用程序級別並在啓動時加載。然後,當發生鍵盤佈局更改時,提示用戶重新啓動應用程序以使更改全局生效。

+0

是的,我正在尋找一種方法來保留在應用程序中所做的任何佈局更改,以避免在每個新對話框中一次又一次地更改佈局。 現在我正在探索在應用程序級別使用AWTEventListener的選項,以避免爲每個子框架編寫額外的代碼 – yggdraa 2012-03-12 14:39:23

+0

定時器更新無疑是超負荷的。 要求重新加載應用程序也不成問題,用戶需要始終在兩種語言之間進行更改。 – yggdraa 2012-03-12 14:52:28

+0

我也查看了NetBeans和IntellijIdea,也有同樣的事情。您打開設置,例如,更改輸入語言,關閉設置,鍵盤佈局返回到之前的狀態。在其他應用程序(瀏覽器,mssql,記事本)中,鍵盤佈局的變化與整個應用程序一致。 – yggdraa 2012-03-12 14:53:23

1

是和否:yggdraa的Mar 13的代碼在Windows上工作正常,但在Linux上失敗。

Linux可能沒有通用的解決方案:沒有Windows的GetKeyboardLayout()和ActivateKeyboardLayout()那樣的東西。儘管如此,一些配置依賴的黑客可能是可能的,例如解析xset的輸出(details here)並強制佈局,比如在鍵上/下。

在上面的示例中,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事件)。解決方法:關閉每個窗口的單獨佈局:設置=>鍵盤=>佈局,取消選中「爲每個窗口單獨佈局」。

相關問題