Google Tag Manager

2020/10/31

Show or hide each TableColumn added to the JTableHeader

Code

class TableHeaderPopupMenu extends JPopupMenu {
  protected TableHeaderPopupMenu(JTable table) {
    super();
    TableColumnModel columnModel = table.getColumnModel();
    List>TableColumn> list = Collections.list(columnModel.getColumns());
    list.forEach(tableColumn -> {
      String name = Objects.toString(tableColumn.getHeaderValue());
      // System.out.format("%s - %s%n", name, tableColumn.getIdentifier());
      JCheckBoxMenuItem item = new JCheckBoxMenuItem(name, true);
      item.addItemListener(e -> {
        if (((AbstractButton) e.getItemSelectable()).isSelected()) {
          columnModel.addColumn(tableColumn);
        } else {
          columnModel.removeColumn(tableColumn);
        }
        updateMenuItems(columnModel);
      });
      add(item);
    });
  }

  @Override public void show(Component c, int x, int y) {
    if (c instanceof JTableHeader) {
      JTableHeader header = (JTableHeader) c;
      JTable table = header.getTable();
      header.setDraggedColumn(null);
      header.repaint();
      table.repaint();
      updateMenuItems(header.getColumnModel());
      super.show(c, x, y);
    }
  }

  private void updateMenuItems(TableColumnModel columnModel) {
    boolean isOnlyOneMenu = columnModel.getColumnCount() == 1;
    if (isOnlyOneMenu) {
      stream(this).map(MenuElement::getComponent).forEach(mi ->
          mi.setEnabled(!(mi instanceof AbstractButton)
                        || !((AbstractButton) mi).isSelected()));
    } else {
      stream(this).forEach(me -> me.getComponent().setEnabled(true));
    }
  }

  private static Stream>MenuElement> stream(MenuElement me) {
    return Stream.of(me.getSubElements())
      .flatMap(m -> Stream.concat(Stream.of(m), stream(m)));
  }
}

Explanation

  • Initially shows all TableColumns generated from a TableModel
    • All JCheckBoxMenuItems are also selected
  • TableColumn hidden with TableColumnModel#removeColumn(TableColumn) method when deselected with JCheckBoxMenuItem
    • The column is removed from TableColumnModel and hidden from JTableHeader, but the column remains in TableModel
    • Check the number of TableColumn columns to enable/disable the JCheckBoxMenuItem, e.g. when opening a JPopupMenu, so that all TableColumns are not hidden
  • Show TableColumn with TableColumnModel#addColumn(TableColumn) method when selected and set with JCheckBoxMenuItem
    • Columns are added to TableColumnModel and appear in JTableHeader, but TableModel is unchanged from its initial state

  • UIManager.put("CheckBoxMenuItem.doNotCloseOnMouseClick", true) in Java 9 or higher; If set to and the currently selected TableColumn is hidden with JCheckBoxMenuItem while JPopupMenu is open, an ArrayIndexOutOfBoundsException will occur
    • Add PopupMenuListener to JPopupMenu or override the JPopupMenu#show(...) method to JTableHeader.setDraggedColumn(null) can be avoided by clearing the selection state in the scene view

References

No comments:

Post a Comment