表格的核心是二维数组。
因此填充数据的时候,只需要将一个二维数组按从上到下、从左到右的顺序依次填充即可。
但是表格往往有表头标题栏(可能还有多行的、带分组的标题表头)、底部汇总栏等。
为了让构造二维数组的时候更方便,我们在表格的类实现上做了一些设计。
1 1 1 1 1 → row
2 2 2 2 2
↓
col
int[][] data = new int[2][5];
data[0] = new int[]{1,1,1,1,1};
data[1] = new int[]{2,2,2,2,2};
Table t = new Table(data);
// 当然,直接操作数组会很繁琐。更实际的例子一般是从数据库(或其他数据源)查出一个List。
List<User> users = findUsers();
class User {
String name;
String phone;
String address;
}
String[] header = new String[]{ "name", "address", "phone"};
// 将 User 映射到 Object[] 的时候,用 header 来控制顺序
// Object[0] = user.name
// Object[1] = user.address
// Object[2] = user.phone
Table t1 = new Table();
t1.setData(header, users);table with header in the top 表头在表格顶部
Table t = new Table(new Object[2][5]);
Object[][] header = new Object[][]{"a","b","c","d","e"}; // Object[1][5]
t.merge(Position.TOP, header);a b c d e 1 1 1 1 1 2 2 2 2 2
table with header in the left 表头在表格左侧
Table t = new Table(new Object[3][4]);
Object[][] header = new Object[][]{ {"a"},{"b"},{"c"}};// Object[3][1]
t.merge(Position.LEFT, header);a 1 2 3 4 b 1 2 3 4 c 1 2 3 4
table with header in the left, and then another header in the top
先加一个左侧的表头,再在顶部加一个表头
Table t = new Table(new Object[3][4]);
t.merge(Position.LEFT, new Object[3][1]);
t.merge(Position.TOP, new Object[1][5]);A B C D E a 1 2 3 4 b 1 2 3 4 c 1 2 3 4
table with header in the top, and then another header in the left
先在顶部加一个表头,再在左侧加一个表头
Table t = new Table(new Object[3][4]);
t.merge(Position.TOP, new Object[1][4])
t.merge(Position.LEFT, new Object[4][1])a A B C D b 1 2 3 4 c 1 2 3 4 d 1 2 3 4
其他的复杂表格,如多行表头、分组、底部带有合计汇总等,将表格合理拆分后,用merge方法合并成一个大表格即可。
for指令
假设模板UI上的表格大小是4 * 4。
当传入的表格数据是 5 * 5 时,UI会自动扩展(引擎默认取最后一行、最后一列为模板复制)。
当传入的表格数据是 3 * 3 时,UI会自动裁剪(引擎默认从最后一行、最后一列开始删除)。
注意1:引擎没有对表格样式(宽高)做特殊处理。
PPT 自己的逻辑是:
- 表格总高度随着行的增加/删除而变化。
- 表格总宽度不变,列宽自动按比例调整。
注意2:引擎没有对表格内自动新增的单元格样式做处理。
如果你在设置样式的时候,是对整个表格设置的样式,那么新增的行也会自动生效。
但如果你不是给表格设置,而是给单元格设置样式,那么新增的行里不会复制样式。
另外,如果模板设置了字体,
poi渲染的结果是丢失了字体,
aspose渲染的结果会保留字体。
如果要保留字体,商业用途的话,建议用aspose。
如果用poi,就用定制化函数钩子重新设置字体。
参见表格导出,里面设置的字体大小样式,导出字体大小很大,这个怎么处理?
这种情况下,如果你的PPT页最多放一个5行的表格,建议设置模板的时候就插入5行,然后预先设置好样式。
这样当实际传入少于5行时,也会自动清除多余的行。
但如果模板只放一行,原本是期望复制上一行的样式做为新增行样式的。
但实际未实现(aspose倒是支持,poi还是相对简陋)。
考虑到实现成本,目前暂不考虑实现。
表格是个非常常用的组件。
同时也会有非常多的定制化需求,最常见的莫过于合并单元格。
每次做一点小小的改动,都要去自定义processor,感觉确实太繁琐。
但是在engine内实现太具体的细节,又感觉不合适。
因此增加了一个定制化函数钩子,可以在里面实现一些风格的定制化。
SimpleEngine engine = new SimpleEngine("src/test/resources/table-hook.pptx");
DataSource dataSource = new DataSource();
String[] headers = new String[]{
"goods",
"year",
"price"
};
List<Trend> trends = new ArrayList<>();
trends.add(new Trend("cloth", 2021, 300));
trends.add(new Trend("cloth", 2022, 600));
trends.add(new Trend("cloth", 2023, 900));
trends.add(new Trend("drink", 2021, 400));
trends.add(new Trend("drink", 2022, 600));
trends.add(new Trend("drink", 2023, 800));
Table tableA = new Table();
tableA.setCustomizeFunction(table -> {
table.mergeCells(1,3,0,0); // 合并第1列的2-4行单元格
table.mergeCells(4,6,0,0); // 合并第1列的5-7行单元格
});
tableA.setData(headers, trends, Table.Direction.HORIZONTAL);
tableA.merge(Table.Position.TOP, new Object[1][1]);
dataSource.setVariable("tableA", tableA);
engine.setDataSource(dataSource);
engine.process();
String outputfile = "src/test/resources/test-table-hook.pptx";
engine.save(outputfile);