概要

JPopupMenuの背景色、縁色とその子要素として配置されたJMenuItemなどの文字色を変更します。

サンプルコード

class DarkModePopupMenu extends JPopupMenu {
  @Override public void updateUI() {
    super.updateUI();
    setUI(new BasicPopupMenuUI());
    setBackground(Color.DARK_GRAY);
    setBorder(new BorderUIResource(
        BorderFactory.createLineBorder(Color.LIGHT_GRAY)));
    EventQueue.invokeLater(() -> {
      for (MenuElement m : getSubElements()) {
        Component c = m.getComponent();
        c.setForeground(Color.WHITE);
        // for Metal, Windows Classic LookAndFeel
        ((JComponent) c).setOpaque(false);
      }
    });
  }
}
View in GitHub: Java, Kotlin

解説

  • Default
    • デフォルトのJPopupMenuで、LookAndFeelで設定された背景色などで描画される
  • setBackground(...)
    • JPopupMenu#setBackground(...)などで背景色を設定
      • UIManager.put("PopupMenu.background", Color.DARK_GRAY)ですべてのJPopupMenuの文字色をまとめて変更可能
      • WindowsLookAndFeelNimbusLookAndFeelなどでは上記のJPopupMenu#setBackground(...)の設定は無効
    • JPopupMenu#setForeground(...)を設定しても子要素として配置されたJMenuItemなどの文字色には影響しない
      • このサンプルでは指定したJPopupMenuの子要素の文字色のみ変更するため、JPopupMenu#getSubElements()MenuElementを取得しそのComponentComponent#setForeground(Color.WHITE)で文字色を設定している
      • UIManager.put("MenuItem.foreground", Color.WHITE)などですべてのMenuItemの文字色をまとめて変更可能
      • JMenuItemを継承するJCheckBoxMenuItemなどには適用されないので、別途CheckBoxMenuItem.foregroundRadioButtonMenuItem.foregroundを使用する必要がある
  • BasicPopupMenuUI
    • JPopupMenu#setBackground(...)などで設定した色で背景全体を塗りつぶすBasicPopupMenuUIを設定してLookAndFeel依存を排除
    • JPopupMenu#paintComponent(...)をオーバーライドして背景を描画する方法と同等
    • NimbusLookAndFeelなどでJCheckBoxMenuItemのチェックアイコン色を変更する方法がない?
      • RadioButtonMenuItemPainterprivate Color color3 = decodeColor("nimbusBlueGrey", ...);を変更したいが難しい

参考リンク

コメント