Itere las celdas de una plantilla de informe recién abierta y un título combinado se comporta como una fuga. Lee A1 y obtiene "Quarterly Statement"; lee de B1 a F1, que visiblemente están bajo el mismo banner, y no obtiene nada. Escriba un valor en C1 para parchar el encabezado y nunca aparece en pantalla. La cuadrícula no perdió sus datos. Está haciendo exactamente lo que significa una combinación: tanto en XLS como en XLSX, un rectángulo combinado renderiza el contenido de una sola celda, el ancla superior izquierda, y trata al resto como espacio cubierto que guarda valores pero nunca los muestra. Los usuarios de Excel lo asimilan por prueba y error. Un generador de informes tiene que codificarlo como regla, porque en código generado el síntoma es una región en blanco sin ninguna excepción que la delate. HotXLS, una biblioteca nativa en Object Pascal que lee y escribe ambos formatos de Excel desde Delphi y C++Builder, expone la tabla de combinaciones de forma lo bastante explícita como para programar contra la regla en lugar de redescubrirla en un ticket de soporte
Un valor, un ancla
Una combinación es una instrucción de visualización superpuesta a una cuadrícula que no cambia de forma. Cada celda cubierta sigue existiendo en el archivo como su propia ranura; el registro de combinación solo le indica al consumidor que pinte el contenido del ancla a lo largo del rectángulo. Esa distinción determina tres comportamientos que conviene interiorizar antes de escribir cualquier código de diseño. Leer una celda cubierta devuelve su propio valor almacenado, que para un banner construido por usted suele estar vacío, así que cualquier código que inspeccione un título combinado tiene que resolver y leer el ancla. Escribir en una celda cubierta tiene éxito a nivel de archivo y no se muestra en ningún lado, que es la trampa del encabezado invisible de la introducción. Y descombinar una región expone lo que estuvo debajo todo el tiempo, así que un valor perdido escrito en el espacio cubierto se convierte en un defecto visible el día que alguien disuelve la combinación
Del lado XLSX esa tabla es un objeto de primera clase. Sheet.MergedCells ofrece Add('A1:C1'), FindAt(Row, Col), DeleteAt e Items, y la llamada que más usará es FindAt: entréguele cualquier coordenada y devuelve la región combinada que cubre esa celda, o nil cuando la celda está sola. Esa única búsqueda es la base de las dos mitades del manejo correcto de combinaciones, la lectura segura y la guarda de escritura, y ambas aparecen más adelante
Dos fachadas, dos formas de combinar
HotXLS mantiene el motor clásico BIFF8 de .xls y el motor OOXML de .xlsx como modelos de objetos separados, y escriben la combinación de manera distinta porque descienden de convenciones distintas. La fachada XLS sigue el estilo COM de Excel: toma un rango de una propiedad indexada de dos argumentos y llama a Merge con un OleVariant cuyo valor decide la geometría que obtiene al final
var
Book: IXLSWorkbook; // contado por interfaz: sin Free manual
Sh: IXLSWorksheet;
begin
Book := TXLSWorkbook.Create;
Sh := Book.Sheets[1]; // la colección de hojas XLS es base 1
Sh.Range['A1', 'F1'].Merge(False); // False = un solo bloque combinado
Sh.Cells.Item[1, 1].Value := 'Quarterly Statement';
Sh.Range['A3', 'F4'].Merge(True); // True = combinar horizontalmente: una combinación por fila
Book.SaveAs('layout.xls');
end;
El argumento de Merge es la parte en la que la gente se equivoca. Sobre un rango de dos filas, Merge(True) produce dos combinaciones independientes de una fila, que es el "Combinar horizontalmente" de Excel y exactamente lo que quiere para una banda de encabezado apilada que debe mantener sus filas separables. Merge(False) fusiona todo el rectángulo en un solo bloque. El rango también reporta MergeCells como bandera de estado, devuelve la región contenedora mediante MergeArea y se disuelve con Unmerge. La fachada XLSX expone las mismas operaciones con otros nombres: Sheet.MergeCells(Row1, Col1, Row2, Col2) recibe límites enteros, TXLSXRange.Merge acepta la variante Across equivalente, y la colección MergedCells guarda el resultado
Una plantilla que crece con sus datos
Una plantilla de informe real no es una cuadrícula fija. El encabezado y los totales son fijos, pero la sección de detalle entre ellos se estira hasta lo que devuelva la consulta. El patrón que se sostiene mantiene en la plantilla una sola fila de detalle completamente estilizada, la clona una vez por registro y luego abre un hueco antes del bloque de totales para que todo lo anclado debajo se deslice hacia abajo sin perder su formato
Sheet.Range['A1:F1'].Merge;
Sheet.Cells[1, 1].Value := 'INVOICE #2026-0611'; // el valor va al ancla, A1
Sheet.RowHeight[1] := 28;
TitleFont := Book.Fonts.Add('Calibri', 16, True, False);
Sheet.Cells[1, 1].FontIndex := TitleFont + 1; // índice del pool base 0, lado de celda base 1
// la fila 5 es la línea de plantilla de detalle estilizada
for I := 0 to ItemCount - 1 do
Sheet.CopyRange(5, 1, 5, 6, 6 + I, 1); // los estilos y las fórmulas viajan con ella
// abrir un hueco sobre el bloque de totales; el contenido de abajo se desplaza
Sheet.InsertRows(6 + ItemCount, 1);
Sheet.Range['A1:F1'].SetBorders(xlsxEdgeOutline, xlsxBorderMedium);
Dos líneas merecen una segunda mirada. La asignación de fuente lleva un desfase de uno que muerde en silencio: Fonts.Add devuelve una posición base 0 en el pool, mientras que una celda almacena una referencia de fuente base 1 donde 0 significa la fuente predeterminada, así que omitir el + 1 no lanza nada, simplemente estiliza su título con la tipografía equivocada. La otra línea es CopyRange, que mueve formato y fórmulas junto con los valores. Esa es toda la razón para clonar una fila de plantilla construida a mano en lugar de reconstruir su aspecto en código. Un diseñador es dueño de la apariencia una sola vez, en la plantilla; el generador solo vierte datos en copias de ella
Esa separación escala aún más cuando el diseño reutilizable vive en su propio libro de trabajo, digamos una hoja de bandas de encabezado y pie compartidas entre informes. CopyRangeTo realiza el mismo clonado a través de los límites de la hoja de cálculo, recibiendo una hoja de destino más coordenadas de destino, así que un generador puede mantener una sola hoja de plantilla intacta y estampar sus regiones en tantas hojas de salida como necesite un trabajo. La alternativa, mutar la plantilla en el lugar e intentar restaurarla después, es el tipo de cosa que funciona hasta el día en que una ejecución aborta a la mitad
Qué mueve InsertRows y qué no
El patrón de plantilla que crece solo funciona porque el InsertRows de XLSX es una edición estructural y no una reorganización de celdas. Cuando abre un hueco reubica las regiones combinadas, alturas de fila, hipervínculos, comentarios, paneles inmovilizados, rangos de autofiltro, formatos condicionales, validaciones de datos, tablas, nombres definidos, anclas de imagen y anclas de gráfico que están debajo del punto de inserción, no solo los valores de las celdas. Eso es lo que permite que el bloque de totales llegue a su nueva fila con sus combinaciones y formatos numéricos intactos en lugar de llegar despojado
Sus dos límites documentados son los que conviene tener en cuenta al diseñar. El ajuste de fórmulas se limita a la hoja que se edita: las referencias dentro de esa hoja se reescriben, y una fórmula en otra hoja que apunte al área desplazada también se reescribe, pero el ajuste solo sigue referencias que apunten a la hoja editada, así que cualquier esquema de referencias entre libros merece su propia auditoría en lugar de confianza ciega. El segundo límite es más agudo, y está del lado XLS. Las tablas dinámicas sobreviven a los ciclos de abrir y guardar como registros preservados en bruto, no como objetos modelados que HotXLS pueda mover, así que insertar filas no reubica la huella de una tabla dinámica. Cualquier plantilla que construya para el formato .xls debe ubicar sus regiones de tabla dinámica bien lejos de cualquier banda que crezca
Negarse a escribir datos en el espacio de diseño
El fallo de celdas combinadas que de verdad llega a producción no es el cosmético. Es estructural: una fila de detalle se desplaza hacia una banda de diseño combinada, sus valores caen en celdas cubiertas y se vuelven invisibles, y los totales de columna dejan de coincidir en silencio con lo que cualquiera que lea la hoja puede ver. Como FindAt responde la pregunta de la región cubriente para cualquier coordenada, el generador puede rechazar esa escritura en el momento en que ocurriría en lugar de entregar un informe que subestima en silencio
// rechazar la escritura de datos de detalle en una región de diseño combinada
if Sheet.MergedCells.FindAt(Row, 1) <> nil then
raise Exception.CreateFmt('row %d overlaps a merged layout region', [Row]);
Sheet.Cells[Row, 1].Value := Detail.Description;
La misma comprobación de límites corresponde en cualquier lugar donde un usuario vaya a ordenar o filtrar la salida después. Un rango con combinaciones dentro no puede ordenarse limpiamente, porque la ordenación mueve las filas de forma independiente y una combinación que abarca filas no tiene una sola fila con la que viajar; Excel responde con un error o con un diseño revuelto. La disciplina que mantiene correctos los informes es geográfica. Confine las combinaciones a bandas de título, separadores de sección y bloques de firma, y mantenga plana la parte tabular central de la hoja. El artículo sobre generación de informes con plantillas desarrolla esta separación entre diseño y datos hasta un flujo de trabajo completo basado en marcadores de posición, y el artículo sobre formato condicional y texto enriquecido cubre el estilo de esa banda de datos plana
Cómo se degradan las combinaciones al salir
Una combinación es un concepto de libro de trabajo, y cada formato de exportación orientado a texto la respeta en distinto grado. Conocer los tres comportamientos de antemano ahorra un ciclo de control de calidad. La exportación HTML reproduce las combinaciones con fidelidad, emitiendo colspan y rowspan en una sola tabla, así que un informe destinado al navegador conserva su aspecto en bandas. La exportación RTF no abarca columnas en absoluto: el texto del ancla cae en su propia celda y el ancho restante de la combinación sale como celdas vacías, lo que deja un título ancho visualmente empujado a la izquierda en un procesador de texto. CSV no tiene concepto de combinación, así que el valor del ancla ocupa un campo y cada celda cubierta se emite como campo vacío. La conclusión para un libro de trabajo que también alimenta exportaciones delimitadas es mantener todo lo que soporte carga fuera de la geometría combinada; el artículo sobre exportación a CSV, TSV y HTML recorre cada formato en detalle
Una tranquilidad para quien sopese esto frente al tamaño de archivo: las combinaciones cuestan casi nada a escala de informe. La tabla de combinaciones es diminuta junto a los datos de celda, y leer una celda cubierta sigue pasando por FindAt en lugar de escanear. La presión de rendimiento en libros de trabajo grandes viene de otra parte, principalmente del crecimiento del pool de estilos y de la memoria que retiene la ruta de guardado, que el artículo sobre rendimiento con libros de trabajo grandes aborda directamente. Ambas API de combinación, las operaciones de edición estructural y las demostraciones de plantillas se distribuyen con HotXLS Delphi Component