Apache POI: Cómo definir estilos en archivos excel

En la entrada anterior sobre apache POI, vimos como crear archivos excel con Java y Apache POI. En esta ocasión, véremos como personalizar el estilo de los archivos excel generados.

Cómo crear un estilo de celda

La clase que representa un estilo de una celda es HSSFCellStyle. Nos permite definir características propias de la celda: tipo de borde, color del borde, alineación del contenido, color de fondo, etc. Para crear un estilo de celda, solo necesitamos una referencia al libro de trabajo de excel:

HSSFWorkbook workbook = new HSSFWorkbook();
HSSFCellStyle style = workbook.createCellStyle();

Una vez creado el estilo, podemos invocar sus métodos set...(), para configurar cada una de sus propiedades. La clase HSSFCellStyle posee una serie de propiedes definidas que nos ayudarán a configurar nuestro estilo. Así mismo, la clase que nos permite definir los colores utilizados en nuestros estilos es HSSFColor:

// Sets the cell background
style.setFillForegroundColor(HSSFColor.BLUE_GREY.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

Probablemente, también querremos modificar las propiedades del texto que se muestra en las celdas. Para hacer esto, debemos crear un estilo de fuente (a continuación).

Cómo crear un estilo de fuente

Los estilos de fuente está representados por la clase HSSFFont. Esta clase nos da control sobre la fuente tipográfica usada, color del texto, negrita, cursiva, etc. Al igual que los estilos de celdas, podemos crear estilos de fuentes a partir del libro de trabajo:

HSSFFont font = workbook.createFont();

Una vez tenemos la fuente, la asignamos al estilo donde queremos aplicarla:

style.setFont(font);

Ejemplo Completo

Como ejemplo, vamos a generar un archivo excel tal que así:

final_excel_with_styleUtilizaremos una clase auxiliar llamada FakeDataProvider, que simplemente nos devuelve de datos de prueba para rellenar la tabla:

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public final class FakeDataProvider {
 
    /** Return the columns name for the table */
    public static List<String> getTableHeaders() {
        List<String> tableHeader = new ArrayList<String>();
        tableHeader.add("Name");
        tableHeader.add("Address");
        tableHeader.add("Phone");
 
        return tableHeader;
    }
 
 
    /**
     * Return values for the table
     * 
     * @param numberOfRows Number of rows we want to receive
     * 
     * @return Values
     */
    public static List<List<String>> getTableContent(int numberOfRows) {
        if (numberOfRows <= 0) {
            throw new IllegalArgumentException("The number of rows must be a positive integer");
        }
 
        List<List<String>> tableContent = new ArrayList<List<String>>();
 
        List<String> row = null;
        for (int i = 0; i < numberOfRows; i++) {
            tableContent.add(row = new ArrayList<String>());
            row.add("my name is " + i);
            row.add("my address is " + i);
            row.add("my phone is " + i);
        }
 
        return tableContent;
    }
 
}

La clase encargada de la generación del excel es ExcelGenerator. Tiene un sólo método público, generateExcel(), que devuelve el excel generado:

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
public class ExcelGenerator {
 
	// Excel work book
	private HSSFWorkbook workbook;
 
	// Fonts
	private HSSFFont headerFont;
	private HSSFFont contentFont;
 
	// Styles
	private HSSFCellStyle headerStyle;
	private HSSFCellStyle oddRowStyle;
	private HSSFCellStyle evenRowStyle;
 
	// Integer to store the index of the next row
	private int rowIndex;
 
 
	/**
	 * Make a new excel workbook with sheet that contains a stylized table
	 * 
	 * @return
	 */
	public HSSFWorkbook generateExcel() {
 
		// Initialize rowIndex
		rowIndex = 0;
 
		// New Workbook
		workbook = new HSSFWorkbook();
 
		// Generate fonts
		headerFont  = createFont(HSSFColor.WHITE.index, (short)12, true);
		contentFont = createFont(HSSFColor.BLACK.index, (short)10, false);
 
		// Generate styles
		headerStyle  = createStyle(headerFont,  HSSFCellStyle.ALIGN_CENTER, HSSFColor.BLUE_GREY.index,       true, HSSFColor.WHITE.index);
		oddRowStyle  = createStyle(contentFont, HSSFCellStyle.ALIGN_LEFT,   HSSFColor.GREY_25_PERCENT.index, true, HSSFColor.GREY_80_PERCENT.index);
		evenRowStyle = createStyle(contentFont, HSSFCellStyle.ALIGN_LEFT,   HSSFColor.GREY_40_PERCENT.index, true, HSSFColor.GREY_80_PERCENT.index);
 
		// New sheet
		HSSFSheet sheet = workbook.createSheet("Very Cool Sheet");
 
		// Table header
		HSSFRow      headerRow    = sheet.createRow( rowIndex++ );
		List<String> headerValues = FakeDataProvider.getTableHeaders();
 
		HSSFCell headerCell = null;
		for (int i = 0; i < headerValues.size(); i++) {
			headerCell = headerRow.createCell(i);
			headerCell.setCellStyle(headerStyle);
			headerCell.setCellValue( headerValues.get(i) );
		}
 
 
		// Table content
		HSSFRow  contentRow  = null;
		HSSFCell contentCell = null;
 
		// Obtain table content values
		List<List<String>> contentRowValues = FakeDataProvider.getTableContent(20);
		for (List<String> rowValues : contentRowValues) {
 
			// At each row creation, rowIndex must grow one unit
			contentRow = sheet.createRow( rowIndex++ );
			for (int i = 0; i < rowValues.size(); i++) {
				contentCell = contentRow.createCell(i);
				contentCell.setCellValue( rowValues.get(i) );
 
				// Style depends on if row is odd or even
				contentCell.setCellStyle( rowIndex % 2 == 0 ? oddRowStyle : evenRowStyle );
			}
		}
 
 
		// Autosize columns
		for (int i = 0; i < headerValues.size(); sheet.autoSizeColumn(i++));
 
		return workbook;
	}
 
 
	/**
	 * Create a new font on base workbook
	 * 
	 * @param fontColor       Font color (see {@link HSSFColor})
	 * @param fontHeight      Font height in points
	 * @param fontBold        Font is boldweight (<code>true</code>) or not (<code>false</code>)
	 * 
	 * @return New cell style
	 */
	private HSSFFont createFont(short fontColor, short fontHeight, boolean fontBold) {
 
		HSSFFont font = workbook.createFont();
		font.setBold(fontBold);
		font.setColor(fontColor);
		font.setFontName("Arial");
		font.setFontHeightInPoints(fontHeight);
 
		return font;
	}
 
 
	/**
	 * Create a style on base workbook
	 * 
	 * @param font            Font used by the style
	 * @param cellAlign       Cell alignment for contained text (see {@link HSSFCellStyle})
	 * @param cellColor       Cell background color (see {@link HSSFColor})
	 * @param cellBorder      Cell has border (<code>true</code>) or not (<code>false</code>)
	 * @param cellBorderColor Cell border color (see {@link HSSFColor})
	 * 
	 * @return New cell style
	 */
	private HSSFCellStyle createStyle(HSSFFont font, short cellAlign, short cellColor, boolean cellBorder, short cellBorderColor) {
 
		HSSFCellStyle style = workbook.createCellStyle();
		style.setFont(font);
		style.setAlignment(cellAlign);
		style.setFillForegroundColor(cellColor);
		style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
 
		if (cellBorder) {
			style.setBorderTop(HSSFCellStyle.BORDER_THIN);
			style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
			style.setBorderRight(HSSFCellStyle.BORDER_THIN);
			style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
 
			style.setTopBorderColor(cellBorderColor);
			style.setLeftBorderColor(cellBorderColor);
			style.setRightBorderColor(cellBorderColor);
			style.setBottomBorderColor(cellBorderColor);
		}
 
		return style;
	}
}

Ya sólo nos quedaría utilizarlo desde la clase principal y escribir el excel generado en disco:

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class App {
 
    public static void main(String[] args) {
 
        HSSFWorkbook workbook = new ExcelGenerator().generateExcel();
 
        // Writing the excel to output file
        try {
            OutputStream out = new FileOutputStream("src/main/resources/ExcelWithStyles.xls");
            workbook.write(out);
            workbook.close();
            out.flush();
            out.close();
        }
        catch (IOException e) {
            System.err.println("Error at file writing");
            e.printStackTrace();
        }
    }
}

Estilos con nombre

Si definimos un nombre de usuario para el estilo, éste aparecerá entre los estilos predefinidos al abrir el documento desde Microsoft Excel. Por ejemplo, si hubiéramos hecho lo siguiente:

headerStyle.setUserStyleName("Header");

Nuestro estilo estaría disponible para el usuario:

custom_user_styles

Estilos sobre filas

Al igual que las celdas, las filas (HSSFRow) tienen un método setRowStyle(). Es importante tener en cuenta que si aplicamos un estilo sobre una fila, éste sólo se aplica a las celdas vacías. Es decir, que en cuanto creemos una celda sobre esa fila invocando a sú método createCell(), ésta no usará el estilo de la fila.

Optimización

Tanto los estilos (HSSFCellStyle) como las fuentes (HSSFFont) son creados a nivel de libro excel.

Es necesario tenerlo en cuenta porque, si necesitamos aplicar un mismo estilo a varias celdas, lo correcto es crearlo una sola vez y aplicarlo a todas las celdas. Si en lugar de eso, creamos el estilo de nuevo cada vez que tenemos que aplicarlo a una celda, estaremos multiplicando el estilo tantas veces como celdas haya. Esto no es apreciable al mostrar el archivo excel generado, ya que todos los estilos son iguales, pero sí que tendremos un archivo generado de mayor tamaño.

De igual forma, si queremos aplicar el mismo estilo de texto a varios estilos de celda, lo correcto es utilizar una misma fuente para todos los estilos, en lugar de crear una nueva fuente para cada estilo que la utilice.

Código fuente

Puedes descargar el proyecto de ejemplo mi repositorio de GitHub. El ejemplo mostrado corresponde a Poi-ExcelWithStyles.

Saludos,

6 Replies to “Apache POI: Cómo definir estilos en archivos excel”

  1. Hola, buenas tardes.

    Estoy generando archivos xls con la libreria npoi en visual basic .net, pero cuando genero un archivo con varias hojas y les doy estilo, en algunas ya no quiere ponerlo, sabes a que se debe esta situación?

    Gracias

    • Hola Sandra,

      Es complicado saber exactamente la causa del error sin ver el código, pero te aconsejo que revises:

      • Que no estás creando un estilo por cada celda, sino que aplicas el mismo a todas las celdas iguales
      • Que no estás aplicando un estilo sobre una fila, y luego creando celdas en esa fila. Las celdas creadas no recibirán el estilo de su fila

      Siento no poder darte más ayuda en este momento

      Saludos,

      • Hola, buenos días, gracias por responder.

        Ya revisé lo que me sugeriste y al parecer todo esta bien, hice una prueba generando archivos por separado en vez de uno solo con hoja y cuando los crea por separado todo el formato lo pone muy bien, pero al momento de quererlo generar por hojas como que pierde los estilos y las fuentes.
        Ahora la idea es generarlos por separado y concatenar esos archivos en uno solo pero no lo he logrado este es el código:
        Dim CnH As Integer
        Dim ArchivoFinal As New HSSFWorkbook
        Dim ArchivoFinal2 As New HSSFWorkbook
        Dim ArchivoH As HSSFWorkbook
        Dim sheetCH As HSSFSheet
        Dim file2 As FileStream
        Try
        For CnH = 1 To totalH
        ArchivoH = New HSSFWorkbook(New FileStream(RutaPrincipal & “Temp\\” & filename & “_” & CnH & “.xls”, FileMode.Open))
        sheetCH = ArchivoH.GetSheetAt(0)
        sheetCH.CopyTo(ArchivoFinal, sheetCH.SheetName, True, True)
        Next CnH
        file2 = New FileStream(RutaPrincipal & “Temp\\” & filename & “.xls”, FileMode.Create, FileAccess.ReadWrite)
        ArchivoFinal.Write(file2)
        file2.Close()
        Catch ex As Exception
        GrabaError(ex.ToString())
        End Try

        me da el error “Referencia a objeto no establecida como instancia de un objeto”
        Esto lo marca en la línea ArchivoFinal.Write(file2)

        Sabes a que se debe esta situación?

  2. Buenos días:
    Me gustaría saber si se puede poner dos estilos distintos de letra dentro de la misma celda ( una palabra en cursiva y otra en negrita).
    En caso de que sí. ¿Como se hace?

    Gracias

    • Hola Rubén,

      No puedo ponerte un ejemplo completo en este momento, pero sí que es posible hacer lo que dices. Tendrás que poner como contenido de esa celda un RichTextString. En ese objeto es posible definir distintos formatos para partes de un mismo texto.

      Gracias por comentar y un saludo,

  3. Buenas, estoy generando un Excel desde java, quiero ajustar las columnas a en relación a su contenido. Uso la función:
    hoja.autoSizeColumn((short)0 )
    el tema es que con el mismo código funciona en el pc de mi compañero, generándose el tamaño correcto, pero con mi pc en mi Excel no hace caso, y se quedan sin ajustar las columnas.
    Que puede pasar? Supongo que debe ser la configuración del Excel, pero no doy con la tecla correcta.

    Un saludo.

    Abel

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*