根据菜单选择添加/删除列

时间:2015-09-05 03:18:10

标签: java swing jtable tablecolumn

我有一个JTable;我想提供一个带复选框的菜单,表格中每列的一个复选框,以允许用户选择要显示或隐藏的列。我写了下面的课程,几乎可以工作。

public class SelectableColumns implements ActionListener
{
  JTable table = null;
  JMenu  menu  = null;    public JMenu getMenu() { return menu; }

  public SelectableColumns(JTable table)
  { 
    this.table = table;
    menu = new JMenu("Columns");

    TableColumnModel columnModel = table.getColumnModel();

    Enumeration<TableColumn> enumerator = columnModel.getColumns();
    while (enumerator.hasMoreElements())
    {
      TableColumn column = enumerator.nextElement();
      String headerName = column.getHeaderValue().toString();
      JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(headerName, true);
      cbmi.addActionListener(this);

      column.setIdentifier(cbmi);

      menu.add(cbmi);
    }
  }

  @Override
  public void actionPerformed(ActionEvent e)
  {
    JCheckBoxMenuItem source = (JCheckBoxMenuItem)e.getSource();
    boolean checked = source.getState();

    TableColumnModel columnModel = table.getColumnModel();
    int columnIndex = columnModel.getColumnIndex(source); // <<-- fails after removing the column
    System.out.printf("Checked: %b, column: %d%n", checked, columnIndex);
    TableColumn column = columnModel.getColumn(columnIndex);

    if (checked)
    {
      // add this column back to the table
      table.addColumn(column);
      int displayedColumns = getDisplayedColumns(columnModel);
      table.moveColumn(displayedColumns, displayedColumns-1);
    }
    else
    {
      // remove this column from the table
      table.removeColumn(column);
    }
  }

  private int getDisplayedColumns(TableColumnModel columnModel)
  {
    Enumeration<TableColumn> columns = columnModel.getColumns();
    int displayedCount = 0;
    while (columns.hasMoreElements())
    {
      displayedCount++;
    }
    return displayedCount;
  }
}

我遇到的问题是,一旦删除了列,它就不再出现在TableColumnModel中;我希望该列位于TableColumnModel中,但不再位于JTable中。

但我错了:方法TableColumnModel.getColumn(int index)在显示列时有效,在显示列后失败。当我检查调试器中的TableColumnModel实例时,很明显该列已从模型中删除。

有没有办法做我想要的?我可以创建一个列的集合来重新插入缺少的列,但是我读过的一些文档让我相信该表只是模型的一个视图,所以我坚持这个信念专栏在那里。谁能告诉我在哪里找到它?

非常感谢camickr;我以为我会发布我最后的课程:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

/**
 * Holds representation of columns from the given JTable, including
 * a JMenu and its action routine for removing them and replacing
 * them in the table.  
 * <P>To use, create an instance with your table after
 * it has at least enough data to establish its columns.  Then use
 * getMenu() for an instance of JMenu, and put it on your menu bar.
 * The resulting menu will have checkboxes for all the columns, and
 * it handles their removal and addition.  No other code in the application
 * should remove or add columns; their added/removal state is maintained
 * in the SelectableColumns instance.
 * 
 * @author rcook
 */
public class SelectableColumns implements ActionListener
{
  JTable table = null;
  JMenu  menu  = null;    public JMenu getMenu() { return menu; }

  ArrayList<TableColumn> removedColumns = new ArrayList<TableColumn>();

  public SelectableColumns(JTable table)
  { 
    this.table = table;
    menu = new JMenu("Columns");

    TableColumnModel columnModel = table.getColumnModel();

    Enumeration<TableColumn> enumerator = columnModel.getColumns();
    while (enumerator.hasMoreElements())
    {
      TableColumn column = enumerator.nextElement();
      String headerName = column.getHeaderValue().toString();
      JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(headerName, true);
      cbmi.addActionListener(this);

      column.setIdentifier(cbmi);

      menu.add(cbmi);
    }
  }

  /**
   * A Checkbox menu item representing one column has been chosen; it 
   * could have been checked or unchecked.  Put the removed column
   * back into the table, or remove it from the table.
   */
  @Override
  public void actionPerformed(ActionEvent e)
  {
    JCheckBoxMenuItem source = (JCheckBoxMenuItem)e.getSource();
    TableColumnModel columnModel = table.getColumnModel();

    boolean checked = source.getState();
    TableColumn removedColumn = null;
    if (!checked)
    {
      // remove this column from the table
      int columnIndex = columnModel.getColumnIndex(source);
      //System.out.printf("Checked: %b, column: %d%n", checked, columnIndex);
      TableColumn column = columnModel.getColumn(columnIndex);
      table.removeColumn(column);
      removedColumns.add(column);
    }
    else
    {
      // add this column back to the table
      // first find the column in the list of removed columns
      for (TableColumn column: removedColumns)
      {
        if (column.getIdentifier().equals(source)) 
        { 
          removedColumn = column; 
          break; 
        }
      }

      // as long as we actually have a column, add it back to the
      // table
      if (removedColumn == null)
      {
        System.err.println("removedColumn not in the list...");
      }
      else
      {
        table.addColumn(removedColumn);
        int numDisplayed = columnModel.getColumnCount();
        table.moveColumn(numDisplayed-1, numDisplayed-2);  // move to next-to-last position
        removedColumns.remove(removedColumn);
      }
    }
  }

}

我只是添加了一个&#34;已删除列&#34;的列表,并使用它来添加任何已重新检查以显示的已删除列。我总是加回到倒数第二的位置;显然,这可以使其更加灵活,适合一般用途。我还想过有一个方法可以显示带有复选框的对话框,因此用户可以一次更改多个列的状态。但是对于100行代码来说,这就是我现在想要的,并说明了我正在寻找的原则,并且提供了一个很好的提供。

1 个答案:

答案 0 :(得分:4)

  

有没有办法做我想要的?我可以创建一个列集合来重新插入缺少的列,

正确,您需要跟踪您删除的TableColumns。然后,您的弹出菜单需要设置复选框的状态,具体取决于TableColumn是在TableColumnModel中还是在已删除的TableColumns集合中。

或者您可以使用已为您提供此功能的Table Column Manager

此实现还尝试在删除列时跟踪列的位置,以便将其插回到同一位置,而不是仅将其附加到TableColumnModel的末尾。