如何在JTable

时间:2015-09-14 20:45:06

标签: java swing jtable jcombobox tablecellrenderer

我想要一个对话框,为JTable中的数据指定过滤器。该对话框将有第二个JTable;其中一列将代表过滤器适用的第一个JTable中的列;其他列之一将是用于过滤的字符串。

我在真实应用中的第二个JTable中有其他列 - 过滤器是否确保字符串存在或不存在等等 - 但这些对问题并不重要。

我为TableColumn创建并安装了自定义渲染器和编辑器,并为TableColumn类注册了第二个表;我希望表示第二个表中列的字符串是TableColumn的标题,并且能够引用实际的TableColumn作为正在编辑的项目。

在我到目前为止的代码中,当我第一次显示带有一行伪数据的对话框时,确实显示了伪数据中列的标题值。但是,当我单击该值时,每列的下拉值是执行tableColumn.toString()时获得的字符串。

构建单元格编辑器下拉列表的代码会将TableColumn值放在JComboBox<TableColumn>中,正如我认为的那样;如何让编辑器使用tableColumn中的标头值而不是使用它的toString(),或者它正在做什么?

还有一件事:在真实应用中,第一个JTable中的列是动态的;我不能简单地列出代码中的列。我从数据中导出列数及其标题。请不要只给我一些例子,假设要编辑的列是提前知道的。如果有人可以解释它是如何工作而不只是举例,那就太棒了,但如果我们必须完全通过例子进行沟通,请包括表格的动态性质。

package lincoln.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Enumeration;

import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;

@SuppressWarnings("serial")
public class ExampleColumnCombo extends JFrame
{
  private JButton getDialogButton = null;

  public static void main(String ... arguments)
  {
    ExampleColumnCombo me = new ExampleColumnCombo();
    me.go(arguments);
  }

  private void go(String ... arguments)
  {
    createUI(this);
    setVisible(true);
  }

  // defines one filter test: each item defines a column to test 
  // and the value to test in it.
  class FilterItem
  {
    private TableColumn column            = null;
    private String      targetString      = null;

    public FilterItem  (TableColumn tc, String targetString)
    {
      column = tc;
      this.targetString = targetString;
    }
    public TableColumn getColumn()        { return column; }
    public String      getTargetString()  { return targetString; }
  }

  private void createUI(final ExampleColumnCombo mainFrame)
  {
    Object[][] data = { { "color", "red" }, {"shape", "square"}, {"fruit", "banana"}, {"plain", "text"}};
    String[] columnNames = {"type", "value" };
    DefaultTableModel model = new DefaultTableModel(data, columnNames);
    final JTable table = new JTable(model);

    getDialogButton = new JButton("filters");
    getDialogButton.addActionListener
    (
        new ActionListener()
        {
          public void actionPerformed(ActionEvent event)
          {
            FilterModel filterModel = new FilterModel();
            filterModel.addItem(new FilterItem(table.getColumnModel().getColumn(0), "color"));
            FilterDialog dialog = new FilterDialog(mainFrame, filterModel);
            dialog.setVisible(true);
          }
        }
    );

    JPanel upperPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
    upperPanel.add(getDialogButton);
    add(upperPanel, BorderLayout.NORTH);

    JScrollPane scrollPane = new JScrollPane(table);
    add(scrollPane, BorderLayout.CENTER);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300,300);
    setLocationByPlatform(true);
  }

  class FilterModel extends AbstractTableModel
  {
    private ArrayList<FilterItem> filters = new ArrayList<>();

    public int getColumnCount()                         { return 2; }
    public boolean isCellEditable(int row, int column)  { return true; }

    public Class<?> getColumnClass(int i)
    {
      switch (i)
      { 
      case 0: return TableColumn.class; 
      case 1: return String.class;
      default: System.err.println("error, bad column given for class");
      }
      return null;
    }

    @Override
    public int getRowCount()    {      return filters.size();    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex)
    {
      FilterItem item = filters.get(rowIndex);
      switch(columnIndex)
      {
      case 0: return item.getColumn();       //break;
      case 1: return item.getTargetString(); //break;
      default: System.err.println("wrong"); new Exception().printStackTrace(); break;
      }
      return null;
    } 

    public void addItem(FilterItem item)
    {
      filters.add(item);
    }
  }

  class FilterDialog extends JDialog
  {
    public FilterDialog(ExampleColumnCombo mainDisplay, 
                        final FilterModel filterModel)
    {
      JTable table = new JTable(filterModel);

      table.setDefaultRenderer(TableColumn.class, new TableColumnCellRenderer());
      table.setDefaultEditor(TableColumn.class, new TableColumnCellEditor());

      JScrollPane scrollPane = new JScrollPane(table);
      add(scrollPane);
      setSize(200,200);
      pack();
      setVisible(true);
    }
  }

  class TableColumnCellEditor extends AbstractCellEditor implements
      TableCellEditor, ActionListener
  {
    private TableColumn tableColumn;
    public TableColumnCellEditor() {}

    @Override
    public Object getCellEditorValue()
    {
      return tableColumn;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
        boolean isSelected, int row, int col)
    {
      if (value instanceof TableColumn) 
      { 
        tableColumn = (TableColumn)value;
      }

      JComboBox<TableColumn> comboTableColumnType = new JComboBox<>();

      Enumeration<TableColumn> columnEnumeration = table.getColumnModel().getColumns();
      while (columnEnumeration.hasMoreElements())
      {
        TableColumn column = (TableColumn)columnEnumeration.nextElement();
        comboTableColumnType.addItem(column);
      }
      comboTableColumnType.setSelectedItem(value);
      comboTableColumnType.addActionListener(this);

      return comboTableColumnType;
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
      @SuppressWarnings("unchecked")
      JComboBox<TableColumn> comboTableColumnType = (JComboBox<TableColumn>) e.getSource();
      this.tableColumn = (TableColumn)comboTableColumnType.getSelectedItem();
    }

    @Override
    public String toString()
    {
      return this.tableColumn.getHeaderValue().toString();
    }

  }

  public class TableColumnCellRenderer extends DefaultTableCellRenderer
  {
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
        int row, int column)
    {
      if (value instanceof TableColumn)
      {
        TableColumn tableColumn = (TableColumn) value;
        Object o = tableColumn.getHeaderValue();
        setText((String)o);
      }
      return this;
    }
  }

}

1 个答案:

答案 0 :(得分:2)

一种方法是使用JComboBox<String>作为编辑器,并使用getHeaderValue().toString()返回的结果填充其模型。

image

JComboBox<String> comboTableColumnType = new JComboBox<>();

Enumeration<TableColumn> columnEnumeration = table.getColumnModel().getColumns();
while (columnEnumeration.hasMoreElements()) {
    TableColumn column = (TableColumn) columnEnumeration.nextElement();
    comboTableColumnType.addItem(column.getHeaderValue().toString());
}

无需覆盖toString()中的TableColumnCellEditor