eec icon indicating copy to clipboard operation
eec copied to clipboard

关于分别修改表头和body样式的问题

Open zhangwx95 opened this issue 1 year ago • 12 comments

麻烦大佬帮忙看下我这个问题,应该是我对样式修改没理解,谢谢。 我现在有个输出的样式的需求,表头所有列宽指定且要换行改字体大小,body不换行以及其他格式要求 我现在通过ListSheet<>添加数据 Sheet sumSheet = new ListSheet<>(resultSummaryPOS).setName("汇总"); 本来想通过setHeadStyle设置表头,但没看到可以设置表头换行的方法 那么通过Column[] 构造列 然后通过sheet.setColumns设置表头,如wiki所写为例,

sheet.setColumns(new Column[] {  
        new Column("编码", "code").setWidth(20.0D).setWrapText(true).setFont(new Font("宋体",10))  
        , new Column("姓名", "name").setWidth(20.0D).setWrapText(true).setFont(new Font("宋体",10)) 
        , new Column("日期", "date").setWidth(20.0D).setWrapText(true).setFont(new Font("宋体",10)) 
        , new Column("数字", "num").setWidth(20.0D).setWrapText(true).setFont(new Font("宋体",10)) 
});

然后我该如何修改body样式?也是如wiki里所写吗?

new Workbook()
    .addSheet(new ListSheet<>(resultSummaryPOS
        , new Column("编码", "code").setFont(new Font("Trebuchet MS", 20))
        , new Column("姓名", "name").setFont(new Font("Trebuchet MS", 20)).setHorizontal(Horizontals.CENTER) // <-- 设置水平居中
        , new Column("日期", "date").setFont(new Font("华文行楷", 11)).setNumFmt("yyyy-mm-dd hh:mm:ss")
        , new Column("数字", "num").setFont(new Font("Bauhaus 93", 14)).setNumFmt("#,##0_);[Red]-#,##0_);0_)") // <- 指定字体和格式化
    )).writeTo(Paths.get("f:/excel"));

那是不是意味着有两个Column[] ,分别是表头和body的,且分别生效互不影响?还是说不是我这么理解的,麻烦大佬,谢谢~

zhangwx95 avatar Nov 07 '24 09:11 zhangwx95

通过new Column("编码", "code").setWidth(20.0D).setWrapText(true).setFont(new Font("宋体",10)) 设置的样式均为body样式,目前只能通过setHeaderStyle设置表头样式

Workbook workbook = new Workbook();
Styles styles = workbook.getStyles();
int headerStyle = styles.addFont(new Font("宋体",10));
// 折行
headerStyle = styles.modifyWrapText(headerStyle, true);
// 水平居中
headerStyle = styles.modifyHorizontal(headerStyle, Horizontals.CENTER);

workbook.addSheet(new ListSheet<>(resultSummaryPOS
        , new Column("编码", "code").setFont(new Font("Trebuchet MS", 20)).setHeaderStyle(headerStyle)
        , new Column("姓名", "name").setFont(new Font("Trebuchet MS", 20)).setHorizontal(Horizontals.CENTER).setHeaderStyle(headerStyle) // <-- 设置水平居中
        , new Column("日期", "date").setFont(new Font("华文行楷", 11)).setNumFmt("yyyy-mm-dd hh:mm:ss").setHeaderStyle(headerStyle)
        , new Column("数字", "num").setFont(new Font("Bauhaus 93", 14)).setNumFmt("#,##0_);[Red]-#,##0_);0_)").setHeaderStyle(headerStyle) // <- 指定字体和格式化
    )).writeTo(Paths.get("f:/excel"));

如果表头样式一样的则可以使用ListSheet.setHeadStyle(headerStyle)来设置统一的表头样式,使用Column.setHeadStyle(headerStyle)可以为每一列设置不同的表头样式,设置不同的背景和颜色可以起到提示作用,可以参考WIKI静态样式设置

wangguanquan avatar Nov 07 '24 11:11 wangguanquan

感谢大佬,在wiki看漏了setHeaderStyle(borderStyle)这个方法 TAT 再问一下,如果不用Column,而是实体类上用了@ExcelColumn注解,生效的也是body样式吗?我看@ExcelColumn注解里没有设置font的方法,是不是意味着要设置body的font只能用Column?感谢~

zhangwx95 avatar Nov 08 '24 01:11 zhangwx95

目前是这样的,你可以使用自定义注解来实现,EEC具有很高的自由度,自定义注解可以参考wiki高级特性

wangguanquan avatar Nov 08 '24 01:11 wangguanquan

明白了,感谢大佬

zhangwx95 avatar Nov 08 '24 02:11 zhangwx95

你可以先尝试做一下,直接复制高级特性里的代码然后将上面的代码添加到Column即可,自定义注解可以更通用

如果只是需要添加样式则可以简单实现大体如下 样式注解可以放在createColumn方法中,表头样式注解一般可以放在对象上不需要每个字段都添加

// 添加body样式
@Override
protected ListSheet.EntryColumn createColumn(AccessibleObject ao) {
    ListSheet.EntryColumn column = super.createColumn(ao);
    // 解析自定义Body样式注解
    ExcelStyle bodyStyle = ao.getAnnotation(ExcelStyle.class);
    if (bodyStyle != null) {
        Font font = headerStyle.getFont();
        if (font != null) {
            // 修改表头样式
            column.setFont(font);
        }
        ... 复制上面的代码添加样式
    }
}

// 添加header样式
protected void buildHeaderStyle(AccessibleObject main, AccessibleObject sub, Column column) {
    // 从对象头上拿到注释
   ExcelStyle headerStyle = tClazz.getAnnotation(ExcelStyle.class);
    if (headerStyle != null) {
        Styles styles = workbook.getStyles();
        Font font = headerStyle.getFont();
        int styleIndex = 0;
        if (font != null) {
            styleIndex = styles.modifyFont(styles.createFont(font));
        }
        ... 复制上面的代码
            
        // 修改表头样式
        column.setHeaderStyle(styleIndex);
    }
}

这只是示例效果得自己尝试,如果注释不好使用则可能自定义一个ListSheet传入一个ExcelStyle对象,像下面这样

public class CustomStyleListSheet<T> extends ListSheet<T> {
    private ExcelStyle headerStyle, bodyStyle; // 传入表头和body样式
    public CustomStyleListSheet(ExcelStyle headerStyle, ExcelStyle bodyStyle) {
        this.headerStyle = headerStyle;
        this.bodyStyle = bodyStyle;
    }
    
    // 其它不变方法和上面的一样修改即可,不再需要从注解从获取
}

wangguanquan avatar Nov 08 '24 03:11 wangguanquan

你可以先尝试做一下,直接复制高级特性里的代码然后将上面的代码添加到Column即可,自定义注解可以更通用

如果只是需要添加样式则可以简单实现大体如下 样式注解可以放在createColumn方法中,表头样式注解一般可以放在对象上不需要每个字段都添加

// 添加body样式
@Override
protected ListSheet.EntryColumn createColumn(AccessibleObject ao) {
    ListSheet.EntryColumn column = super.createColumn(ao);
    // 解析自定义Body样式注解
    ExcelStyle bodyStyle = ao.getAnnotation(ExcelStyle.class);
    if (bodyStyle != null) {
        Font font = headerStyle.getFont();
        if (font != null) {
            // 修改表头样式
            column.setFont(font);
        }
        ... 复制上面的代码添加样式
    }
}

// 添加header样式
protected void buildHeaderStyle(AccessibleObject main, AccessibleObject sub, Column column) {
    // 从对象头上拿到注释
   ExcelStyle headerStyle = tClazz.getAnnotation(ExcelStyle.class);
    if (headerStyle != null) {
        Styles styles = workbook.getStyles();
        Font font = headerStyle.getFont();
        int styleIndex = 0;
        if (font != null) {
            styleIndex = styles.modifyFont(styles.createFont(font));
        }
        ... 复制上面的代码
            
        // 修改表头样式
        column.setHeaderStyle(styleIndex);
    }
}

这只是示例效果得自己尝试,如果注释不好使用则可能自定义一个ListSheet传入一个ExcelStyle对象,像下面这样

public class CustomStyleListSheet<T> extends ListSheet<T> {
    private ExcelStyle headerStyle, bodyStyle; // 传入表头和body样式
    public CustomStyleListSheet(ExcelStyle headerStyle, ExcelStyle bodyStyle) {
        this.headerStyle = headerStyle;
        this.bodyStyle = bodyStyle;
    }
    
    // 其它不变方法和上面的一样修改即可,不再需要从注解从获取
}

好的,看上去自定义一个ListSheet传入一个ExcelStyle对象好像更简单点,我有空了一定尝试下到时候回复;

现在遇到个新问题,设置表头自动换行后,高度没有自适应调整,表头样式里确实也没找到调整高度的地方? image

zhangwx95 avatar Nov 08 '24 03:11 zhangwx95

EEC默认表头行高20.5与Body相区隔这里没有考虑到wrapText后续改进。Sheet有一个方法setHeaderRowHeight可以用于设置高度,正数为实际行高,负数表示不设置自动计算new ListSheet<>().setHeaderRowHeight(-1)

wangguanquan avatar Nov 08 '24 04:11 wangguanquan

谢谢大佬,setHeaderRowHeight(-1)可以生效 我自己尝试了自定义注解,表头已经生效了, 但是自定义的body没有生效,我把body注解也放在对象上,打断点看是因为bodyStyle为null,麻烦看看问题在哪,感谢~ 自定义注解

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface HeaderExcelStyle {

    String fontName() default "宋体";

    int fontSize() default 10;

    boolean wrapText() default true;

    ColorDefine color() default ColorDefine.Z_BLUE;

}



@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface BodyExcelStyle {
    String fontName() default "宋体";

    int fontSize() default 10;

    double width() default 11D;

}

自定义ListSheet

 @Override
    protected ListSheet.EntryColumn createColumn(AccessibleObject ao) {
        ListSheet.EntryColumn column = super.createColumn(ao);
//        // 解析自定义Body样式注解
        BodyExcelStyle bodyStyle = ao.getAnnotation(BodyExcelStyle.class);
        if (bodyStyle != null) {
            Font font = new Font(bodyStyle.fontName(),bodyStyle.fontSize());
            if (font != null) {
                // 修改表头样式
                column.setFont(font);
            }

        }
        return column;
    }

    // 添加header样式
    @Override
    protected void buildHeaderStyle(AccessibleObject main, AccessibleObject sub, Column column) {
        // 从对象头上拿到注释
        HeaderExcelStyle headerStyle = tClazz.getAnnotation(HeaderExcelStyle.class);
        if (headerStyle != null) {
            Styles styles = workbook.getStyles();
            Font font = new Font(headerStyle.fontName(), headerStyle.fontSize());
            int styleIndex = 0;
            if (font != null) {
                styleIndex = styles.addFont(font);
            }
            styleIndex = styles.modifyHorizontal(styleIndex, Horizontals.CENTER);
            styleIndex = styles.modifyVertical(styleIndex, Verticals.CENTER);
            styleIndex = styles.modifyWrapText(styleIndex, headerStyle.wrapText());
            Color color = headerStyle.color().getRGB();
            if (color != null) {
                styleIndex = styles.modifyFill(styleIndex, new Fill(PatternType.solid, color));
            }

            // 修改表头样式
            column.setHeaderStyle(styleIndex);
        }

    }

zhangwx95 avatar Nov 08 '24 08:11 zhangwx95

优秀,这样写已经可以满足你现在的需求,不过可以更进一步通用化,可以包含所有Style样式不限制字体,折行和颜色两种样式。 还可以将行高放在buildHeaderStyle方法,wrapText=true时默认将HeaderRowHeight设为-1,这样在外部就不需要再次设置了

wangguanquan avatar Nov 08 '24 10:11 wangguanquan

优秀,这样写已经可以满足你现在的需求,不过可以更进一步通用化,可以包含所有Style样式不限制字体,折行和颜色两种样式。 还可以将行高放在buildHeaderStyle方法,wrapText=true时默认将HeaderRowHeight设为-1,这样在外部就不需要再次设置了

谢谢大佬,行高设置我修改后生效了

if(headerStyle.wrapText()){
                headerRowHeight = -1;
            }

不过没太懂 可以包含所有Style样式不限制字体,折行和颜色两种样式 这个是什么意思?

zhangwx95 avatar Nov 11 '24 01:11 zhangwx95

优秀,这样写已经可以满足你现在的需求,不过可以更进一步通用化,可以包含所有Style样式不限制字体,折行和颜色两种样式。 还可以将行高放在buildHeaderStyle方法,wrapText=true时默认将HeaderRowHeight设为-1,这样在外部就不需要再次设置了

谢谢大佬,行高设置我修改后生效了

if(headerStyle.wrapText()){
                headerRowHeight = -1;
            }

不过没太懂 可以包含所有Style样式不限制字体,折行和颜色两种样式 这个是什么意思?

我看BodyExcelStyle只定义了字体,折行和颜色,所以建议写个更通用的,比如加上背景,边框,格式化,垂直对齐,水平对齐这几个样式,当然这个并不是必须的,根据业务需求来适配即可。

wangguanquan avatar Nov 11 '24 02:11 wangguanquan

优秀,这样写已经可以满足你现在的需求,不过可以更进一步通用化,可以包含所有Style样式不限制字体,折行和颜色两种样式。 还可以将行高放在buildHeaderStyle方法,wrapText=true时默认将HeaderRowHeight设为-1,这样在外部就不需要再次设置了

谢谢大佬,行高设置我修改后生效了

if(headerStyle.wrapText()){
                headerRowHeight = -1;
            }

不过没太懂 可以包含所有Style样式不限制字体,折行和颜色两种样式 这个是什么意思?

我看BodyExcelStyle只定义了字体,折行和颜色,所以建议写个更通用的,比如加上背景,边框,格式化,垂直对齐,水平对齐这几个样式,当然这个并不是必须的,根据业务需求来适配即可。

哦哦 看懂了 断句断错了哈哈哈哈 谢谢大佬

zhangwx95 avatar Nov 11 '24 02:11 zhangwx95