概要

JComboBoxのドロップダウンリストとしてJListの代わりにJTableを使用します。

サンプルコード

class DropdownTableComboBox<E extends Vector<Object>> extends JComboBox<E> {
  protected final transient HighlightListener highlighter = new HighlightListener();
  protected final JTable table = new JTable() {
    @Override public Component prepareRenderer(
          TableCellRenderer renderer, int row, int column) {
      Component c = super.prepareRenderer(renderer, row, column);
      c.setForeground(Color.BLACK);
      if (highlighter.isHighlightableRow(row)) {
        c.setBackground(new Color(255, 200, 200));
      } else if (isRowSelected(row)) {
        c.setBackground(Color.CYAN);
      } else {
        c.setBackground(Color.WHITE);
      }
      return c;
    }
    @Override public void updateUI() {
      removeMouseListener(highlighter);
      removeMouseMotionListener(highlighter);
      super.updateUI();
      addMouseListener(highlighter);
      addMouseMotionListener(highlighter);
      getTableHeader().setReorderingAllowed(false);
    }
  };
  protected final List<E> list;

  protected DropdownTableComboBox(List<E> list, DefaultTableModel model) {
    super();
    this.list = list;
    table.setModel(model);
    list.forEach(this::addItem);
    list.forEach(model::addRow);
  }

  @Override public void updateUI() {
    super.updateUI();
    EventQueue.invokeLater(() -> {
      setUI(new MetalComboBoxUI() {
        @Override protected ComboPopup createPopup() {
          return new ComboTablePopup(comboBox, table);
        }
      });
      setEditable(false);
    });
  }
  public List<Object> getSelectedRow() {
    return list.get(getSelectedIndex());
  }
}
view all

解説

  • JListではなくJTableを使用するBasicComboPopupを作成
    • JTableなので、ヘッダや複数列の設定などが可能
  • MetalComboBoxUI#createPopup()メソッドをオーバーライドして、JComboBoxのドロップダウンリストとして設定
class ComboTablePopup extends BasicComboPopup {
  private final JTable table;
  private final JScrollPane scroll;
  protected ComboTablePopup(JComboBox<?> combo, JTable table) {
    super(combo);
    this.table = table;

    ListSelectionModel sm = table.getSelectionModel();
    sm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    sm.addListSelectionListener(e -> {
      combo.setSelectedIndex(table.getSelectedRow());
    });

    combo.addItemListener(e -> {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        setRowSelection(combo.getSelectedIndex());
      }
    });

    table.addMouseListener(new MouseAdapter() {
      @Override public void mousePressed(MouseEvent e) {
        combo.setSelectedIndex(table.rowAtPoint(e.getPoint()));
        setVisible(false);
      }
    });

    scroll = new JScrollPane(table);
    setBorder(BorderFactory.createEmptyBorder());
  }
  @Override public void show() {
    if (isEnabled()) {
      Insets ins = scroll.getInsets();
      int tableh = table.getPreferredSize().height;
      int headerh = table.getTableHeader().getPreferredSize().height;
      scroll.setPreferredSize(new Dimension(
          240, tableh + headerh + ins.top + ins.bottom));
      super.removeAll();
      super.add(scroll);
      setRowSelection(comboBox.getSelectedIndex());
      super.show(comboBox, 0, comboBox.getBounds().height);
    }
  }
  private void setRowSelection(int index) {
    if (index != -1) {
      table.setRowSelectionInterval(index, index);
      table.scrollRectToVisible(table.getCellRect(index, 0, true));
    }
  }
}

参考リンク

コメント