• category: swing folder: VariableRoundedBorderOnComboBox title: JComboBoxのBorderをドロップダウンリストの表示状態で切り替える tags: [JComboBox, Border, PopupMenuListener] author: aterai pubdate: 2024-03-11T02:49:30+09:00 description: JComboBoxのBorderをドロップダウンリストの表示状態で切り替えて左右の辺が直線で描画されるよう設定します。 image: https://drive.google.com/uc?id=1srDCMSHQw2olzIC8t0q1MQjJRHhVR4y_

概要

JComboBoxのBorderをドロップダウンリストの表示状態で切り替えて左右の辺が直線で描画されるよう設定します。

サンプルコード

JComboBox<String> combo1 = new JComboBox<String>(model) {
  private transient PopupMenuListener listener;

  @Override public void updateUI() {
    setRenderer(null);
    removePopupMenuListener(listener);
    super.updateUI();
    setBorder(new RoundedCornerBorder());
    setRenderer(new RoundedCornerListCellRenderer());
    setUI(new BasicComboBoxUI() {
      // ...
    }
    listener = new HeavyWeightContainerListener();
    addPopupMenuListener(listener);
    Object o = getAccessibleContext().getAccessibleChild(0);
    if (o instanceof JComponent) {
      JComponent c = (JComponent) o;
      c.setBorder(new BottomRoundedCornerBorder());
      c.setBackground(Color.WHITE);
    }
  }
};
// ...
class HeavyWeightContainerListener implements PopupMenuListener {
  @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    EventQueue.invokeLater(() -> {
      JComboBox<?> combo = (JComboBox<?>) e.getSource();
      combo.setBorder(new TopRoundedCornerBorder());
      Accessible a = combo.getUI().getAccessibleChild(combo, 0);
      if (a instanceof JPopupMenu) {
        Window w = SwingUtilities.getWindowAncestor((Component) a);
        if (w != null && w.getType() == Window.Type.POPUP) {
          // Popup$HeavyWeightWindow
          w.setBackground(new Color(0x0, true));
        }
      }
    });
  }

  @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    JComboBox<?> combo = (JComboBox<?>) e.getSource();
    combo.setBorder(new RoundedCornerBorder());
  }

  @Override public void popupMenuCanceled(PopupMenuEvent e) {
    /* not needed */
  }
}
View in GitHub: Java, Kotlin

解説

  • JComboBox本体にはRoundedCornerBorder(4隅を丸めたラウンド矩形Border)を設定
  • BasicComboPopup(ドロップダウンリスト用)にはBottomRoundedCornerBorder(左右下の2隅を丸めたラウンド矩形Border)を設定
  • PopupMenuListenerJComboBoxに追加してドロップダウンリストが開いたとき(PopupMenuListener#popupMenuWillBecomeVisible(...))、JComboBox本体にTopRoundedCornerBorder(左右上の2隅を丸めたラウンド矩形Border)を設定
    • JComboBox本体の左辺とドロップダウンリストの左辺、JComboBox本体の右辺とドロップダウンリストの右辺が直線でつながり、本体とドロップダウンリスト全体でひとつのRoundRectangle2Dを描画するBorderになる
  • ドロップダウンリストが閉じるとき(PopupMenuListener#popupMenuWillBecomeInvisible(...))、JComboBox本体のBorderRoundedCornerBorderに戻す

参考リンク

コメント