概要

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を返すので選択文字色が黒になってしまう?

参考リンク

コメント