Technical Article

Коментари на клетки и хипервръзки в Excel от Delphi с HotXLS

Преименувайте лист от „Summaryâ€?на „Overviewâ€?в генерирана работна книга и всяка вътрешна връзка, която сочи към Summary!A1, ще спре да работи. Без изключение при запис, без съобщение при отваряне. Връзката продължава да се показва и изглежда активна, но не води до никъде. Подобни проблеми възникват и след конвертиране чрез „запиÑ?катоâ€?или при преобразуване между .xls и .xlsx, когато коментар се измести с една колона или относителна връзка загуби целта си. И двете функции съдържат състояние за преглед, от което зависят потребителите, така че когато се повредят, грешката остава скрита, докато някой не кликне върху тях.

Това е практическата причина, поради която коментарите и хипервръзките изискват повече внимание, отколкото подсказва външният им вид. HotXLS предоставя на Delphi и C++Builder разработчиците директен достъп за запис и на двата обекта в XLS и XLSX без необходимост от Excel автоматизация. Обратната страна на този контрол е отговорността: библиотеката записва точните цели, които й подадете, без да ги валидира, така че поддържането на коректен работен процес за преглед е задача на вашия код, а не на Excel.

Коментари в клетките като автоматизирани записи за преглед

В класовия модел на XLSX коментарът е обект на ниво работен лист: неговият автор е налице, той знае своя ред, своята колона и има текст. Полето за автор има важно значение. Когато генерираната книга преминава през верига за одит, първият въпрос е кой е написал дадена бележка, а бележка без автор оставя това поле празно. Винаги маркирайте автоматично генерираните коментари с името на съответната услуга, за да бъде произходът им ясен.

var

  Book: TXLSXWorkbook;

  Sheet: TXLSXWorksheet;

  Note: TXLSXComment;

begin

  Book := TXLSXWorkbook.Create;

  try

    Book.Open('reconciliation.xlsx');

    Sheet := Book.Sheets[0];



    // Authored note on the adjusted figure

    Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',

      'recon-service');



    // Update an existing note instead of stacking a second one

    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;

Методът FindAt е по-полезен, отколкото изглежда. Автоматична задача, която се рестартира след временна грешка, би извикала AddComment втори път за същата клетка, което води до два насложени коментара. Винаги проверявайте първо с FindAt и обновявайте върнатия обект. Колекцията Comments излага също DeleteAt и DeleteInRange. Вариантът за диапазон е изключително удобен за изчистване на вътрешни QA анотации от цяла област с едно извикване, преди файлът да напусне организацията.

Външните URL адреси и вътрешните връзки в книгата ползват различни API

Форматът OOXML съхранява двата вида връзки на различни места. Външният URL адрес се записва като връзка в .rels частта на листа, а клетката сочи към него по идентификатор (ID). Вътрешният преход никога не докосва слоя с връзките, той е обикновен низ с местоположение (например Overview!B12), съхранен директно в самата връзка. HotXLS запазва това разграничение в API, вместо да претоварва един метод. Това означава, че избирате правилния метод въз основа на местоположението на целта:

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');

В обекта TXLSXHyperlink свойствата Url и Location се изключват взаимно, а IsInternal указва кой от двата е попълнен. Този флаг се проверява при опис на връзките в отворен документ, когато трябва да се приложат различни правила за външни и вътрешни цели: външните хостове могат да се проверяват спрямо списък с разрешени адреси, докато за вътрешните е достатъчно да сочат към съществуващ лист. Вътрешните връзки не изискват генериране на релационни части, което ги прави по-бързи за масова промяна.

Описаният проблем с преименуването на листове засяга именно вътрешните връзки, тъй като низът за местоположение не е парсната референция. HotXLS записва точния текст, който му подадете, и нищо не променя този текст, ако листът се преименува по-късно. Две стратегии помагат на практика: първо, преименувайте всички листове преди да генерирате каквито и да е връзки; второ, насочете връзката към дефинирано име (defined name) на ниво работна книга вместо към конкретен адрес на клетка. Excel автоматично обновява дефиницията на името при промяна на листа, така че връзката продължава да работи. Този подход се съчетава с описаното в дефинирани имена и формули между листове в HotXLS.

От страна на XLS: същите концепции, по-стара архитектура

Интерфейсът на BIFF8 прикрепя коментарите към диапазони, а не към колекция на ниво работен лист. Извиквате AddComment за IXLSRange и получавате TXLSComment; свойството Comment на диапазона чете съществуваща бележка, а ClearComments ги изтрива. Позиционирането тук има особености. Обектът TXLSComment не показва публично своя ред и колона, така че стандартният цикъл за обхождане и отчитане на позицията на коментарите изисква да започнете от клетките. Записвайте координатите на коментарите при генерирането им, тъй като самият обект няма да ви ги съобщи по-късно.

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;   // pop the note open on first view



  Sheet.AddHyperlink(7, 2, 'https://intranet.example.com/signoff/4821',

    'Sign-off form', 'Opens the controller queue');

  Book.SaveAs('review.xls');

end;

Задаването на Visible на True е класически начин да направите бележката лесна за забелязване, жълтото поле остава отворено, вместо да чака посочване с мишката. Обектът TXLSComment в XLS позволява форматиране на части от текста чрез свойството TextRuns (например удебеляване на предупреждение до обикновен текст), възможност, която не се поддържа по същия начин в XLSX коментарите. Хипервръзките в XLS се създават чрез три претоварени метода (само адрес, с показван текст или с подсказка) и се четат през колекцията HyperLinks на работния лист.

Създаване на индекс с препратки вместо пръснати бележки

При наличие на повече от десетина анотации прегледът чрез посочване с мишката става неефективен. Бележките се натрупват на листове, които никой не отваря, и най-важните от тях лесно се пропускат. Най-доброто решение е генериране на индексен лист за преглед: по един ред за всяко анотирано местоположение, съдържащ името на листа, адреса на клетката, автора и резюме на бележката. Последната колона съдържа вътрешна връзка, създадена с AddHyperlinkToCell, която води директно до анотираната клетка. Така рецензентът чете структуриран списък, вместо да претърсва цялата таблица.

Този индекс се генерира лесно, тъй като приложението знае всяка позиция, която е променило. Добавяйте запис (лист, ред, колона, автор, резюме) към списък при запис на всеки коментар, след което генерирайте индексния лист последен. Две подобрения са полезни: сортирайте индекса по важност или по лист, и поставете връзка за връщане обратно в заглавието на индекса. Тъй като вътрешните връзки са обикновени текстови местоположения без релационни части, голям индекс не увеличава размера на файла или времето за запис.

Същият лист е полезен и при обработка на върнатия файл. Вашето приложение може да чете клетките със статуси до индексните редове, вместо да претърсва отново цялата работна книга за променени коментари. Структурирана колона със статуси се чете лесно, докато разпръснатите коментари са трудни за обработка.

Проверка преди изпращане за предотвратяване на грешки

Нито едно от тези API не валидира целта. Връзка към изтрит лист, грешен вътрешен хост или несъществуващ файлов споделен ресурс се записват без предупреждение. ECMA-376 определя как се съхранява връзката, а не дали тя води до реално местоположение. Поради това е препоръчително да добавите кратка стъпка за одит преди извикването на SaveAs:

  • Съберете всички вътрешни местоположения и потвърдете, че името на листа преди знака â€?â€?съществува в колекцията от листове на книгата.
  • Проверете външните URL адреси спрямо списък с разрешени протоколи и хостове. Пътища от тип file:// и UNC адреси могат да разкрият системна информация и спират да работят извън мрежата.
  • Пребройте коментарите на всеки лист и ги сравнете с очаквания брой, за да откриете евентуални дублирания при повторни опити.
  • Премахнете вътрешните анотации с DeleteInRange, когато файлът е предназначен за външни получатели.

Тази стъпка може да се автоматизира. Механиката е сходна с описаното в експортиране на резултати от бази данни в Excel отчети, но е насочена към връзки и коментари.

Ена подробност при кавичките често води до грешки при ръчно сглобяване на местоположения. Лист, чието име съдържа интервал, трябва да бъде ограден с единични кавички: 'Quarterly Totals'!A1, а не Quarterly Totals!A1. HotXLS прилага същите правила за формули, така че ако връзката работи във формула, тя ще работи и тук. Нецитирано име с интервал води до неработеща връзка.

Коментарите и хипервръзките са елементите, на които потребителите разчитат, поради което неработещите връзки могат да доведат до сериозни проблеми. Изградете автоматична валидация и връзките ви ще останат стабилни при всякакви промени. Пълното API описание е достъпно на продуктовата страница за HotXLS Component.