除最后一行外,对JTable进行排序

时间:2013-05-21 15:11:59

标签: java swing jtable tablerowsorter

我有一个JTable,其中最后一行是聚合所有其他行的总行。当用户单击表上的列标题时,行按该列排序,但总行应始终位于底部。

是否有一种简单的方法可以使用TableRowSorter实现此目的?

5 个答案:

答案 0 :(得分:5)

就个人而言,我会创建一个单行的第二个表,删除标题,并将其直接放在主表的下方,以便创建最后一行的错觉。

除了它解决你的排序问题之外,它还会在用户滚动主表时持续存在,这可能是一件好事,因为它是一个“总计”行。

您甚至可以在主表的ColumnModelListener中添加TableColumnModel来同步列调整大小。

编辑:这是一般性的想法:

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class TestFrame implements Runnable
{
  JTable mainTable;
  JTable fixedTable;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new TestFrame());
  }

  public void run()
  {
    mainTable = new JTable(8, 3);
    mainTable.getTableHeader().setReorderingAllowed(false);
    mainTable.setAutoCreateRowSorter(true);

    for (int r = 0; r < 8; r++)
    {
      for (int c = 0; c < 3; c++)
      {
        mainTable.setValueAt((int)(Math.random()*100), r, c);
      }
    }

    mainTable.getColumnModel().addColumnModelListener(
      new TableColumnModelListener()
      {
        public void columnAdded(TableColumnModelEvent e) {}
        public void columnRemoved(TableColumnModelEvent e) {}
        public void columnMoved(TableColumnModelEvent e) {}
        public void columnSelectionChanged(ListSelectionEvent e) {}

        public void columnMarginChanged(ChangeEvent e)
        {
          synchColumnSizes();
        }
      });

    setVisibleRowCount(mainTable, 5);

    JScrollPane scroll = new JScrollPane(mainTable);
    scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    fixedTable = new JTable(1, 3);
    fixedTable.setValueAt("will not sort or", 0, 0);
    fixedTable.setValueAt("scroll but will",  0, 1);
    fixedTable.setValueAt("resize with main", 0, 2);

    JPanel p = new JPanel(new GridBagLayout());
    p.setBorder(BorderFactory.createTitledBorder("Fixed Last Row"));
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.anchor = GridBagConstraints.WEST;
    p.add(scroll, gbc);
    gbc.gridy = 1;
    p.add(fixedTable, gbc);

    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(p, BorderLayout.CENTER);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }

  private void synchColumnSizes()
  {
    TableColumnModel tcmMain = mainTable.getColumnModel();
    TableColumnModel tcmFixed = fixedTable.getColumnModel();

    for (int i = 0; i < tcmMain.getColumnCount(); i++)
    {
      int width = tcmMain.getColumn(i).getWidth();
      tcmFixed.getColumn(i).setPreferredWidth(width);
    }
  }

  public static void setVisibleRowCount(JTable table, int rows)
  {
    table.setPreferredScrollableViewportSize(new Dimension( 
            table.getPreferredScrollableViewportSize().width, 
            rows * table.getRowHeight())); 
  }
}

答案 1 :(得分:2)

  

有没有一种简单的方法可以使用TableRowSorter来实现它?

答案 2 :(得分:2)

以下解决方案对我有用....

在您的表模型中,更新getRowCount()成员以返回少于所需的1行。

然后修改分拣机报告的索引和行数,如下所示......

TableRowSorter<TableModel> sorter =
    new DefaultTableRowSorter<TableModel>(this.getModel()) 
{
    public int convertRowIndexToModel(int index)
    {
        int maxRow = super.getViewRowCount();
        if (index >= maxRow)
            return index;
        return super.convertRowIndexToModel(index);
    }

    public int convertRowIndexToView(int index) 
    {
        int maxRow = super.getModelRowCount();
        if (index > maxRow)
            return index;
        return super.convertRowIndexToView(index);
    }

    public int getViewRowCount() 
    {
        return super.getViewRowCount() + 1;
    }
};

myTable.setRowSorter(sorter);

答案 3 :(得分:1)

@Das:也许这个版本更好,因为你不需要覆盖getRowCount(),这可能会被使用并可能导致其他函数出现问题

public class TableRowSorterTotal<MyTableModel extends TableModel> extends TableRowSorter<TableModel>
{   

    TableRowSorterTotal(MyTableModel model)
    {
        super(model);
    }

    public int convertRowIndexToModel(int index)
    {
        int maxRow = super.getViewRowCount();
        int currModel = super.convertRowIndexToModel(index);
        int maxModel = super.convertRowIndexToModel(maxRow-1);

        if(currModel == maxModel)
            return maxRow - 1;

        if(currModel > maxModel)
            return currModel- 1;

        return currModel;
    }

    public int convertRowIndexToView(int index) 
    {
        int maxRow = super.getModelRowCount();
        int currView= super.convertRowIndexToView(index);
        int maxView = super.convertRowIndexToView(maxRow-1);

        if(currView == maxView)
            return maxRow - 1;

        if(currView > maxView)
            return currView- 1;

        return currView;
    }
}

答案 4 :(得分:1)

根据此example,下面的完整示例示例说明了已接受的answer中的方法。特别是,

  • getRowCount()TableModel的实施将返回size()的{​​{1}},其中<{>> 比数字少表中显示的行数。

  • List<Employee>getValueAt()的实施说明了对TableModelsum()的调用以及额外行中其余列的一些可能的显示选择在底部。

  • COLUMN_SALARYgetViewRowCount()的实施可以显示额外的行,但排除了合理的filtering

image

TableRowSorter