5

Java では、デフォルト以外のシステム ルック アンド フィールを使用することで、異なるキーマップが作成されます。

たとえば、私は Mac OS X を使用しており、Substance のルック アンド フィール (非デフォルト システムのルック アンド フィール) を使用しています。その結果、テキスト コンポーネントのすべてを選択するための「メタ」キーが失われます。Mac OS X では「meta + a」である必要がありますが、Substance を使用する場合は「ctrl + a」を使用する必要があります。次の単語"、"前の単語"、"行末"、"行頭" など) そのため、デフォルト以外のシステムのルック アンド フィール (Substance ルック アンド フィール) を使用して、Mac OS X のフィーリングを実現することはできませんでした。

デフォルト以外のシステム ルック アンド フィールを使用し、システム (ネイティブ) キーマップを使用する方法はありますか?

4

2 に答える 2

1

回避策

あまり洗練されていない解決策として、keyPressedメソッドを実装することでデフォルトの「ctrl + a」動作をオーバーライドするキーリスナーを追加してみることができます(次のサンプルでは「ctrl + a」が許可されないため、「meta+a」のサポートが追加されるだけです。 "):

@Override
public void keyPressed(final KeyEvent e) {
  // Get the default toolkit shortcut mask ("meta" for OSX).
  int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

  // You could also check modifiers against KeyEvent.META_MASK...
  if (e.getModifiers() == keyMask && e.getKeyCode() == KeyEvent.VK_A) {
    // Select everything (assumes member of child text component class).
    this.selectAll();

    // We handled this keystroke, 'a' will be ignored by underlying text component.
    e.consume(); 
  }
}

より良い代替案は、inputMapsを使用することです(以下のuudashrによるコメントを参照)。


根本原因についての考え

残念ながら、クラス名が示すように、ルックアンドフィール(またはLAF)は、外観、つまりルックと「システムの動作」、つまりフィールの組み合わせです。物質のソースを掘り下げると、SubstanceLookAndFeelはswingに付属しているBasicLookAndFeelをオーバーライドします。BasicLookAndFeel内にあるように見えますが、問題のある動作はinitComponentDefaultsに設定されています。getDefaults()を呼び出すことにより、LAFからUIDefaultsを取得できるはずです。

ここからの問題は次のとおりです。

  • 変更したい「システムの振る舞い」は、そのままにしておきたい外観設定と混ざり合っています。
  • また、これらのデフォルトをLAFレベルで実質的に注入する簡単な方法を見つけることができませんでした...これについて他のアイデアを持っている人はいますか?
于 2009-12-06T08:23:03.553 に答える
0

1つの可能性は、METAキーイベントをCTRLキーイベントに変換することです。そのため、OS XのユーザーがMETAキーを押すと、代わりにCTRLキーに変換されます。これは、LAF間でCTRLとMETAのみが交換されているキーショートカットに対して正しく機能するはずです。より複雑な他のコンボがある場合は、常により複雑なマッチングと変換を行うことができます。基本的な変換を行うためのコードは以下のとおりです。CTRL+Oのキーアクセラレータを使用してJMenuItemでテストしたので、META+Oがアクセラレータをアクティブにします。

java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            public void eventDispatched(AWTEvent event) {
                KeyEvent kev = (KeyEvent) event;
                if (kev.getID() == KeyEvent.KEY_PRESSED || kev.getID() == KeyEvent.KEY_RELEASED || kev.getID() == KeyEvent.KEY_PRESSED) {
                    if ((kev.getModifiersEx() & KeyEvent.META_DOWN_MASK) != 0 && !((kev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) {
                        kev.consume(); // Drop the original event, this is really optional.
                        KeyEvent fake = new KeyEvent(kev.getComponent(),
                                kev.getID(),
                                kev.getWhen(),
                                (kev.getModifiersEx() & ~KeyEvent.META_DOWN_MASK) | KeyEvent.CTRL_DOWN_MASK,
                                kev.getKeyCode(), kev.getKeyChar());
                        java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(fake);
                    }
                }
            }
        }, KeyEvent.KEY_EVENT_MASK);

これにより、AWTEventListenerがAWTEventキューにインストールされ、すべての主要なイベントに影響します。

于 2009-12-30T18:48:48.430 に答える