Сегодня мы рассмотрим один из наиболее интересных, на мой взгляд, моментов работы с 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:
Ну, и наконец, для того, чтобы представить этот же график в объемном виде, воспользуемся одним из многочисленных свойств объекта Chart — ChartType:
Chart.ChartType:=xl3DLine;
в итоге получим следующий вид диаграммы:
На сегодня все :) В следующий раз займемся свойствами объекта Chart, научимся строить различные типы диаграмм и изменять область построения диаграммы. А пока можете поэкспериментировать с параметрами у ChartWizard и посмотреть какие ещё виды диаграмм Excel Вы сможете построить в Delphi.
Книжная полка
![]() |
Описание Описаны общие подходы к программированию приложений MS Office. Даны программные методы реализации функций MS Excel, MS Word, MS Access и MS Outlook в среде Delphi.
|
![]() |



Спасибо за статью. Доходчиво, понятно… но! — данная тема, в принципе, широко рассмотрена в Интернете…
А вот тема намного интереснее: как «добраться» до диаграммы Excel внедрённой в документ Word и работать с ней? Вот это действительно нетривиально… Надеюсь когда-нибудь увидеть у Вас такую статью! :)
Действительно задачка не из стандартных :) Даже никогда о таком не задумывался. Дело в том, что я сейчас очень плотно занимаюсь работой с Excel, т.к. возникла острая необходимость по работе. Думаю, что Word тоже рассмотрю в блоге, но немного позже…А задачку попробую порешать на досуге. Спасибо за идею :)
Ну во, общий ход мыслей рассмотрел, небольшой примерчик привел :)
Статья хорошая. Но некоторые моменты не понял
объясните теперь мне, что может быть проще редактирования таблицы эксель внедренной в ворд, нубы?
ТоварищЪ пепелаЦо, Вы либо беспросветно слеп, либо настолько же беспросветно нуб :) Что собственно не меняет ситуации. Специально для вас привожу алгоритм чтения. В русском языке текст читается сверху вниз и слева на право. Понимаете? Теперь внимательно вчитайтесь в большие буквы вверху страницы — там написано Диаграммы Excel в Delphi. На мысль не наводит? Delphi, язык программирования, программа, работа с OLE. Знакомые слова? Если нет то лес там —> Если всё-таки так случилось, что одно из словосочетаний знакомо опять включите головной мозг (голова — это то, что в вашем теле торчит сверху, округлая обычно такая штука) и подумайте очень ли… Подробнее »
Выдает ошибку «Член группы не найден» ошибку выдает на строку
Chart:=MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects[MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Count];
Забить на Count.
Chart легко получить в момент его создания.
Chart := MyExcel.ActiveWorkBook.ActiveSheet.ChartObjects.Add(...).Chart;
Так это ошибка от OLE-сервера. Тут не Delphi, а состав документа надо смотреть.
у меня та же проблема «Член группы не найден» что и у igor`. не подскажите как решить проблему? офис 2007
Vlad, столкнулся с проблемой, как поменять толщину построенной линии? (Программа должна строить графики. Строит но линии толстые) Изменить параметры маркера могу.
Делаю это вот так
var
Aseries: Series;
…
Begin
ASeries := Chart1.SeriesCollection(Index, 0) as Series;
Aseries.MarkerBackgroundColorIndex:=2;
Aseries.MarkerForegroundColorIndex:=1;
Aseries.MarkerSize:=4;
….
Думаю, что изменение толщины должно тоже происходить похоже
Mark, я с компонентами для офиса никогда и не работал =) Поэтому сказать какое свойство отвечает за толщину линии диаграммы не могу. Но зато могу посмотреть Help для разработчиков в самом Excel и могу сказать, что судя по хэлпу за внешний вид диаграммы могут отвечать такие свойства: Type, MarkerSize и, наверное, Format, но это свойство только для чтения. ПРо толщину линии диаграммы что-то ничего и нет..
[…] одной из статей, посвященных работе с Excel в Delphi читатель с ником Kanti […]
Если
DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.UsedRange;то выдается ошибка «несовпадение типов.
Если
DataRange:=MyExcel.ActiveWorkBook.ActiveSheet.Range['A0:B10'];то «OLE error 800A03EC»
Обгуглил весь рунет,что делать не пойму…
Vasilich, DataRange какого типа у вас?
OLEVariant, как и в статье
Смотрел http://msdn.microsoft.com/en-us/library/office/ff838804%28v=office.15%29.aspx , там Source — Optional, Variant.
Если не передавать Source, то просто создает поле диаграммы (пустой прямоугольник).
Может, версия офиса не та, но в любом случае, не знаю, в чем дело…
Единственное, чем могу помочь, не имея перед глазами исходного кода с ошибками — это привести кусок кода из работающего приложения, которое читает большую таблицу на 40+ тысяч ячеек:
ExcelServer.WorkBooks.Open(FFileName);// получаем активный лист
WorkSheet := ExcelServer.ActiveWorkbook.ActiveSheet;
// определяем количество строк и столбцов таблицы
Rows := WorkSheet.UsedRange.Rows.Count;
Cols := WorkSheet.UsedRange.Columns.Count;
// считываем данные всего диапазона
FData := WorkSheet.UsedRange.Value;
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;
От всего вызова оставил
myChart.ChartWizard(MyExcel.WorkBooks[1].Worksheets[1].Range['A1:B1']);и заработало
это все конечно хорошо… но когда я пишу программу и у меня получаются числа например 5,76789Е-5 в ексель переносится значение 5,76789Е+9 как решить проблему???
Я только начал разбираться с программированием в Делфи, поэтому не ясно понимаю задачу зачем строить график в ексель из делфи, когда в ексель есть хороший визуальный графический редактор? И нужно только перенести данные в ексель и все.
Пример: вам необходимо, чтобы программа формировала отчёт в Excel и в отчёте должен быть график и таблица с данными. Как вы поступите? Сформируете программно таблицу на листе Excel, а потом скажете пользователю «А ещё в Excel есть хороший визуальный редактор — перенесите в Excel данные и всё»? По-моему, не серьезно :)