Изградили сте един sheet точно както трябва. Заглавният band е merged, ширините на колоните пасват на данните, първите два реда са frozen, печатната област и маржовете са настроени за чист A4 export, а tab-ът е оцветен, за да може finance да го намери. Сега отчетът има нужда от дванадесет такива, по един за всеки регион, всеки започващ от същото оформление. Да изграждате този sheet по код дванадесет пъти е начинът, по който се промъква тих drift: регион 7 получава колона с една точка по-тясна, регион 11 губи freeze-а и никой не забелязва, докато PDF-ът не кацне на бюрото на мениджър. Това, което всъщност искате, е програмната версия на Excel right-click, Move or Copy, Create a copy: вземете готовия sheet и направете независими дубликати
XLSX engine-ът в HotXLS, нативна Delphi и C++Builder библиотека, която чете и записва Excel файлове без да автоматизира самия Excel, вече можеше да мести sheets, да изтрива sheets и да копира cell ranges между sheets. Това, което не можеше до v2.91.0, беше да клонира цял worksheet с едно извикване. Това издание добавя две входни точки: TXLSXWorksheet.CopyFrom, която копира sheet-level state от един worksheet върху друг, и TXLSXSheets.Duplicate, която добавя нов sheet и пуска CopyFrom вместо вас. Интересното не е, че копира неща. Интересното е умишлената линия между това кое се копира дълбоко и кое не, и защо тази линия е точно там
Един call за клониране на готов sheet
Операцията на високо ниво е Duplicate. Подавате му 1-базирания индекс на източниковия sheet и той връща изцяло нов worksheet, който огледално повтаря оформлението и данните на оригинала. Конвенцията за индексите съвпада с Items[] от XLSX страната, така че sheet one е индекс 110, а не nil0
var
Book: TXLSXWorkbook;
Template, Copy: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Template := Book.Sheets.Add('Template');
Template.Cells[1, 1].Value := 'Quarterly Statement';
Template.Range['A1:C1'].Merge;
Template.ColWidth[1] := 18;
Template.FreezePanes(2, 1); // freeze top row + first column
Template.TabColorIsAuto := False;
Template.TabColor := $FF1F4E79;
// Clone with an explicit name...
Copy := Book.Sheets.Duplicate(1, 'Region-North');
// ...or let it pick the Excel-style default name.
Copy := Book.Sheets.Duplicate(1); // -> "Template (2)"
Book.SaveAs('regions.xlsx');
finally
Book.Free;
end;
end;
; подайте индекс извън обхвата и получавате FreezePanes вместо изключение, същия failure contract, който използва и останалата колекция sheet-ове на XLSX.FreezePanes(ARow, ACol)Две неща в този snippet си струва да се забавим върху тях. Първо, Cells[Row, Col] приема аргументите си row-first, Duplicate, така че се подравнява с Copy индексиране; дубликатът наследява точния freeze split. Второ, методът е именуван Copy и не System, а това не е стилово предпочитание. Copy е стандартна routine в Duplicate unit-а, използвана постоянно за низове и dynamic arrays. Метод с име
върху class би го засенчил във вътрешността на method bodies и би създал точно онази двусмисленост при резолвиране, която ви хваща шест месеца по-късно
заобикаля целия проблем и се чете правилно на мястото на извикване.(2)Името по подразбиране следва собственото правило на ExcelTemplateКогато извикате едноаргументния overload или подадете празен низ за име, новият sheet се именува по източника със suffix Template (2) и suffix-ът се увеличава, докато името стане уникално. Дублирайте Template (3) sheet веднъж и получавате Template (2); дублирайте го пак и получавате
, защото Region-North вече е заето. Това повтаря имената, които Excel генерира от своята команда Create a copy, така че workbook, който кодът ви произвежда, изглежда така, както потребител би очаквал ръчно дублиран workbook да изглежда. Проверката за уникалност се изпълнява срещу живата sheet колекция, което означава, че прескача и имена, които сте създали ръчно, не само такива от предишни дубликати.Region-SouthАко генерирате по един sheet на регион или на месец, по-добре се облегнете на overload-а с изрично име. Предвидима (2), (3) схема е по-лесна за адресиране по-късно от поредица от
,
Под капака, Duplicate добавя sheet-а и после вика CopyFrom(ASource), който можете да извикате и директно, когато искате да клонирате върху вече създаден sheet. CopyFrom пази срещу двата дегенеративни случая отпред: копиране от nil, или копиране на sheet върху самия себе си, и двете връщат веднага и не правят нищо. Всичко след това е самото копиране и то е нарочно широко
Първо идват cell данните. CopyFrom пита източника за неговия UsedRange, плътния bounding box на попълнените клетки и merged regions, и използва съществуващата CopyRangeTo machinery, за да пренесе всяка стойност, формула и per-cell style index в целта, започвайки от A1. Върху клетките той възпроизвежда целия слой sheet-level state, който прави template-а завършен:
- Съединените диапазони, пресъздадени по координати, така че banner-ът да обхване същия правоъгълник
- Ширините на колоните и височините на редовете, плюс списъците за hidden, collapsed и outline-level, копирани дословно, така че нестандартните редове и колони да се подравнят точно
- Freeze panes и view state-а: zoom level, gridline и zero-value display, right-to-left посока и типът на изгледа
- Protection state-ът с неговите per-action permission options, така че заключен template да остане заключен по същия начин
- Целият page-setup блок: margins, orientation, paper size, scaling и fit-to-page, print area, print titles, headers and footers, и print-gridlines и print-headings флаговете
- Автофилтърът, tab цветът и видимостта на sheet-а
Резултатът е sheet, който печата, филтрира и се представя идентично на източника. И понеже клетките, merged-овете и dimension списъците са физически пресъздадени върху новия sheet, а не aliased, дубликатът е напълно независим. Запишете 999 в клетка на копието и източникът запазва първоначалната си стойност; тази независимост е най-важното свойство на clone, предназначен за паралелни регионални отчети, и доставеният SheetCopy demo го проверява изрично
Какво оставя shallow и защо
Сега честната част. Charts, embedded images, XLSX tables, data validations и conditional-formatting rules не се копират. Това е документирана, умишлена граница, не пропуск, и си струва да разберете причината, за да планирате около нея вместо да се изненадате от нея
Всяка от тези колекции носи идентичност и препратки, които не оцеляват при наивно копиране на полета. Chart сочи към източников data range и притежава drawing relationship в OOXML пакета; клонирането на обекта без пренасочване на relationship-а и series references произвежда chart, който се рендерира срещу грешните данни, или пакет, който Excel маркира като нуждаещ се от repair. Table има име, което трябва да е уникално в workbook-а, header row, вързан към specific columns, и собствена auto-generated relationship. Conditional formats и data validations се прикрепят към coordinate ranges и, в случая с validation, могат да реферират други ranges чрез formula. Deep-copy на който и да е от тях правилно означава пренаписване на references и сечене на fresh identities, което е истинска работа с реални failure modes. Да го направите наполовина, като копирате обекта, но не и препратките му, е по-лошо от това да не копирате изобщо: получавате файл, който отваря с repair prompt и тихо изпуска content. Така engine-ът копира нещата, които може да копира чисто, и оставя collections с препратки на caller-а, който знае към какво трябва да сочи target-ът
На практика това означава, че workflow-ът за по-богат template е: дублирайте sheet-а, за да вземете клетките, оформлението и печатната настройка, после възстановете chart-а, table-а, validation-ите или conditional format-ите върху копието със същия API, който сте използвали първия път. Понеже ги създавате наново спрямо собствените ranges на дубликата, препратките излизат правилни по конструкция. За chart, който чете A1:C10, добавете нов chart върху копието, насочен към A1:C10; за AutoFilter, който искате да остане жив, имайте предвид, че filter range се запазва, така че трябва само да приложите отново column критериите. Правилата за conditional-formatting и data-validation ще добавите отново чрез същите извиквания, описани в статията за merged cells и report-template layout, която обхожда merge таблицата и range модела, които copy-то наследява
Къде дублирането се вписва в reporting pipeline
Worksheet duplication е естественият спътник на генерирането, водено от placeholders. Подходът, anchored върху token-и, в ръководството за template-driven report generation in Delphi решава проблема с писането на данни в оформление, което други хора редактират; duplication решава проблема с нуждата от това оформление много пъти в един workbook. Комбинирайте ги и моделът е чист: дръжте един незасегнат Template sheet с неговите token-и, merged-ове и печатна настройка, после за всеки регион или период извиквайте Duplicate, попълнете token-ите на клона с тази порция данни и продължете нататък. Незасегнатият template никога не се променя, така че остава надежден source за следващия клон и всеки output sheet започва от byte-for-byte идентично оформление
Една бележка за sequencing спестява цяла класа обърквания. Дублирайте sheet-а преди да налеете данни в него, не след това. Template трябва да носи структура и formatting, не числата от миналото тримесечие, а клонирането на празен стилизиран sheet означава, че всеки дубликат започва чист. Ако дублирате sheet, който вече носи данни, тези данни идват заедно с него, защото CopyFrom копира използвания диапазон вярно; понякога това е търсеното, но за fan-out отчет обикновено не е
Бърз навик за проверка
Понеже разликата между deep-copy и shallow-copy е невидима, докато не я потърсите, вградете петредова проверка в job-а, вместо да се доверявате, че всичко е минало. След дублирането прочетете обратно структурните сигнали, които clone-ът трябва да наследи, и проверете, че съвпадат с източника
Copy := Book.Sheets.Duplicate(1, 'Region-North');
WriteLn(Format('merged=%d colA=%.1f freezeRow=%d tabAuto=%d',
[Copy.MergedCells.Count, Copy.ColWidth[1],
Copy.FreezeRow, Integer(Copy.TabColorIsAuto)]));
// Prove independence: mutate the copy, confirm the source is untouched.
Copy.Cells[2, 2].Value := 999;
// Template.Cells[2, 2].Value is still whatever it was.
Броят на merge-овете, ширина на колона, freeze редът и tab-color флагът ви казват, че слоят, който е копирал, наистина е пристигнал. Отделно, във всеки sheet, който е носил chart, table, validation-и или conditional formats, третирайте тези неща като списък за възстановяване върху копието: липсата им е по дизайн, а fix-ът са няколко извиквания, не bug report. Този mental model, дълбоко там, където е безопасно, и плитко там, където references биха се счупили, е цялата история как да използвате тази функция добре
Worksheet duplication и CopyFrom sheet-state copy-ят, описан тук, идват във v2.91.0 на нативния HotXLS Delphi spreadsheet component, заедно с изпълним SheetCopy sample, който упражнява цикъла clone-и после mutate от край до край