Recorra 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. Escribe un valor en C1 para parchear la cabecera 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 representa el contenido de una celda, el ancla superior izquierda, y trata el resto como espacio cubierto que contiene valores pero nunca los muestra. Los usuarios de Excel absorben esto por ensayo y error. Un generador de informes tiene que codificarlo como una regla, porque en código generado el síntoma es una región en blanco sin ninguna excepción que lo rastree. HotXLS, una biblioteca nativa de Object Pascal que lee y escribe ambos formatos de Excel desde Delphi y C++Builder, expone la tabla de combinaciones con suficiente claridad 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 a un consumidor que pinte el contenido del ancla a través del rectángulo. Esa distinción impulsa tres comportamientos que merece la pena interiorizar antes de escribir cualquier código de diseño. Leer una celda cubierta devuelve su propio valor almacenado, que para un banner que usted construyó normalmente está 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 aparece en ningún sitio, que es la trampa de cabecera invisible del principio. Y separar una región expone lo que llevaba todo el tiempo debajo, así que un valor perdido escrito en espacio cubierto se convierte en un defecto visible el día en que alguien disuelve la combinación
En el lado XLSX esa tabla es un objeto de primera clase. Sheet.MergedCells lleva Add('A1:C1'), FindAt(Row, Col), DeleteAt e Items, y la llamada a la que más recurrirá 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 protección de escritura, y ambas aparecen más adelante
Dos fachadas, dos modismos de combinación
HotXLS mantiene el motor BIFF8 .xls clásico y el motor OOXML .xlsx como modelos de objetos separados, y expresan la combinación de forma distinta porque descienden de convenciones diferentes. La fachada XLS sigue el modismo COM de Excel: se toma un rango de una propiedad indexada de dos argumentos y se llama a Merge con un OleVariant cuyo valor decide la geometría con la que termina
var
Book: IXLSWorkbook; // con recuento de referencias: sin Free manual
Sh: IXLSWorksheet;
begin
Book := TXLSWorkbook.Create;
Sh := Book.Sheets[1]; // la colección de hojas XLS es de 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 a través: una combinación por fila
Book.SaveAs('layout.xls');
end;
El argumento de Merge es la parte que la gente hace mal. En un rango de dos filas, Merge(True) produce dos combinaciones independientes de una fila, que es el "Merge Across" de Excel y exactamente lo que se quiere para una banda de cabecera apilada cuyas filas deban seguir siendo separables. Merge(False) fusiona todo el rectángulo en un único bloque. El rango también reporta MergeCells como un indicador de estado, devuelve la región contenedora mediante MergeArea, y se disuelve a sí mismo con Unmerge. La fachada XLSX expone las mismas operaciones bajo nombres distintos: Sheet.MergeCells(Row1, Col1, Row2, Col2) toma 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. La cabecera 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 una fila de detalle completamente estilizada en la plantilla, 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 en base 0, lado de la celda en base 1
// la fila 5 es la línea de plantilla de detalle con estilo
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
// abre un hueco encima del bloque de totales; el contenido de debajo se desplaza hacia abajo
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 error de desplazamiento por uno que muerde en silencio: Fonts.Add devuelve una posición de pool en base 0, mientras que una celda almacena una referencia de fuente en base 1 donde 0 significa la fuente por defecto, así que omitir el + 1 no lanza nada, simplemente da estilo a su título en la tipografía equivocada. La otra línea es CopyRange, que mueve el formato y las 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 división escala todavía más cuando el diseño reutilizable vive en su propio libro de trabajo, digamos una hoja de bandas de cabecera y pie compartida entre informes. CopyRangeTo realiza el mismo clonado a través de los límites de hoja, tomando una hoja de destino más coordenadas de destino, de modo que un generador puede mantener una hoja de plantilla intacta y estampar sus regiones en tantas hojas de salida como necesite un job. La alternativa, mutar la plantilla in situ e intentar restaurarla después, es el tipo de cosa que funciona hasta el día en que una ejecución se aborta a medias
Qué mueve InsertRows, y qué no
El patrón de plantilla que crece solo funciona porque InsertRows de XLSX es una edición estructural y no un simple desplazamiento de celdas. Cuando abre un hueco, reubica las regiones combinadas, las alturas de fila, los hipervínculos, los comentarios, los paneles inmovilizados, los rangos de autofiltro, los formatos condicionales, las validaciones de datos, las tablas, los nombres definidos, los anclajes de imagen y los anclajes de gráfico que están debajo del punto de inserción, no solo los valores de celda. 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 con los que hay que diseñar. El ajuste de fórmulas se limita a la hoja que se está editando: las referencias dentro de esa hoja se reescriben, y una fórmula en otra hoja que apunta al área desplazada también se reescribe, pero el ajuste solo sigue las referencias que apuntan a la hoja editada, así que cualquier esquema de referencias entre libros de trabajo merece su propia auditoría en lugar de confianza ciega. El segundo límite es más marcado, y está en el 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 debería mantener sus regiones de tabla dinámica bien alejadas de cualquier banda que crezca
Negarse a escribir datos en espacio de diseño
El fallo de celdas combinadas que realmente llega a producción no es el cosmético. Es estructural: una fila de detalle se desliza hacia una banda de diseño combinada, sus valores caen en celdas cubiertas y se vuelven invisibles, y los totales de columna dejan silenciosamente de coincidir con lo que puede ver cualquiera que lea la hoja. Como FindAt responde a la pregunta de la región de cobertura para cualquier coordenada, el generador puede rechazar esa escritura en el momento en que ocurriría en lugar de entregar un informe que subcuenta en silencio
// rechaza escribir 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ímite pertenece a cualquier lugar donde un usuario vaya a ordenar o filtrar la salida más adelante. 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 varias filas no tiene una sola fila con la que viajar; Excel responde con un error o un diseño desordenado. La disciplina que mantiene correctos los informes es geográfica. Confine las combinaciones a bandas de título, divisores de sección y bloques de firma, y mantenga plano el centro tabular de la hoja. El artículo sobre generación de informes basados en plantilla desarrolla esta separación entre diseño y datos hasta convertirla en un flujo 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 exportar
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 QA. La exportación a HTML reproduce las combinaciones fielmente, emitiendo colspan y rowspan en una sola tabla, así que un informe destinado al navegador conserva su aspecto en bandas. La exportación a 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 hacia la izquierda en un procesador de textos. CSV no tiene ningún concepto de combinación, así que el valor del ancla ocupa un campo y cada celda cubierta se emite como un campo vacío. La conclusión para un libro de trabajo que también alimenta exportaciones delimitadas es mantener fuera de la geometría combinada todo lo que sea estructuralmente importante; 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 minúscula al lado de los datos de celda, y leer una celda cubierta sigue pasando por FindAt en lugar de un escaneo. 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, lo que aborda directamente el artículo sobre rendimiento con libros de trabajo grandes. Ambas API de combinación, las operaciones de edición estructural, y las demostraciones de plantilla se distribuyen con HotXLS Delphi Component