уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Сегодня мы рассмотрим один из наиболее интересных, на мой взгляд, моментов работы с Excel в Delphiпостроение диаграмм.

Забегая немного вперед, скажу, что есть несколько способов добавления диаграммы в рабочую книгу Excel.  Чтобы все статьи по вопросам автоматизации Excel в блоге были как-то логически связаны, я решил сегодня рассмотреть способ добавления диаграммы через объект ChartObjects, с которым мы встречались, когда разбирали методы объекта WorkSheet.

План статьи:

Итак, поставим перед собой цель — построить простой линейный график на основании данных таблицы (StringGrid) нашего приложения. При этом, чтобы продолжить предыдущую тему, постараемся скопировать таблицу на лист один-к-одному.

1. Копируем данные из таблицы и оформление StringGrid.

Для копирования данных из таблицы на лист Excel воспользуемся простейшей процедурой, которую мы уже с Вами рассматривали. Для наглядности, приведу листинг процедуры ещё раз:

procedure WriteTable(FirstCol, FirstRow:integer; Grid: TStringGrid);
var col,row:integer;
begin
  try
    for col := 0 to Grid.ColCount - 1 do
      for row := 0 to Grid.RowCount - 1 do
        MyExcel.ActiveWorkBook.ActiveSheet.Cells[FirstRow+row, FirstCol+col]:=Grid.Cells[col, row];
  except
    raise Exception.Create('Запись таблицы завершилась ошибкой')
  end;
end;

Теперь начнем копировать оформление. Во-первых, необходимо определить свойство BorderStyle у StringGrid — оно может быть либо bsSingle либо bsNone. В первом случае внешние границы таблицы будут выделяться. Отсюда следует, что и наша таблица в Excel должна иметь окантовку. Делается это просто:

...
 
if Grid.BorderStyle=bsSingle then
begin
  //отрисовываем внешние границы сплошной линией
  Range1.Borders[xlEdgeBottom].LineStyle:=xlContinuous;
  Range1.Borders[xlEdgeTop].LineStyle:=xlContinuous;
  Range1.Borders[xlEdgeLeft].LineStyle:=xlContinuous;
  Range1.Borders[xlEdgeRight].LineStyle:=xlContinuous;
end;
 
...

Во-вторых, StringGrid может быть с отрисованными внутренними линиями и без них. За отрисовку внутренних линий отвечают два параметра из свойства Options у StringGrid: goFixedVertLine (прорисовка вертикальных линий в ) и goFixedHorzLine (прорисовка горизонтальных линий в StringGrid).

Проверяем наш StringGrid и, в случае необходимости, прорисовываем внутренние границы ячеек:

if goFixedVertLine in Grid.Options then
  Range1.Borders[xlInsideVertical].LineStyle:=xlSolid;
if goFixedHorzLine in Grid.Options then
  Range1.Borders[xlInsideHorizontal].LineStyle:=xlContinuous;

А теперь самое интересное — определение цветов StringGrid и перенос их в таблицу Excel.  Для того, чтобы перевести цвет в Delphi в цвет, приемлемый для Excel, напишем небольшую подпрограмму:

R := GetRValue(ColorToRGB(Color));
G := GetGValue(ColorToRGB(Color));
B := GetBValue(ColorToRGB(Color));

где Color — это любой из цветов в Delphi, например clRed или clBtnFace. В итоге мы получим три составляющих для RGB, который допускается использовать при заливке ячеек в Excel.

Теперь можно копировать цвета фиксированных ячеек StringGrid:

Cell1:=MyExcel.ActiveWorkBook.ActiveSheet.Cells[FirstRow, FirstCol];
Cell2:=MyExcel.ActiveWorkBook.ActiveSheet.Cells[FirstRow+Grid.RowCount-1, FirstCol+Grid.ColCount-1];
//выделяем занятую таблицей область листа
Range1:=MyExcel.ActiveWorkBook.ActiveSheet.Range[Cell1, Cell2];
 
if Grid.FixedCols>0 then //есть фиксированные колонки
for I:=1 to Grid.FixedCols do
Range1.Columns[i].Interior.Color:=RGB(r,g,b);
if Grid.FixedRows>0 then //есть фиксированные строки
for I:=1 to Grid.FixedRows do
Range1.Rows[i].Interior.Color:=RGB(r,g,b);

Таким образом мы скопировали наш StringGrid на лист Excel. Конечно, здесь есть свои недостатки, например StringGrid может быть раскрашен как новогодняя ёлка или иметь совершенно иное оформление, чем стандартное и тогда, следуя вышеперечисленным операциям Вы не добьетесь копирования оформления один-к-одному. Но, при небольшом дополнении исходного кода этого можно легко добиться — суть вопроса остается той же, как и набор операций работы Delphi с Excel.

2. Добавление и редактирование диаграммы Excel

Теперь, имея в своем распоряжении данные, можно приступать к построению диаграммы Excel с помощью Delphi.

Для того, чтобы добавить в коллекцию ChartObjects новый объект необходимо выполнить метод Add:

ChartObjects.Add(Left, Top, Width, Height)

где:

Left и Top — начальные координаты нового объекта (в пикселях), относительно левого верхнего угла ячейки A1 на листе или в левом верхнем углу графика.

Width и Height — соответственно ширина и высота новой диаграммы.

В результате выполнения метода в коллекцию ChartObjects добавляется новый объект. Пока никаких данных объект не использует. По сути в добавляется пустой холст диаграмм Excel.

Для того, чтобы построить диаграмму, необходимо:

  • получить ссылку на объект Chart из коллекции ChartObjects;
  • воспользоваться методом ChartWizard

Чтобы получить ссылку на вновь добавленный объект необходимо выполнить следующую операцию:

var Chart: OLEVariant;
 
ChartCount: integer;
 
begin
 
...
 
ChartCount:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Count;
 
Chart:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects[ChartCount].Chart;
 
...
 
end;

Метод ChartWizard содержит следующие параметры:

ChartWizard(Source, Gallery, Format, PlotBy, CategoryLabels, SeriesLabels, HasLegend, Title, CategoryTitle, ValueTitle, ExtraTitle)
Параметр Тип Описание
Source Variant диапазон, который содержит исходные данные для нового графика
Gallery integer (Enumerations xlChartType) — тип диаграммы. Для метода ChartWizard может принимать следующие значения: xlArea, xlBar, xlColumn, xlLine, xlPie, xlRadar, xlXYScatter, xlCombination, xl3DArea, xl3DBar, xl3DColumn, xl3DLine, xl3DPie, xl3DSurface, xlDoughnut, xlDefaultAutoFormat
Format integer (1..10) — может быть числом от 1 до 10, в зависимости от типов галереи. Если этот аргумент опущен, Microsoft Excel выбирает значение по умолчанию в зависимости от типа диаграммы и источника данных. Например Format = 5 для нашего случая заставит Excel прорисовать на диаграмме линии сетки.
PlotBy определяет каким образом данные располагаются в Source. Может принимать два значения xlColumns =  2 (данные расположены в столбцах)  xlRows = 1 (данные расположены в строках)
CategoryLabel integer определяет номер строки или столбца в пределах источника, содержащим метку категории. Допустимые значения от 0 (ноль) до предпоследнего номера столбца или строки источника
SeriesLabels integer определяет номер строки или столбца в пределах источника, содержащим метку набора данных
HasLegend boolean определяет будет ли на диаграмме Excel отражена легенда
Title string заголовок диаграммы Excel
CategoryTitle string подпись оси категорий
ValueTitle string подпись оси значений
ExtraTitle string дополнительная подпись оси при построении трехмерных графиков

Как и для любых других методов Excel, в Delphi допускается опускать некоторые параметры или отмечать их как EmptyParam.

Теперь построим наш график. Для этого я написал небольшую процедуру:

procedure AddLineChartFromTable(X, Y, Height, Width, Format: integer; Title, XLabel,YLabel: string; DataGrid: TStringGrid; DataPosition: byte; ChartType:integer);
var Chart: OLEVariant;
  DataRange: OLEVariant;
begin
//Вставляем данные из таблицы
  WriteTable(1, 1, DataGrid);
//выбираем данные для диаграммы
  DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.UsedRange;
//добавляем новую диаграмму на активный лист
  MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Add(x,y,width,height);
//выбираем последнюю добавленную диаграмму
  Chart:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects[MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Count];
  Chart.Chart.ChartWizard(Source:=DataRange,
  Gallery:=xlLine,
  Format:=Format,
  PlotBy:=DataPosition,
  CategoryLabels:=1,
  SeriesLabels:=1,
  HasLegend:=true,
  Title:=Title,
  CategoryTitle:=XLabel,
  ValueTitle:=YLabel);
end;

Как видите, все достаточно просто. Берется таблица StringGrid, данные из неё переносятся в Excel на активный лист и, затем, эти данные используются для построения графика. Причём первая ячейка таблицы используется для подписи рядов данных. В результате выполнения процедуры я получил следующую диаграмму Excel:

excel_diagramm
Ну, и наконец, для того, чтобы представить этот же график в объемном виде, воспользуемся одним из многочисленных свойств объекта Chart ChartType:

Chart.ChartType:=xl3DLine;

в итоге получим следующий вид диаграммы:

excel_diagramm_3D

На сегодня все :) В следующий раз займемся свойствами объекта Chart, научимся строить различные типы диаграмм и изменять область построения диаграммы. А пока можете поэкспериментировать с параметрами у ChartWizard  и посмотреть какие ещё виды диаграмм Excel Вы сможете построить в Delphi.

Предыдущая статья на тему работы с Excel в Delphi — «Excel в Delphi. Методы объекта WorkSheet (лист).«
Следующая статья на тему работы с Excel в Delphi — »Excel в Delphi. Работа с объектом Range (диапазон)«

Книжная полка

Автор: Юрий Магда
Название:Разработка приложений Microsoft Office 2007 в Delphi
Описание Описаны общие подходы к программированию приложений MS Office. Даны программные методы реализации функций MS Excel, MS Word, MS Access и MS Outlook в среде Delphi.
купить книгу delphi на ЛитРес

 

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
22 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Kanti
Kanti
11/09/2009 16:15

Спасибо за статью. Доходчиво, понятно… но! — данная тема, в принципе, широко рассмотрена в Интернете…
А вот тема намного интереснее: как «добраться» до диаграммы Excel внедрённой в документ Word и работать с ней? Вот это действительно нетривиально… Надеюсь когда-нибудь увидеть у Вас такую статью! :)
 

Фотограф Краснодар
Фотограф Краснодар
20/09/2009 04:56

Статья хорошая. Но некоторые моменты не понял

пепелаЦо
пепелаЦо
06/06/2010 16:31

объясните теперь мне, что может быть проще редактирования таблицы эксель внедренной в ворд, нубы?

igor`
igor`
25/05/2011 22:30

Выдает ошибку «Член группы не найден» ошибку выдает на строку
Chart:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects[MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Count];

Александр Калабухов
Ответить на  igor`

Забить на Count.
Chart легко получить в момент его создания.

Chart := MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Add(...).Chart;

Begeot
Begeot
15/10/2011 22:49

у меня та же проблема «Член группы не найден» что и у igor`. не подскажите как решить проблему? офис 2007

Mark
Mark
18/12/2011 23:10

Vlad, столкнулся с проблемой, как поменять толщину построенной линии? (Программа должна строить графики. Строит но линии толстые) Изменить параметры маркера могу.
Делаю это вот так
var
Aseries: Series;

Begin
ASeries := Chart1.SeriesCollection(Index, 0) as Series;
Aseries.MarkerBackgroundColorIndex:=2;
Aseries.MarkerForegroundColorIndex:=1;
Aseries.MarkerSize:=4;
….
Думаю, что изменение толщины должно тоже происходить похоже

trackback
Полная автоматизация. Редактируем объекты Excel, содержащиеся в документах Word. | Delphi в Internet
30/09/2013 20:17

[…] одной из статей, посвященных работе с Excel в Delphi читатель с ником Kanti […]

Vasilich
Vasilich
01/12/2014 01:30

Если DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.UsedRange;
то выдается ошибка «несовпадение типов.
Если DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.Range['A0:B10'];
то «OLE error 800A03EC»
Обгуглил весь рунет,что делать не пойму…

Vasilich
Vasilich
01/12/2014 05:36
Ответить на  Vlad

OLEVariant, как и в статье
Смотрел http://msdn.microsoft.com/en-us/library/office/ff838804%28v=office.15%29.aspx , там Source — Optional, Variant.
Если не передавать Source, то просто создает поле диаграммы (пустой прямоугольник).
Может, версия офиса не та, но в любом случае, не знаю, в чем дело…

Vasilich
Vasilich
01/12/2014 16:10
Ответить на  Vlad


procedure TForm14.Button1Click(Sender: TObject);
var
myChart: Variant;
ChartCount:integer;
DataRange: Variant;//и OLEVariant пробовал
begin

MyExcel := CreateOleObject('Excel.Application');
MyExcel.Workbooks.Add(xlWBATWorksheet);
MyExcel.Worksheets.Add;

WriteData(StringGrid1,1,'1111');

MyExcel.Workbooks[1].WorkSheets[1].Activate;

MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Add(50,50,200,200);

ChartCount:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Count;
myChart:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects(ChartCount).Chart;
//DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.UsedRange;// выдает "несовпадение типов"
DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.Range['A0:B10'];//а так выдаст "OLE error 800A03EC"

myChart.ChartWizard(
Source:=DataRange,
Gallery:=4,
Format:=1,
PlotBy:=1,
CategoryLabels:=1,
SeriesLabels:=1,
HasLegend:=false,
Title:='test',
CategoryTitle:='cat',
ValueTitle:='val',
ExtraTitle:=''
);

MyExcel.DisplayAlerts := False;
MyExcel.Visible:=True;

end;

Vasilich
Vasilich
01/12/2014 17:48
Ответить на  Vlad

От всего вызова оставил
myChart.ChartWizard(MyExcel.WorkBooks[1].Worksheets[1].Range['A1:B1']);
и заработало

миша
миша
15/12/2015 17:01

это все конечно хорошо… но когда я пишу программу и у меня получаются числа например 5,76789Е-5 в ексель переносится значение 5,76789Е+9 как решить проблему???

Александр
Александр
01/02/2017 09:40

Я только начал разбираться с программированием в Делфи, поэтому не ясно понимаю задачу зачем строить график в ексель из делфи, когда в ексель есть хороший визуальный графический редактор? И нужно только перенести данные в ексель и все.