Swing/MenuItemAcceleratorAlignment の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/MenuItemAcceleratorAlignment へ行く。
- Swing/MenuItemAcceleratorAlignment の差分を削除
--- category: swing folder: MenuItemAcceleratorAlignment title: JMenuItemのAccelerator表示を右揃えにする tags: [JMenuItem, Locale, KeyEvent, ResourceBundle, Alignment, GridBagLayout] author: aterai pubdate: 2013-09-30T05:06:53+09:00 description: JMenuItemのAccelerator表示を右揃えに変更します。 image: https://lh5.googleusercontent.com/-vl8nnt_tGvQ/UkhDq1YV-VI/AAAAAAAAB2o/B0-hGdv35Ns/s800/MenuItemAcceleratorAlignment.png hreflang: href: https://java-swing-tips.blogspot.com/2014/10/jmenuitem-accelerator-text-alignment.html lang: en --- * Summary [#summary] `JMenuItem`の`Accelerator`表示を右揃えに変更します。 #download(https://lh5.googleusercontent.com/-vl8nnt_tGvQ/UkhDq1YV-VI/AAAAAAAAB2o/B0-hGdv35Ns/s800/MenuItemAcceleratorAlignment.png) * Source Code Examples [#sourcecode] #code(link){{ public static void paintAccText( Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color disabledForeground, Color acceleratorForeground, Color acceleratorSelectionForeground) { if (!lh.getAccText().equals("")) { ButtonModel model = lh.getMenuItem().getModel(); g.setFont(lh.getAccFontMetrics().getFont()); if (!model.isEnabled()) { // *** paint the accText disabled if (disabledForeground != null) { g.setColor(disabledForeground); SwingUtilities2.drawString( lh.getMenuItem(), g, lh.getAccText(), lr.getAccRect().x, lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); } else { g.setColor(lh.getMenuItem().getBackground().brighter()); SwingUtilities2.drawString( lh.getMenuItem(), g, lh.getAccText(), lr.getAccRect().x, lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); g.setColor(lh.getMenuItem().getBackground().darker()); SwingUtilities2.drawString( lh.getMenuItem(), g, lh.getAccText(), lr.getAccRect().x - 1, lr.getAccRect().y + lh.getFontMetrics().getAscent() - 1); } } else { // *** paint the accText normally if (model.isArmed() || (lh.getMenuItem() instanceof JMenu && model.isSelected())) { g.setColor(acceleratorSelectionForeground); } else { g.setColor(acceleratorForeground); } SwingUtilities2.drawString( lh.getMenuItem(), g, lh.getAccText(), // lr.getAccRect().x, >>> lh.getViewRect().x + lh.getViewRect().width - lh.getMenuItem().getIconTextGap() - lr.getAccRect().width, // <<< lr.getAccRect().y + lh.getAccFontMetrics().getAscent()); } } } }} * Explanation [#explanation] - `Default` -- デフォルトの`Windows`環境の場合`Accelerator`は左寄せ -- デフォルトの`Ubuntu`環境の場合`Accelerator`は右寄せ - `RightAcc` -- `BasicMenuItemUI#paintMenuItem(...)`メソッドをオーバーライドして、`JMenuItem`の`Accelerator`を左寄せではなく右寄せで表示 -- `Web Start`で実行すると`java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.swing")`と例外が発生してメニューが表示されない -- `sun.swing.MenuItemLayoutHelper`や、`sun.swing.MenuItemLayoutHelper.LayoutResult`などの内部所有の`API`を使用しているので、今後も使用できるか不明 -- `paintText(...)`、`paintCheckIcon(...)`、`paintIcon(...)`、`paintArrowIcon(...)`などの`BasicMenuItemUI`のプライベートなメソッドをほぼそのままコピーして使用している -- `ComponentOrientation.RIGHT_TO_LEFT`が設定されて、文字列が右から左に配置される場合は考慮していない ---- - `EastAcc` -- `Windows 7`環境の`WindowsLookAndFeel`でのみ正常に動作? -- `JMenuItem`に`GridBagLayout`を設定し、`c.anchor = GridBagConstraints.EAST;`で、`Accelerator`文字列を設定した`JLabel`を配置 -- 本来の`Accelerator`文字列は、`UIManager.put("MenuItem.acceleratorForeground", background);`などで背景色と同化して非表示 -- 参考: [[JMenuItemの内部にJButtonを配置する>Swing/ButtonsInMenuItem]] #code{{ private static JMenuItem makeMenuItem2(JMenuItem mi) { final JLabel label = new JLabel(MenuItemUIHelper.getAccText(mi, "+")); label.setOpaque(true); JMenuItem item = new JMenuItem(mi.getText()) { @Override public void updateUI() { super.updateUI(); if (getUI() instanceof WindowsMenuItemUI) { setUI(new WindowsMenuItemUI() { @Override protected void installDefaults() { super.installDefaults(); acceleratorForeground = UIManager.getColor("MenuItem.background"); acceleratorSelectionForeground = acceleratorForeground; } }); } } }; GridBagConstraints c = new GridBagConstraints(); item.setLayout(new GridBagLayout()); c.gridheight = 1; c.gridwidth = 1; c.gridy = 0; c.gridx = 0; c.insets = new Insets(0, 0, 0, 4); c.weightx = 1d; c.fill = GridBagConstraints.HORIZONTAL; item.add(Box.createHorizontalGlue(), c); c.gridx = 1; c.fill = GridBagConstraints.NONE; c.weightx = 0d; c.anchor = GridBagConstraints.EAST; item.add(label, c); item.setMnemonic(mi.getMnemonic()); item.setAccelerator(mi.getAccelerator()); return item; } }} ---- - `JMenuItem`の`Accelerator`が`JMenuItem#setLocale(Locale.ENGLISH)`としても変化しない -- [https://bugs.openjdk.org/browse/JDK-6292739 Bug ID: JDK-6292739 Locale change at runtime doesn't affect text displayed for accelerator keys] - `JDK 1.7.0`から`Locale.getLocale()`が`Locale.JAPAN`などの場合、`KeyEvent#getKeyText(...)`で取得できる文字列が翻訳されている -- 例: `Space`が「スペース」 - [https://docs.oracle.com/javase/jp/8/docs/api/java/awt/event/KeyEvent.html#getKeyText-int- KeyEvent#getKeyText(int) (Java Platform SE 8)]では、「これらの文字列は`awt.properties`ファイルを変更することによりローカライズが可能です。」となっているが、`%JAVA_HOME%/jre/lib/rt.jar`内に`sun/awt/resources/awt.class`などの優先順位が高いクラスがあるため、`awt_ja.properties`などを作成しても読み込まれない -- `-Xbootclasspath/p:`などで、`rt.jar`より先に以下のような`sun.awt.resources.awt_ja.class`を読み込むよう指定 #code{{ package sun.awt.resources; import java.util.ListResourceBundle; // ant package // cd target // "%JAVA_HOME%\bin\java" -Xbootclasspath/p:example.jar -jar example.jar // Class names should begin with an uppercase character @SuppressWarnings({"PMD.ClassNamingConventions", "checkstyle:typename"}) public final class awt_ja extends ListResourceBundle { @Override protected Object[][] getContents() { System.out.println("awt_ja"); return new Object[][] { {"AWT.space", "XXXXX"} }; } } }} * Reference [#reference] - [https://community.oracle.com/thread/1364746 Swing - Localized Accelorator Keys] - [[JMenuItemの内部にJButtonを配置する>Swing/ButtonsInMenuItem]] - [[JMenuItemのAccelerator表示を変更する>Swing/MenuItemAcceleratorFont]] * コメント [#comment] * Comment [#comment] #comment - `JMenuItem`に`GridBagLayout`を設定して右寄せする方法を追加。 -- &user(aterai); &new{2014-11-30 (日) 17:57:58}; #comment