Zmień nazwę arkusza z "Summary" na "Overview" w generowanym skoroszycie, a każde wewnętrzne hiperłącze wskazujące na Summary!A1 przestaje gdziekolwiek prowadzić. Żadnego wyjątku przy zapisie, żadnego przy otwarciu. Link nadal się renderuje, nadal wygląda na klikalny i po cichu rozwiązuje się w nic. Ta sama awaria pojawia się po konwersji zapisz-jako albo po podróży .xls/.xlsx w obie strony, gdy komentarz ląduje o kolumnę obok albo względny link gubi swój cel. Obie funkcje niosą stan recenzji, na podstawie którego działają prawdziwi ludzie, więc kiedy się psują, awaria jest niewidoczna aż do chwili, gdy recenzent klika i nic się nie dzieje
To praktyczny powód, dla którego komentarze i hiperłącza zasługują na więcej uwagi, niż sugeruje ich kosmetyczny wygląd. HotXLS daje kodowi Delphi i C++Buildera bezpośredni dostęp do zapisu obu, w XLS i XLSX, bez automatyzacji Excela w pętli. Odwrotną stroną tej kontroli jest odpowiedzialność: biblioteka zapisuje dokładnie te cele, które jej podasz, i nie waliduje żadnego z nich, więc utrzymanie nienaruszonego przepływu recenzji to zadanie twojego kodu, nie Excela
Komentarze w komórkach jako maszynowo pisane zapisy recenzji
W modelu klas XLSX komentarz jest obiektem na poziomie arkusza: zna swój wiersz, swoją kolumnę, autora i treść tekstu. Pole autora zasługuje na swoje miejsce. Kiedy skoroszyt wygenerowany przez twój kod wędruje przez łańcuch recenzji, pierwsze pytanie audytora brzmi, kto napisał daną notatkę, a notatka zostawiona bez autora odpowiada na to pytanie pustką. Stemplaj generowane komentarze tożsamością usługi, żeby pochodzenie nigdy nie było niejednoznaczne
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Note: TXLSXComment;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('reconciliation.xlsx');
Sheet := Book.Sheets[0];
// Notatka z autorem przy skorygowanej wartości
Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',
'recon-service');
// Zaktualizuj istniejącą notatkę zamiast nakładać drugą
Note := Sheet.Comments.FindAt(14, 4);
if Note <> nil then
Note.Text := Note.Text + ' [verified 2026-06-11]';
Book.SaveAs('reconciliation-reviewed.xlsx');
finally
Book.Free;
end;
end;
Sonda FindAt waży więcej, niż na to wygląda. Zadanie wsadowe, które ponawia próbę po przejściowej awarii, chętnie wywoła AddComment drugi raz na komórce, którą już opatrzyło notatką, i komórka kończy z dwiema nałożonymi notatkami, o które nikt nie prosił. Najpierw sonduj przez FindAt i aktualizuj obiekt, który zwróci. Kolekcja Comments wystawia też DeleteAt i DeleteInRange. Ten wariant zakresowy jest tym, po który sięgasz, gdy oczyszczasz skoroszyt przed jego wysłaniem poza firmę: usunięcie wewnętrznych adnotacji QA z całego obszaru to jedno wywołanie, a nie ręcznie pisana pętla po komórkach
Zewnętrzne adresy URL i skoki wewnątrz skoroszytu to różne API
OOXML trzyma oba rodzaje linków w różnych miejscach. Zewnętrzny adres URL staje się wpisem relacji w części .rels arkusza, a komórka wskazuje na relację przez jej identyfikator. Wewnętrzny skok w ogóle nie dotyka warstwy relacji; to zwykły ciąg lokalizacji, taki jak Summary!A1, przechowywany wprost na linku. HotXLS utrzymuje to rozróżnienie widoczne w API, zamiast przeciążać jedną metodę, co znaczy, że właściwe wywołanie wybierasz, wiedząc, gdzie mieszka cel:
Sheet.Cells[2, 1].Value := 'Source record';
Sheet.AddHyperlink(2, 1, 'https://intranet.example.com/records/2214',
'Open record 2214', 'ERP source entry');
Sheet.Cells[3, 1].Value := 'Totals';
Sheet.AddHyperlinkToCell(3, 1, 'Overview!B12', 'Jump to totals');
Na powstałym obiekcie TXLSXHyperlink pola Url i Location wzajemnie się wykluczają, a IsInternal mówi ci, które z dwóch jest wypełnione. Tę flagę sprawdzasz, gdy inwentaryzujesz linki w otwartym skoroszycie i musisz potraktować "wychodzi z pliku" i "zostaje w pliku" według różnych reguł: zewnętrzny host może stanąć przed listą dozwolonych, podczas gdy cel wewnętrzny musi tylko nazwać arkusz, który istnieje. Wewnętrzne linki nie niosą za sobą żadnych części relacji, co czyni je też tańszymi w masowym przepisywaniu
Awaria z otwarcia artykułu żyje w całości po stronie wewnętrznej i wynika z jednego faktu: ciąg lokalizacji nie jest sparsowaną referencją. HotXLS zapisuje dokładnie ten tekst, który mu podasz, i nic nie przekierowuje tego tekstu, gdy arkusz zostanie później przemianowany. W praktyce sprawdzają się dwie obrony. Pierwsza to dyscyplina kolejności: zmień nazwy wszystkich arkuszy, zanim wygenerujesz choćby jeden link, a potem traktuj nazwy arkuszy jak zamrożone identyfikatory. Druga jest solidniejsza i przeżywa zmiany nazw dokonane po fakcie. Skieruj link na nazwę zdefiniowaną na poziomie skoroszytu zamiast na surowy adres Sheet!Cell, bo Excel przepisuje definicję nazwy, gdy zmienia się arkusz pod spodem, więc link jedzie razem z nią automatycznie. To drugie podejście naturalnie łączy się z technikami z artykułu nazwy zdefiniowane i formuły międzyarkuszowe w HotXLS
Strona XLS: te same pojęcia, starsza hydraulika
Fasada BIFF8 wiesza komentarze na zakresach zamiast na kolekcji na poziomie arkusza. Wywołujesz AddComment na IXLSRange i dostajesz z powrotem TXLSComment; właściwość Comment zakresu czyta istniejącą notatkę, a ClearComments je kasuje. Ostra krawędź jest tutaj pozycyjna. TXLSComment nie wystawia publicznie własnego wiersza i kolumny, więc naturalna pętla "przejdź po każdym komentarzu i zgłoś, gdzie siedzi" działa pod prąd API. Musisz zacząć od komórek. Albo prowadź audyt z listy adresów, które opatrzyłeś notatkami, albo trzymaj własny log pozycji w trakcie zapisu, bo obiekt komentarza nie powie ci potem, gdzie mieszka
var
Book: IXLSWorkbook;
Sheet: IXLSWorksheet;
Remark: TXLSComment;
begin
Book := TXLSWorkbook.Create;
Sheet := Book.Sheets.Add;
Sheet.Name := 'Review';
Sheet.Cells.Item[5, 2].Value := 4821.50;
Remark := Sheet.Cells.Item[5, 2].AddComment('Awaiting sign-off from controller');
Remark.Visible := True; // otwórz notatkę od razu przy pierwszym spojrzeniu
Sheet.AddHyperlink(7, 2, 'https://intranet.example.com/signoff/4821',
'Sign-off form', 'Opens the controller queue');
Book.SaveAs('review.xls');
end;
Ustawienie Visible na True to starszy sposób, by notatka była nie do przeoczenia: żółte pole zostaje otwarte na arkuszu zamiast czekać na najechanie kursorem. TXLSComment idzie krok dalej niż jego odpowiednik z XLSX, bo wystawia TextRuns, więc pojedyncza notatka może nieść pogrubione ostrzeżenie obok zwykłego wyjaśnienia — formatowanie, którego API komentarzy XLSX nie wystawia w ten sam sposób. Hiperłącza po tej stronie przychodzą przez trzy narastające przeciążenia (sam adres, potem z tekstem wyświetlanym, potem z dymkiem podpowiedzi) i odczytuje się je przez kolekcję HyperLinks arkusza, gdzie każdy link wystawia Address, SubAddress, DisplayText i ScreenTip
Arkusz indeksu recenzji bije rozproszone notatki
Powyżej kilkunastu adnotacji czytanie przez najechanie kursorem po cichu przestaje się skalować. Notatki piętrzą się na arkuszach, których recenzent nigdy nie otwiera, a te najważniejsze są dokładnie tymi, które najłatwiej przeoczyć. Strukturą, która trzyma się najlepiej, jest generowany arkusz indeksu: jeden wiersz na adnotowaną lokalizację, z nazwą arkusza, adresem komórki, autorem i krótkim fragmentem notatki. Ostatnia kolumna niesie wewnętrzne hiperłącze zbudowane przez AddHyperlinkToCell, które skacze prosto do adnotowanej komórki. Teraz recenzent czyta listę w dół zamiast polować po siatce, a liczba wierszy tego indeksu służy zarazem za inwentarz komentarzy do przebiegu audytu opisanego niżej
Indeks jest tani w budowie, bo twój generator zna już każdą pozycję, której dotknął. Dopisuj krotkę (arkusz, wiersz, kolumna, autor, streszczenie) do listy przy zapisie każdego komentarza, a arkusz indeksu emituj na końcu, żeby liczba jego wierszy była ostateczna przed zapisem. Dwa dopracowania się opłacają: uporządkuj indeks według wagi albo według arkusza, a nie według kolejności wstawiania, i umieść link powrotny w nagłówku indeksu, żeby recenzent mógł odbić się na górę po każdej pozycji. Ponieważ wewnętrzne linki to zwykłe ciągi lokalizacji bez niczego w warstwie relacji za nimi, nawet tysiącwierszowy indeks prawie nic nie dodaje do rozmiaru pliku ani do czasu zapisu
Ten sam arkusz opłaca się ponownie w drodze powrotnej. Kiedy zrecenzowany skoroszyt wraca, twój kod czyta wartości statusu wpisane do komórek obok wierszy indeksu, zamiast ponownie skanować każdy arkusz w poszukiwaniu komentarzy, które mogły się zmienić. Kolumna ustrukturyzowanych komórek statusu parsuje się czysto; rozsypka swobodnych notatek tekstowych nie
Przebieg audytu przed dostawą, który naprawdę łapie awarię
Żadne z tych API nie waliduje celu. Link do arkusza, który usunąłeś, źle wpisany host intranetowy, udział plikowy wycofany w zeszłym kwartale: wszystko to zapisuje się bez szemrania. ECMA-376 określa, jak link jest przechowywany, a nie to, że do czegokolwiek się rozwiązuje. Skoroszyt niosący metadane recenzji zasługuje więc na krótki własny etap audytu, uruchamiany tuż przed SaveAs:
- Zbierz każdą wewnętrzną lokalizację zapisaną podczas generowania i potwierdź, że nazwa arkusza przed wykrzyknikiem nadal istnieje w kolekcji arkuszy skoroszytu
- Sprawdź zewnętrzne adresy URL wobec listy dozwolonych schematów i hostów. Gołe ścieżki
file://i UNC wyciekają szczegóły środowiska i psują się w chwili, gdy plik opuszcza twoją sieć - Policz komentarze na arkusz i porównaj z tym, co twój generator zamierzał zapisać. Ponowienie, które podwoiło notatki, wychodzi tutaj, a nie w skrzynce recenzenta
- Usuwaj adnotacje wyłącznie wewnętrzne przez
DeleteInRange, ilekroć odbiorca siedzi poza organizacją
Zespoły, które budują skoroszyty z warstwy danych, mogą wpiąć ten etap w ten sam krok potoku, który już waliduje dane, więc kontrola metadanych jedzie razem za darmo. Mechanika jest tą opisaną w artykule eksport wyników zapytań bazodanowych do raportów Excela, obrócona ku linkom i komentarzom zamiast ku wierszom
Jeden szczegół cytowania podkłada ludziom nogę, gdy budują ciągi lokalizacji ręcznie. Arkusz, którego nazwa zawiera spację, musi być ujęty w apostrofy wewnątrz lokalizacji, dokładnie tak, jak ujmuje go pasek formuły: 'Quarterly Totals'!A1, a nie Quarterly Totals!A1. HotXLS stosuje te same reguły, których silnik formuł używa do referencji międzyarkuszowych, więc jeśli link działa w formule arkusza, jego cytowanie zadziała i tutaj. Podaj mu nieujętą nazwę ze spacją, a dostaniesz ten sam cichy martwy link, przed którym ostrzegało otwarcie
Komentarze i hiperłącza to te części generowanego skoroszytu, na których recenzenci działają bez zastanowienia, i właśnie dlatego cel wskazujący w nicość robi realną szkodę, zanim ktokolwiek zauważy. Zbuduj przebieg walidacji raz, uruchamiaj go na każdym skoroszycie, zanim wyruszy, a przepływ recenzji przetrwa zmiany nazw i konwersje. Pełna powierzchnia API dla obu fasad, XLS i XLSX, jest udokumentowana na stronie produktu HotXLS Delphi Component