• category: swing folder: RoundedCornerListCellRenderer title: JComboBoxのドロップダウンリストでアイテム選択状態表示をラウンド矩形に変更する tags: [JComboBox, JList, ListCellRenderer] author: aterai pubdate: 2024-02-19T03:05:38+09:00 description: JComboBoxで使用するドロップダウンリストのアイテム選択状態表示をラウンド矩形に変更するListCellRendererを作成します。 image: https://drive.google.com/uc?id=1rMdApPD-7KgcOs2jLFTbRXqcI_SUe6IR

概要

JComboBoxで使用するドロップダウンリストのアイテム選択状態表示をラウンド矩形に変更するListCellRendererを作成します。

サンプルコード

class RoundedCornerListCellRenderer<E> implements ListCellRenderer<E> {
  private static final Icon GAP = new GapIcon();
  private final DefaultListCellRenderer renderer = new DefaultListCellRenderer() {
    @Override protected void paintComponent(Graphics g) {
      if (getIcon() != null) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setPaint(getBackground());
        Rectangle r = SwingUtilities.calculateInnerArea(this, null);
        g2.fill(new RoundRectangle2D.Float(r.x, r.y, r.width, r.height, 10f, 10f));
        super.paintComponent(g2);
        g2.dispose();
      } else {
        super.paintComponent(g);
      }
    }
  };

  @Override public Component getListCellRendererComponent(JList<? extends E> list, E value, int index, boolean isSelected, boolean cellHasFocus) {
    Component c = renderer.getListCellRendererComponent(
        list, value, index, isSelected, cellHasFocus);
    if (c instanceof JLabel) {
      JLabel label = (JLabel) c;
      label.setOpaque(false);
      label.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
      label.setIconTextGap(0);
      label.setIcon(index >= 0 ? GAP : null);
      // Nimbus DerivedColor bug?
      Color fgc = isSelected
          ? new Color(list.getSelectionForeground().getRGB())
          : list.getForeground();
      label.setForeground(fgc);
    }
    return c;
  }
}

class GapIcon implements Icon {
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    /* Empty paint */
  }

  @Override public int getIconWidth() {
    return 2;
  }

  @Override public int getIconHeight() {
    return 18;
  }
}
View in GitHub: Java, Kotlin

解説

  • DefaultListCellRenderer#paintComponent(...)をオーバーライドしてアイテム選択時(このサンプルでは左余白として使用しているIconが設定されている場合)選択状態表示を矩形ではなくラウンド矩形で描画するよう変更
    • JLabel#setOpaque(false)で背景を描画しないよう設定し、ラウンド矩形の上にアイテムテキストのみ描画する必要がある
    • ラウンド矩形とアイテムのテキストの間隔は空のアイコンとJLabel#setIconTextGap(...)で調整
  • NimbusLookAndFeelSynthComboBoxRendererではなくDefaultListCellRendererを使用するとJList#getSelectionBackground()DerivedColorを返すので選択文字色が黒になってしまう?

参考リンク

コメント