Суббота
18.05.2024, 23:30
M@kS!M 2010
Приветствую Вас Гость | RSS
Главная Дневник Регистрация Вход
Меню

Категории раздела
Все любовные истории [9]
Сказки о любви [5]
Стихи о любви [5]
Поздравления для любимых [1]
Программирование [2]
Прикольные SMS [8]

Мини-чат

Наш опрос
Оцените мой сайт
Всего ответов: 202

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » 2008 » Апрель » 14 » Процедуры и функции для работы с OpenOffice
20:01
Процедуры и функции для работы с OpenOffice

Владимир Ермаков, Королевство Дельфи

Все в мире развивается по спирали. Раньше программисты разрабатывали механизмы взаимодействия между Delphi и MSExcel, теперь они методом проб и ошибок создают приложения для создания документов в OpenOffice. Надеюсь, что эта статья сэкономит время и усилия для решения более важных проблем, чем открытие шаблона и поиск нужной ячейки.

Автор ни в коем случае не возлагает на себя лавры разработчика-первооткрывателя. Очень многое из данной статьи лежит в интернете на разных сайтах. Например — www.delphimaster.ru и др.

Другие процедуры и функции были созданы прямо в процессе работы над заданием. Все было проверено на работоспособность. Итак, начнем.

Для удобства работы, вынесем базовые функции и процедуры в новый класс

type TopofCalc = class(TObject)

при работе с таблицами, информация о типе документа может принимать следующие состояния:

type TTipooCalc = (ttcError, ttcNone, ttcExcel, ttcOpenOffice);

данные функции определяет тип приложения

function TopofCalc.GetIsExcel: boolean;
begin
 result:= (Tipoo=ttcExcel);
end;
function TopofCalc.GetIsOpenOffice: boolean;
begin
 result:= (Tipoo=ttcOpenOffice);
end;

и произведена ли его загрузка

function TopofCalc.GetProgLoaded: boolean;
begin
 result:= not (VarIsEmpty(Programa) or VarIsNull(Programa));
end;
function TopofCalc.GetDocLoaded: boolean;
begin
 result:= not (VarIsEmpty(Document) or VarIsNull(Document));
end;

запуск приложения…

procedure TopofCalc.LoadProg;
begin
 if ProgLoaded then CloseProg;
 if ((UpperCase(ExtractFileExt(FileName))='.XLS') or
 (UpperCase(ExtractFileExt(FileName))='.XLT')) then begin
 //Excel...
 Programa:= CreateOleObject('Excel.Application');
 Programa.Application.EnableEvents:=false;
 Programa.displayAlerts:=false;
 if ProgLoaded then Tipoo:= ttcExcel;
 end;
 // Another filetype? Let's go with OpenOffice...
 if ((UpperCase(ExtractFileExt(FileName))='.ODS') or
 (UpperCase(ExtractFileExt(FileName))='.OTS')) then begin
 //OpenOffice.calc...
 Programa:= CreateOleObject('com.sun.star.ServiceManager');
 if ProgLoaded then Tipoo:= ttcOpenOffice;
 end;
 //Still no program loaded?
 if not ProgLoaded then begin
 Tipoo:= ttcError;
 raise Exception.create('TopofCalc.create failed, may be no Office is installed?');
 end;
end;

проведя все необходимые проверки, мы можем создать электронную таблицу

procedure TopofCalc.NewDoc;
var ooParams: variant;
begin
 if not ProgLoaded
 then raise exception.create('No program loaded for the new document.');
 if DocLoaded then CloseDoc;
 DeskTop:= Unassigned;
 if IsExcel then begin
 Programa.WorkBooks.Add();
 Programa.Visible:= Visible;
 Document:= Programa.ActiveWorkBook;
 ActiveSheet:= Document.ActiveSheet;
 end;
 if IsOpenOffice then begin
 Desktop:= Programa.CreateInstance('com.sun.star.frame.Desktop');
 ooParams:= VarArrayCreate([0, 0], varVariant);
 ooParams[0]:= ooCreateValue('Hidden', not Visible);
 Document:= Desktop.LoadComponentFromURL('private:factory/scalc', '_blank',
 0, ooParams);
 ActivateSheetByIndex(1);
 end;
end;

а теперь закрыть таблицу

procedure TopofCalc.CloseDoc;
begin
 if DocLoaded then begin
 try
 if IsOpenOffice then Document.Dispose;
 if IsExcel then Document.close;
 finally
 //Clean up both "pointer"...
 Document:= Null;
 ActiveSheet:= Null;
 end;
 end;
end;

и само приложение

procedure TopofCalc.CloseProg;
begin
 if DocLoaded then CloseDoc;
 if ProgLoaded then begin
 try
 if IsExcel then Programa.Quit;
 Programa:= Unassigned;
 finally end;
 end;
 Tipoo:= ttcNone;
end;

вынесем последовательности команд создания таблицы в отдельную процедуру конструктора

constructor TopofCalc.CreateTable(MyTipoo: TTipooCalc; MakeVisible: boolean);
var
 i: integer;
 IsFirstTry: boolean;
begin
 //Close all opened things first...
 if DocLoaded then CloseDoc;
 if ProgLoaded then CloseProg;
 IsFirstTry:= true;
 for i:= 1 to 2 do begin
 //Try to open OpenOffice...
 if (MyTipoo = ttcOpenOffice) or (MyTipoo = ttcNone)then begin
 Programa:= CreateOleObject('com.sun.star.ServiceManager');
 if ProgLoaded then begin
 Tipoo:= ttcOpenOffice;
 break;
 end else begin
 if IsFirstTry then begin
 //Try Excel as my second choice
 MyTipoo:= ttcExcel;
 IsFirstTry:= false;
 end else begin
 //Both failed!
 break;
 end;
 end;
 end;
 //Try to open Excel...
 if (MyTipoo = ttcExcel) or (MyTipoo = ttcNone) then begin
 Programa:= CreateOleObject('Excel.Application');
 if ProgLoaded then begin
 Tipoo:= ttcExcel;
 break;
 end else begin
 if IsFirstTry then begin
 //Try OpenOffice as my second choice
 MyTipoo:= ttcOpenOffice;
 IsFirstTry:= false;
 end else begin
 //Both failed!
 break;
 end;
 end;
 end;
 end;
 //Was it able to open any of them?
 if Tipoo = ttcNone then begin
 Tipoo:= ttcError;
 raise exception.create('TopofCalc.create failed, may be no OpenOffice is installed?');
 end;
 //Add a blank document...
 fVisible:= MakeVisible;
 NewDoc;
end;

это – создание таблицы «с нуля». откроем существующую

procedure TopofCalc.LoadDoc;
var ooParams: variant;
begin
 if FileName='' then exit;
 if not ProgLoaded then LoadProg;
 if DocLoaded then CloseDoc;
 DeskTop:= Unassigned;
 if IsExcel then begin
 Document:=Programa.WorkBooks.Add(FileName);
 Document.visible:=visible;
 Document:= Programa.ActiveWorkBook;
 ActiveSheet:= Document.ActiveSheet;
 end;
 if IsOpenOffice then begin
 Desktop:= Programa.CreateInstance('com.sun.star.frame.Desktop');
 ooParams:= VarArrayCreate([0, 0], varVariant);
 ooParams[0]:= ooCreateValue('Hidden', not Visible);
 Document:= Desktop.LoadComponentFromURL(FileNameToURL(FileName), '_blank', 0, ooParams);
 ActivateSheetByIndex(1);
 end;
 if Tipoo=ttcNone then
 raise exception.create('File "'+FileName+'" is not loaded. Are you install OpenOffice?');
end;

опишем еще один конструктор для открытия существующей таблицы

constructor TopofCalc.OpenTable(Name: string; MakeVisible: boolean);
begin
 //Store values...
 FileName:= Name;
 fVisible:= MakeVisible;
 //Open program and document...
 LoadProg;
 LoadDoc;
end;

кроме того, опишем уничтожение объекта

destructor TopofCalc.Destroy;
begin
 CloseDoc;
 CloseProg;
 inherited;
end;

по аналогии, опишем сохранение

function TopofCalc.SaveDoc: boolean;
begin
 result:= false;
 if DocLoaded then begin
 if IsExcel then begin
 Document.Save;
 result:= true;
 end;
 if IsOpenOffice then begin
 Document.Store;
 result:= true;
 end;
 end;
end;

печать

function TopofCalc.PrintDoc: boolean;
var ooParams: variant;
begin
 result:= false;
 if DocLoaded then begin
 if IsExcel then begin
 Document.PrintOut;
 result:= true;
 end;
 if IsOpenOffice then begin
 //NOTE: OpenOffice will print all sheets with Printable areas, but if no
 //printable areas are defined in the doc, it will print all entire sheets.
 //Optional parameters (wait until fully sent to printer)...
 ooParams:= VarArrayCreate([0, 0], varVariant);
 ooParams[0]:= ooCreateValue('Wait', true);
 Document.Print(ooParams);
 result:= true;
 end;
 end;
end;

и режим предварительного просмотра

procedure TopofCalc.ShowPrintPreview;
begin
 if DocLoaded then begin
 Visible:= true;
 if IsExcel then
 Document.PrintOut(,,,true);
 if IsOpenOffice then
 ooDispatch('.uno:PrintPreview', Unassigned);
 end;
end;

нам также пригодится скрытие/отображение на экране

procedure TopofCalc.SetVisible(v: boolean);
begin
 if DocLoaded and (v<>fVisible) then begin
 if IsExcel then
 Programa.Visible:= v;
 if IsOpenOffice then
 Document.getCurrentController.getFrame.getContainerWindow.setVisible(v);
 fVisible:= v;
 end;
end;

теперь, мы можем получить информацию о таблице.
Начнем с количества листов

function TopofCalc.GetCountSheets: integer;
begin
 result:= 0;
 if DocLoaded then begin
 if IsExcel then result:= Document.Sheets.count;
 if IsOpenOffice then result:= Document.getSheets.GetCount;
 end;
end;

и сделаем один из листов активным.

function TopofCalc.ActivateSheetByIndex(nIndex: integer): boolean;
begin
 result:= false;
 if DocLoaded then begin
 if IsExcel then begin
 Document.Sheets[nIndex].activate;
 ActiveSheet:= Document.ActiveSheet;
 result:= true;
 end;
//Index is 1 based in Excel, but OpenOffice uses it 0-based
 if IsOpenOffice then begin
 ActiveSheet:= Document.getSheets.getByIndex(nIndex-1);
 result:= true;
 end;
 sleep(100); //Asyncronus, so better give it time to make the change
 end;
end;

активным лист можно сделать не только по его индексу, но и по названию

function TopofCalc.ActivateSheetByName(SheetName: string; CaseSensitive: boolean): boolean;
var
 OldActiveSheet: variant;
 i: integer;
begin
 result:= false;
 if DocLoaded then begin
 if CaseSensitive then begin
 //Find the EXACT name...
 if IsExcel then begin
 Document.Sheets[SheetName].Select;
 ActiveSheet:= Document.ActiveSheet;
 result:= true;
 end;
 if IsOpenOffice then begin
 ActiveSheet:= Document.getSheets.getByName(SheetName);
 result:= true;
 end;
 end else begin
 //Find the Sheet regardless of the case...
 OldActiveSheet:= ActiveSheet;
 for i:= 1 to GetCountSheets do begin
 ActivateSheetByIndex(i);
 if UpperCase(ActiveSheetName)=UpperCase(SheetName) then begin
 result:= true;
 Exit;
 end;
 end;
 //If not found, let the old active sheet active...
 ActiveSheet:= OldActiveSheet;
 end;
 end;
end;

getByName(string) имеет свойства для чтения и записи

function TopofCalc.GetActiveSheetName: string;
begin
 if DocLoaded then begin
 if IsExcel then
 result:= ActiveSheet.Name;
 if IsOpenOffice then
 result:= ActiveSheet.GetName;
 end;
end;
procedure TopofCalc.SetActiveSheetName(NewName: string);
var ooParams:variant;
begin
 if DocLoaded then begin
 if IsExcel then
 Programa.ActiveSheet.Name:= NewName;
 if IsOpenOffice then begin
 ActiveSheet.setName(NewName);
 //This code always changes the name of "visible" sheet, not active one!
 ooParams:= VarArrayCreate([0, 0], varVariant);
 ooParams[0]:= ooCreateValue('Name', NewName);
 ooDispatch('.uno:RenameTable', ooParams);
 end;
 end;
end;

пригодится проверка на защиту листа от записи

function TopofCalc.IsActiveSheetProtected: boolean;
begin
 result:= false;
 if DocLoaded then begin
 if IsExcel then
 result:= ActiveSheet.ProtectContents;
 if IsOpenOffice then
 result:= ActiveSheet.IsProtected;
 end;
end;

добваление листа

procedure TopofCalc.AddNewSheet(NewName: string);
var
 ooSheets: variant;
begin
 if DocLoaded then begin
 if IsExcel then begin
 Document.WorkSheets.Add;
 Document.ActiveSheet.Name:= NewName;
 //Active sheet has move to this new one, so I need to update the var
 ActiveSheet:= Document.ActiveSheet;
 end;
 if IsOpenOffice then begin
 ooSheets:= Document.getSheets;
 ooSheets.insertNewByName(NewName, 1);
 //Redefine active sheet to this new one
 ActiveSheet:= ooSheets.getByName(NewName);
 end;
 end;
end;

перейдем от листов к ячейкам
получить значение ячейки

//OpenOffice start at cell (0,0) while Excel at (1,1)
function TopofCalc.GetCellText(row, col: integer): string;
begin
 if DocLoaded then begin
 if IsExcel then result:= ActiveSheet.Cells[row, col].Formula; //.Text;
 if IsOpenOffice then result:= ActiveSheet.getCellByPosition(col-1, row-1).getFormula;
 end;
end;

установить значение

procedure TopofCalc.SetCellText(row, col: integer; Txt: string);
begin
 if DocLoaded then begin
 if IsExcel then ActiveSheet.Cells[row, col].Formula:= Txt;
 if IsOpenOffice then ActiveSheet.getCellByPosition(col-1, row-1).setFormula(Txt);
 end;
end;

то же самое, но по имени ячейки.

Обязательно указание номера листа

function TopofCalc.GetCellTextByName(Range: string): string;
var OldActiveSheet: variant;
begin
 if DocLoaded then begin
 if IsExcel then begin
 result:= Programa.Range[Range].Text; //Set 'Formula' but Get 'Text';
 end;
 if IsOpenOffice then begin
 OldActiveSheet:= ActiveSheet;
 //If range is in the form 'NewSheet!A1' then first change sheet to 'NewSheet'
 if pos('!', Range) > 0 then begin
 //Activate the proper sheet...
 if not ActivateSheetByName(Copy(Range, 1, pos('!', Range)-1), false) then
 raise exception.create('Sheet "'+Copy(Range, 1, pos('!', Range)-1)+
 '" not present in the document.');
 Range:= Copy(Range, pos('!', Range)+1, 999);
 end;
 result:= ActiveSheet.getCellRangeByName(Range).getCellByPosition(0,0).getFormula;
 ActiveSheet:= OldActiveSheet;
 end;
 end;
end;
procedure TopofCalc.SetCellTextByName(Range: string; Txt: string);
var OldActiveSheet: variant;
begin
 if DocLoaded then begin
 if IsExcel then begin
 Programa.Range[Range].formula:= Txt;
 end;
 if IsOpenOffice then begin
 OldActiveSheet:= ActiveSheet;
 //If range is in the form 'NewSheet!A1' then first change sheet to 'NewSheet'
 if pos('!', Range) > 0 then begin
 //Activate the proper sheet...
 if not ActivateSheetByName(Copy(Range, 1, pos('!', Range)-1), false) then
 raise exception.create('Sheet "'+Copy(Range, 1, pos('!', Range)-1)+
 '" not present in the document.');
 Range:= Copy(Range, pos('!', Range)+1, 999);
 end;
 ActiveSheet.getCellRangeByName(Range).getCellByPosition(0,0).SetFormula(Txt);
 ActiveSheet:= OldActiveSheet;
 end;
 end;
end;

а так же – размера шрифта. Можно установить его в шаблоне, а можно прямо в ходе работы программы.

procedure TopofCalc.FontSize(row,col:integer;oosize:integer);
begin
 if DocLoaded then begin
 if IsExcel then begin
 Programa.ActiveSheet.Cells[row,col].Font.Size:=oosize;
 end;
 if IsOpenOffice then begin
 ActiveSheet.getCellByPosition(col-1, row-1).getText.createTextCursor.CharHeight:= oosize;
 end;
 end;
end;

сделать шрифт жирным

procedure TopofCalc.Bold(row,col: integer);
const ooBold: integer = 150; //150 = com.sun.star.awt.FontWeight.BOLD
begin
 if DocLoaded then begin
 if IsExcel then begin
 Programa.ActiveSheet.Cells[row,col].Font.Bold;
 end;
 if IsOpenOffice then begin
 ActiveSheet.getCellByPosition(col-1, row-1).getText.createTextCursor.CharWeight:= ooBold;
 end;
 end;
end;

изменить ширину столбца

procedure TopofCalc.ColumnWidth(col, width: integer); //Width in 1/100 of mm.
begin
 if DocLoaded then begin
 if IsExcel then begin
 //Excel use the width of '0' as the unit, we do an aproximation: Width '0' = 2 mm.
 Programa.ActiveSheet.Cells[col, 1].ColumnWidth:= width/100/3;
 end;
 if IsOpenOffice then begin
 ActiveSheet.getCellByPosition(col-1, 0).getColumns.getByIndex(0).Width:= width;
 end;
 end;
end;

в заключение, предлагаю функции, предназначенные именно для OpenOffice

преобразование имени

//Change 'C:\File.txt' into 'file:///c:/File.txt' (for OpenOffice OpenURL)
function TopofCalc.FileNameToURL(FileName: string): string;
begin
 result:= '';
 if LowerCase(copy(FileName,1,8))<>'file:///' then
 result:= 'file:///';
 result:= result + StringReplace(FileName, '\', '/', [rfReplaceAll, rfIgnoreCase]);
end;

создание объекта

function TopofCalc.ooCreateValue(ooName: string; ooData: variant): variant;
var
 ooReflection: variant;
begin
 if IsOpenOffice then begin
 ooReflection:= Programa.createInstance('com.sun.star.reflection.CoreReflection');
 ooReflection.forName('com.sun.star.beans.PropertyValue').createObject(result);
 result.Name := ooName;
 result.Value:= ooData;
 end else begin
 raise exception.create('ooValue imposible to create, load OpenOffice first!');
 end;
end;

запуск диспатчера

procedure TopofCalc.ooDispatch(ooCommand: string; ooParams: variant);
var
 ooDispatcher, ooFrame: variant;
begin
 if DocLoaded and IsOpenOffice then begin
 if (VarIsEmpty(ooParams) or VarIsNull(ooParams)) then
 ooParams:= VarArrayCreate([0, -1], varVariant);
 ooFrame:= Document.getCurrentController.getFrame;
 ooDispatcher:= Programa.createInstance('com.sun.star.frame.DispatchHelper');
 ooDispatcher.executeDispatch(ooFrame, ooCommand, '', 0, ooParams);
 end else begin
 raise exception.create('Dispatch imposible, load a OpenOffice doc first!');
 end;
end;
end.

 

Редакция рекомендует:
Категория: Программирование | Просмотров: 659 | Добавил: maxim2007 | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Форма входа

Поиск

Календарь
«  Апрель 2008  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
282930

Архив записей


Copyright MyCorp © 2024