Appliquer de multiple CellStyle sur une Cellule avec Apache POI

de | août 5, 2014

Bonjour,

Je vais vous parler de ma manière de gérer les styles avec Apache POI. En effet pour ajouter un style sur une cellule avec POI vous devez créer un CellStyle :

Workbook wb = new HSSFWorkbook();
CellStyle grey25ForeGroundColor = wb.createCellStyle();
grey25ForeGroundColor.setFillForegroundColor(IndexedColors.Grey_40_PERCENT.getIndex());
grey25ForeGroundColor.setFillPattern(CellStyle.SOLID_FOREGROUND);

Ceci créer un style appliquant une couleur de fond gris clair sur une cellule. Vous appliquez ensuite le style à la cellule de la manière suivante :

Sheet sheet = wb.createSheet("Feuille 1");
Row row = sheet.createRow((short)0);
Cell cell = row.createCell(0);
cell.setCellValue("Test");
cell.setCellStyle(grey25ForeGroundColor);

Cela fonctionne très bien mais j’ai du produire plusieurs fichier Excel avec plein de styles différents dans chacun des fichiers. Plutôt que de créer un style pour chaque cellule, je me suis dis que j’allais mutualiser le code dans une classe abstraite. Seulement voilà, cela pose un gros problème. Imaginez que je veuille une cellule grise comme celle que l’on viens de créer.
Je créer donc mon style dans ma classe abstraite. Maintenant je veux une cellule grise avec le contenu centré et une autre avec le contenu centré et des bordures. Je ne vais pas créer un style pour chaque combinaison possible. Ce qui aurait été bien c’est de pouvoir ajouter plusieurs styles sur une cellule. Seulement on ne peux en mettre qu’un seul.

Voici ma solution qui permet de fusionner plusieurs styles entre eux.

/**
* Fusionne plusieurs CellStyle entre eux. Si deux CellStyle ont un style en commun. Le suivant prend le dessus sur le précédent.
* @Param String Une liste de CellStyle à fusionner prise parmi une liste contenu dans un Hashmap.
* @return CellStyle Le CellStyle contenant tout les styles.
*/
protected CellStyle mergeCellStyle(String... cellStyles) {
    // Style vide qui nous servira de base de comparaison.
    CellStyle defaultStyle = wb.createCellStyle();
    // Un CellStyle de base qui servira à agréger les styles à fusionner.
    CellStyle currentStyle = wb.createCellStyle();
    try  {
        // On boucle sur les CellStyles à fusionner
        for(String cellStyleString:cellStyles) {
            // On récupère le CellStyle à fusionner avec le/les précedent(s)
            CellStyle cellStyle = styles.get(cellStyleString)
            // On récupère la liste des méthodes de l'object CellStyle que l'on souhaite prendre en compte lors de la fusion.
            Set<String> keys = mergeMethods.keySet();
            // On parcours la liste de ces méthodes.
            for(String key : keys)
                Method method = cellStyle.getClass().getMethod(key);
                Class<?> returnType = method.getReturnType();
                Object result = method.invoke(cellStyle);
                Object resultBase = methode.invoke(currentStyle);
                Object defaultStyle = method.invoke(defaultStyle);
                /* On compare si il y a un changement par rapport au style courant
                * et si ce changement ne correspond pas au style de base pour éviter
                * les retours en arrière.
                */
                if(result.hashCode() != resultBase.hashCode() && result.hashCode() != resultDefault.hashCode()) {
                    // Si un changement existe on modifie le style courant.
                    currentStyle.getClass().getMethod(mergeMethods.get(key), returnType).invoke(currentStyle, result);
                }
            }
        }
    }
    // On retourne le style fusionné.
    return currentStyle;
    // Catch clause
}

A noter que l’on utilise ici le hashcode pour la comparaison. En effet comme nous utilisons la réflexivité, le résultat de l’invocation d’une méthode est de type Object. Donc la différence avec l’opérateur « != » ne donnera pas un résultat pertinent. Et comme les types utiliser par POI pour modifier les styles sont des primitifs, une différence faite avec  » ! » ».equals()   » ne donnera pas le résultat escompté non plus.

je vous donne la méthode permettant de charger la HashMap mergesMethods :

private void loadMergeMethod() {
    mergeMethods.put("getAlignment", "setAlignment");
    mergeMethods.put("getBorderBottom", "getBorderBottom");
    mergeMethods.put("getBorderLeft", "getBorderLeft");
    mergeMethods.put("getBorderRight", "getBorderRight");
    mergeMethods.put("getBorderTop", "getBorderTop");
    mergeMethods.put("getBottomBorderColor", "getBottomBorderColor");
    mergeMethods.put("getLeftBorderColor", "getLeftBorderColor");
    mergeMethods.put("getRightBorderColor", "getRightBorderColor");
    mergeMethods.put("getTopBorderColor", "getTopBorderColor");
    mergeMethods.put("getDataFormat", "getDataFormat");
    mergeMethods.put("getFillBackgroundColor", "getFillBackgroundColor");
    mergeMethods.put("getFillForegroundColor", "getFillForegroundColor");
    mergeMethods.put("getFillPattern", "getFillPattern");
    mergeMethods.put("getHidden", "getHidden");
    mergeMethods.put("getIndention", "getIndention");
    mergeMethods.put("getLocked", "getLocked");
    mergeMethods.put("getRotation", "getRotation");
    mergeMethods.put("getShrinkToFit", "getShrinkToFit");
    mergeMethods.put("getVerticalAlignment", "getVerticalAlignment");
    mergeMethods.put("getWrapText", "getWrapText");

}

Pour ceux qui se demanderais pourquoi je n’ai pas utiliser la récursivité pour récupérer les méthodes de manière dynamique? La réponse est que la méthode MaClasse.getMethods() retourne l’ensemble des méthodes public, privé, protected de la classe. Nous serions donc obligés de filtrer les méthodes à exclure. J’ai donc préféré filtrer les méthodes à inclure.

il ne nous reste plus qu’a définir des styles unitaires pouvant être mixer entre eux. Si nous reprenons les exemples donnés plus haut, nous auront donc :

</pre>
private void createDefaultStyle() {
    // CellStyle avec bordure
    CellStyle cellBordered = wb.createCellStyle();
    // Add border
    cellBordered.setBorderBottom(CellStyle.BORDER_THIN);
    cellBordered.setBorderLeft(CellStyle.BORDER_THIN);
    cellBordered.setBorderRight(CellStyle.BORDER_THIN);
    cellBordered.setBorderTop(CellStyle.BORDER_THIN);
    // Set border color
    cellBordered.setBottomBorderColor(IndexedColors.BLACK.getIndex());
    cellBordered.setLeftBorderColor(IndexedColors.BLACK.getIndex());
    cellBordered.setRightBorderColor(IndexedColors.BLACK.getIndex());
    cellBordered.setTopBorderColor(IndexedColors.BLACK.getIndex());
    styles.put(STYLE_CELL_BORDERED, cellBordered);

    // CellStyle avec texte aligné au centre
    CellStyle cellCentered = wb.createCellStyle();
    cellCentered.setAlignment(CellStyle.ALIGN_CENTER);
    styles.put(STYLE_CELL_CENTERED, cellCentered);

    // CellStyle avec fond gris clair.
    CellStyle grey25BackgroundColor = wb.createCellStyle();
    grey25BackgroundColor.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
    grey25BackgroundColor .setFillPattern(CellStyle.SOLID_FOREGROUND);</li>
    styles.put(STYLE_CELL_GREY_25_BACKGROUND_COLOR, grey25BackgroundColor);

la variable styles est une hashmap<String, CellStyle> contenant la liste des styles disponibles.
Il ne nous reste plus qu’a appliquer les styles sur notre cellule.

Sheet sheet = wb.createSheet("Feuille 1);
Row row = sheet.createRow((short)0);
Cell cell = row.createCell(0);
cell.setCellValue("Test");
cell.setCellStyle(mergeCellStyle(STYLE_CELL_GREY_25_BACKGROUND_COLOR, STYLE_CELL_CENTERED, STYLE_CELL_BORDERED));

Et voilà. Une belle cellule, centrée, avec bordure et fond gris.
A bientôt.

00

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.