Закроем Excel корректно!
Собственно говоря, при закрытии приложения Excel сам будет закрыт, если вы там не устели чего-нибудь отредактировать. И это правильно. Программисты Borland (Inprise до сих пор мне режет слух, да и некоторым в Inprise, судя по всему, тоже) позаботились об этом. Но я еще с Delphi 3 заимел дурную привычку освобождать все самостоятельно. Освобождать обычным присваиванием в nil (это касается проекта для D4). Труда это не составляет, да и проверка на Assigned удобна. Поэтому, и еще из кое-каких соображений, я делаю так:
Delphi 4.0
procedure TForm1.ReleaseExcel;
begin
if Assigned(FIXLSApp) then begin
if (FIXLSApp.Workbooks.Count > 0) and (not FIXLSApp.Visible[0]) then begin
FIXLSApp.WindowState[0] := TOLEEnum(xlMinimized);
FIXLSApp.Visible[0] := true;
Application.BringToFront;
end;
end;
FIXLSApp := nil;
end;
Ну вот, написал только про nil, а кода - на полстраницы. Опишу ситуацию.
Вы не запускали новый процесс, вы “законнектились” к уже существовавшему. В нем была открыта книга. Попробуйте: CreateExcel, ShowExcel, HideExcel (имеем право), ReleaseExcel. Если оставить только присваивание в nil, то существовавший процесс не будет выгружен (он же существовал до запуска нашего демо), но будет спрятан от пользователя с его открытой книгой.
Delphi 5.0
procedure TForm1.ReleaseExcel;
begin
if Assigned(IXLSApp) then begin
if (IXLSApp.Workbooks.Count > 0) and (not IXLSApp.Visible[0]) then begin
IXLSApp.WindowState[0] := TOLEEnum(xlMinimized);
IXLSApp.Visible[0] := true;
if not(csDestroying in ComponentState) then Self.SetFocus;
Application.BringToFront;
end;
end;
FreeAndNil(FIXLSApp);
end;
Практически тот же код. Только в D5 вы работаете уже не с интерфейсом напрямую, а с экземпляром класса TexcelApplcation. Если посмотреть его предков, то можно увидеть, что это настоящий класс, освободить который просто необходимо. Поэтому вместо присваивания в nil там написано FreeAndNil (помните такую процедуру?).
Часть 2: Лучшее решение - шаблоны.
Excel, интегрированный с моими приложениями, хорош (для меня - программиста) только по одной причине. Я всегда создаю шаблоны и использую их потом при построении отчетов. Шаблоны позволяют мне избежать ручного (в исходном тексте) форматирования. В общем случае, алгоритм выглядит просто: по шаблону создается книга, каким-то образом помеченные области заполняются данными и… (а дальше все уже готово). Как я создаю книгу по шаблону:
Delphi 4.0 / 5.0
function TForm1.AddWorkbook(const WorkbookName: string): Excel8TLB._Workbook;
begin
Result := nil;
if Assigned(FIXLSApp) and (trim(WorkbookName) <> ”) then begin
Result := FIXLSApp.Workbooks.Add(WorkbookName, 0);
end;
end;
В этом коде нет ничего сложного. В принципе при работе с Excel я мало находил мест, где что-либо сделать было бы сложно. Чаще достаточно прочитать справку по VBA или записать макрос (благо, Microsoft встроила в Excel хороший пишущий player). После выполнения этого метода будет добавлена книга, близнец шаблона, с именем шаблона и порядковым номером (как “Книга1.xls” или “Книга228.xls”). Правда здесь есть одна тонкость. Эти “циферки” в имя книги Excel добавляет после поиска книг с таким же названием в каталоге по умолчанию. Я несколько раз наступал на грабли (больно!), когда пытался сохранять книги в другом каталоге и создавать новую - по этому же шаблону. К сожалению, не может эта “злобная” программа держать открытыми несколько книг с одинаковыми названиями, несмотря на то, что они лежат в разных каталогах.
Как я помечаю области, в которые необходимо разместить данные? В Excel существует возможность объединить ячейки в группу и поименовать эту группу. В терминах Microsoft это объект Range (область). Для своего проекта я создал тестовую книгу “Test.xls”, в которой на листе “Лист1″ разместил область “TestRange” (см. рисунок). Более того, для ячеек этой области я указал форматы вывода (Field4 - дата, Field3 - красный цвет шрифта). Я надеюсь, что после переноса тестовых данных форматы сохранятся.
