通过POI在Excel表格的标题上设置筛选器

56

我生成了一个带有标准标题和数据列的表格。

我想为该表格开启“筛选”功能,以便用户可以轻松地对数据进行排序和筛选。

我能否使用POI来实现这一点?


1
可能是POI自动筛选器的重复问题。 - beldaz
5个回答

80

保存筛选区域的第一个和最后一个单元格,并执行:

sheet.setAutoFilter(new CellRangeAddress(firstCell.getRow(), lastCell.getRow(), firstCell.getCol(), lastCell.getCol()));

例如,从下面的表格中。

>x         (x, y)
  0123456  
0|--hhh--|   h = header
1|--+++--|   + = values
2|--+++--|   - = empty fields
3|--+++--|
4|-------|

第一个单元格将是第一个+(2,1)单元格上方的标题。最后一个单元格将是最后一个+单元格(5,3)。


7
好的。看起来我可以使用以下代码:s.setAutoFilter(CellRangeAddress.valueOf("A1:E1")); 这个区域仅涵盖标题单元格,不包括数据单元格。但是,这个结果正是我想要的。 - Anders Johansen
1
s.setAutoFilter(CellRangeAddress.valueOf("A1:N1")); 通过这个方法,我们可以对数据进行筛选。 - swamy
7
你的意思是最后一个单元格是(4, 3)吗? - amphibient
4
我认为单元格的API可能已经发生了改变。我必须使用这个范围:new CellRangeAddress( firstCell.getRowIndex(), lastCell.getRowIndex(), firstCell.getColumnIndex(), lastCell.getColumnIndex() )。现在getRow()返回一个行对象而不是索引,getCol()已不存在。 - Matt Pennington
现在的方法是sheet.SetAutoFilter(),其中S要大写。 - Chegon
显示剩余2条评论

27
在标题上添加过滤器的最简单方法:
sheet.setAutoFilter(new CellRangeAddress(0, 0, 0, numColumns));
sheet.createFreezePane(0, 1);

11
小修正:应该是 numColumns - 1 (否则最后会多出一个过滤器列)。 - Priidu Neemre
既然numColumns是一个变量,为什么要减去一个值呢?你可以直接定义它,例如:如果你期望有9个,你不需要将其设置为10并减去1... - Tiago Medici
2
这更多是一个概念性的评论,而不是逐字逐句的代码 :). 要点是 CellRangeAddress 的构造函数是从零开始索引和包含边界的。因此,如果您正在基于某些内容计算 numColumns,则需要考虑这一点。 - Priidu Neemre
2
我同意@PriiduNeemre的观点。我认为lastIndexnumColumns更合适(或者我会使用numColumns - 1)。 - Julio

4
如果您想以编程方式设置过滤器,可以使用以下代码:
void setAutoFilter(final XSSFSheet sheet, final int column, final String value) {
    sheet.setAutoFilter(CellRangeAddress.valueOf("A1:Z1"));

    final CTAutoFilter sheetFilter = sheet.getCTWorksheet().getAutoFilter();
    final CTFilterColumn filterColumn = sheetFilter.addNewFilterColumn();
    filterColumn.setColId(column);
    final CTFilter filter = filterColumn.addNewFilters().insertNewFilter(0);
    filter.setVal(value);

    // We have to apply the filter ourselves by hiding the rows: 
    for (final Row row : sheet) {
        for (final Cell c : row) {
            if (c.getColumnIndex() == column && !c.getStringCellValue().equals(value)) {
                final XSSFRow r1 = (XSSFRow) c.getRow();
                if (r1.getRowNum() != 0) { // skip header
                    r1.getCTRow().setHidden(true);
                }
            }
        }
    }
}

相关的Gradle依赖项:

    // https://mvnrepository.com/artifact/org.apache.poi/poi
compile group: 'org.apache.poi', name: 'poi', version: '3.9'

// https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.9'

// https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas
compile group: 'org.apache.poi', name: 'poi-ooxml-schemas', version: '3.9'

// https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas
compile group: 'org.apache.poi', name: 'ooxml-schemas', version: '1.3'

3
我使用 NPOI 解决了这个问题。
你需要将 CT_AutoFilter 添加到 CT_Table 中。
我猜 POI 和 NPOI 的操作方式应该相同。
    cttable.autoFilter = new CT_AutoFilter();
    cttable.autoFilter.@ref = "A1:C5";   // value is data and includes header.

谢谢,这是唯一对我有效的方法。使用其他答案,Excel会不断地清除我的表格。 - Nathan Champion
这个功能非常有效:它在表格中设置了自动筛选(并直接进入表格实体)。在工作表上调用SetAutoFilter会向工作表添加一些数据,但在我的情况下,它还会导致Excel抱怨并修复文档,将表格删除。 - Yennefer

1

使用 sheet.setAutoFilter(CellRangeAddress.valueOf("B1:H1"));

我们需要指定表格数据的表头单元格。在我的示例中,表头从单元格B1开始,结束于单元格H1
Excel会自动查找下面的数据并在筛选选项中显示它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接