Работа с Exсel из приложения, написанного на C++Builder (часть 2)

Итак, начинаем второй урок по работе с Excel из C++Builder.

Первый урок был достаточно коротким, после него возникло множество вопросов
и в этом уроке мы попытаемся ответить на многие из них.
Кроме того, на многие вопросы ответили Вы сами,
прислав примеры своих работ с Excel.

Все ответы и примеры построены на программном коде первого урока
(http://cbuilder.ru/WinLesson/bles1.htm)

-----------------------------------------

Список вопросов, ответы на которые приводятся в данном уроке.

1 Как получить из ячейки не только ее значение, но и формулу данной ячейки ?
2 Как нарисовать диаграмму ?
3 Как нарисовать границы у выбранного диапазона ячеек (бордюр) ?
4 Как получить значение какой-либо ячейки ?
5 Как задать формат для ячейки ?
6 Как установить масштаб для документа ?
7 Как выровнять данные в ячейке ?
8 Как установить высоту строки ?
9 Как установить ширину столбца ?
10 Как установить цвет ячеек ?
11 Как задать количество листов в книге ?
12 Как дать название листу ?
13 Как сохранить получившийся документ ?
14 Как установить настройки при печати ?
14 Как распечатать получившийся документ ?
15 Как закрыть документ Excel ?

и множество других...
------------------------------------------

Для того, чтобы лучше понять работу с Excel, рассмотрим иерархию объектов в Excel.


Примерная иерархия вложенных объектов OLE-сервера.

Итак, на вершине — объект Application (у нас в примере Variant App),
Workbooks — книга (не используем), работаем сразу с листом — WorkSheets  — у нас Variant Sh,
группы ячеек Cells — для них используем объект Variant Rang;

"Свойствами объектов Excel могут являться так называемые коллекции объектов.
Например, коллекция Workbooks является свойством объекта Excel.Application, при этом она содержит
набор вложенных объектов — рабочих книг Excel, а те, в свою очередь, обладают свойством Worksheets,
представляющим собой коллекцию рабочих листов, каждый из которых обладает свойством Cells,
являющимся коллекцией ячеек.
Аналогично, коллекция Charts также является свойством рабочей книги"
из статьи "Создание контроллеров автоматизации с помощью C++Builder" Наталия Елманова

Итак, запускаем предыдущий проект и добавляем в него следующий код.

Вопрос. У меня в ячейке есть число, но оно рассчитывается по формуле в этой ячейке.
Как получить из ячейки не только ее значение, но и формулу данной ячейки ?

// получить формулу из ячейки
Variant __fastcall TForm1::fromExcelFormula(int Row, int Column)
{
try{
Variant result,cur;
cur = Sh.OlePropertyGet("Cells",Row,Column);
result = cur.OlePropertyGet("Formula");
return result;
}catch(...) {;}
}
// получаем значение и формулу из ячейки 34,5
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Label3->Caption = fromExcelCell(34,5); // получить значение из ячейки
Label4->Caption = fromExcelFormula(34,5); // получить формулу из ячейки
}
//-----------------------------------------------

Вопрос. Как нарисовать диаграмму ?

void __fastcall TForm1::Button5Click(TObject *Sender)
{
Variant Chart;
Chart=App.OlePropertyGet("Charts").OleFunction("Add"); // добавим объект диаграмму
Chart.OlePropertySet("ChartType",65); // установим один из типов диаграммы

// выберем ячейки для построения диаграммы, это строки 3 — 31 и столбец 3
Chart.OleProcedure("SetSourceData",Sh.OlePropertyGet("Range",Sh.OlePropertyGet("Cells",3,3),
Sh.OlePropertyGet("Cells",31,3)),2);
Chart.OlePropertyGet("SeriesCollection",1).OlePropertySet("XValues",Sh.OlePropertyGet("Range",
Sh.OlePropertyGet("Cells",2,3),Sh.OlePropertyGet("Cells",31,3)));
Chart.OleProcedure("Location",2,Sh.OlePropertyGet("Name"));
// установим место вывода диаграммы
// для этого получим UsedRange — испольуемый диапазон ячеек, и отступим вниз на 25 пикселей
Sh.OlePropertyGet("ChartObjects",1).
OlePropertySet("Top",Sh.OlePropertyGet("UsedRange").OlePropertyGet("Height")+25);
// и слева от края 10 пикселей
Sh.OlePropertyGet("ChartObjects",1).OlePropertySet("left",10);
// встаем на начало
Sh.OlePropertyGet("Cells",1,1).OleProcedure("Select");
}
//-----------------------------------------------------

Вопрос. Как нарисовать границы у выбранного диапазона ячеек (бордюр) ?

// Устанавливаем диапазон ячеек для рисования бордюра A2:E31
int m = 30;
AnsiString s = "A2:E"+IntToStr(m+1);
Variant range = App.OlePropertyGet("Range", s.c_str());
for (int i=1; i<=4; i++)
range.OlePropertyGet("Borders").OlePropertyGet("Item", i).OlePropertySet("LineStyle", 1);

//------------------------------------------------------


Вопрос. Как получить значение какой-либо ячейки ?

Label3->Caption = fromExcelCell(34,5); // получить значение ячейки 34,5

// получить значение ячейки
Variant __fastcall TForm1::fromExcelCell(int Row, int Column)
{
try{
Variant result,cur;
cur = Sh.OlePropertyGet("Cells",Row,Column);
result = cur.OlePropertyGet("Value");
return result;
}catch(...) {;}
}
//-------------------


Вопрос. Как задать формат для ячейки ?

// устанавливаем формат числа для ячейки 1,1
Sh.OlePropertyGet("Cells", 1,1).OlePropertySet("NumberFormat", "0.00");
// устанавливаем формат строка для ячейки 1,2
Sh.OlePropertyGet("Cells", 1,2).OlePropertySet("NumberFormat", "@");
// устанавливаем формат даты для ячейки 1,3
Sh.OlePropertyGet("Cells", 1,3).OlePropertySet("NumberFormat", "ДД.ММ.ГГГГ");

//-------------------

Вопрос. Как установить масштаб для документа ?

// Устанавливаем масштаб = 75%
App.OlePropertyGet("ActiveWindow").OlePropertySet("Zoom", 75);

//-------------------

Вопрос. Как выровнять данные в ячейке ?

// Выравнивам данные в ячейке
Sh.OlePropertyGet("Cells", 1,1).OlePropertySet("HorizontalAlignment", 4);
// где 4 — по левому краю, 2 — по правому, 3 — по центру)

// или по-другому это можно записать так
// Rang = Sh.OlePropertyGet("Cells",1,1);
// Rang.OlePropertySet("HorizontalAlignment",4);
// и для вертикального выравнивания — VerticalAlignment

//-------------------

Вопрос. Как установить высоту строки ?

// устанавливаем высоту 60
Rang.OlePropertySet("RowHeight", 60);

//-------------------

Вопрос. Как установить ширину столбца ?

// устанавливаем ширину столбца 12
Sh.OlePropertyGet("Columns").OlePropertyGet("Item",1).OlePropertySet("ColumnWidth", 12);

//-------------------

Вопрос. Как установить цвет ячеек ?

Rang = Sh.OlePropertyGet("Range", "A1:E1");
Rang.OlePropertyGet("Interior").OlePropertySet("ColorIndex",4);

//-------------------

Вопрос. Как задать количество листов в книге ?

// Определяем количество листов в книге — 1
App.OlePropertySet("SheetsInNewWorkbook", 1);

//-------------------

Вопрос. Как дать название листу ?

// Даем название нашему листу "Наш лист итогов"
Sh = App.OlePropertyGet("Worksheets").OlePropertyGet("Item", 1);
Sh.OlePropertySet("Name", "Наш лист итогов");

//-------------------

Вопрос. Как сохранить получившийся документ ?

// Не спрашивать о замене файла, если он уже есть
App.OlePropertySet("DisplayAlerts", false);

// Сохраняем файл как "Firm.xls"
App.OlePropertyGet("WorkSheets",1).OleProcedure("SaveAs","Firm.xls");

//--------------------

Вопрос. Как установить настройки при печати ?

// Левое и правое поля отступа для печати
Sh.OlePropertyGet("PageSetup").OlePropertySet("LeftMargin", 80);
Sh.OlePropertyGet("PageSetup").OlePropertySet("RightMargin",20);

//--------------------

Вопрос. Как распечатать получившийся документ ?

App.OlePropertyGet("WorkBooks",1).OleProcedure("PrintOut");

//--------------------

Вопрос. Как закрыть документ Excel ?

try{
App.OlePropertyGet("WorkBooks",1).OleProcedure("Close");
}catch(...){
ShowMessage("Не забудьте сами закрыть Excel.");
}
// закрыть сам Excel
App.OleProcedure("Quit");

//-----------------------------
Посмотреть как все это работает и другие возможности
для C++Builder 6 полный проект можно скачать и посмотреть в работе здесь (15 Кб).

Многие спрашивают — как ускорить вывод в Excel больших массивов данных,
слишком медленно все работает.
Наиболее идеальный вариант — воспользоваться компонентами XLSReadWrite2 или аналогичными.
Также, в проекте есть пример, как можно немного ускорить такой вывод,
для этого при выводе данных можно не выводить данные последовательно в каждую ячейку
в цикле, а лучше сформировать вариантный массив, и выполнить присвоение области
(Range)
этого массива, только после этого делая Excel видимым.
Также более быстрая работа происходит при использовании библиотеки типов.

Все замечания и предложения и добавления: support@cbuilder.ru
Если Вы используете Excel или Word в работе с C++Builder,
присылайте примеры, проекты и интересные решения нам,
а также если у вас остались вопросы — спрашивайте.

В следующем уроке:

Для облегчения вывода данных в Excel можно использовать шаблоны.
Мы рассмотрим работу с шаблонами (.xlt) и использование макросов.