Диаграммы excel на delphi

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

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

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

План статьи:

  • Копируем данные из таблицы и оформление StringGrid
  • Добавление и редактирование диаграммы Excel

Итак, поставим перед собой цель — построить простой линейный график на основании данных таблицы (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.

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

Название:Разработка приложений Microsoft Office 2007 в Delphi

Описание Описаны общие подходы к программированию приложений MS Office. Даны программные методы реализации функций MS Excel, MS Word, MS Access и MS Outlook в среде Delphi.

купить книгу delphi на ЛитРес

0
0
голоса

Рейтинг статьи

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

Поскольку этот вопрос перекликается с предыдущим в плане навыков программной работы с приложениями MSOffice (да и вообще с COM-объектами), попробую объяснить порядок составления своего Delphi-кода на основе VBA. Напоследок отложим непосредственно ответ на сам вопрос.

Во-первых, нужно представлять себе иерархию объектов MS Office-приложения. В Excel она несколько проще, чем в Word.

Основное:

- Application - глобальный объект, из него можно "достучаться" до чего угодно   
    - Workbooks - коллекция книг,
      (Workbook) - каждая из которых содержит
        - Worksheets - коллекцию рабочих листов
          (Worksheet) - на которых мы и размещаем информацию.
               - Cells - ячейки листа. Именно с ними и производится бОльшая часть работы - 
                         размещение данных, объединение/разделение, изменение шрифта и т.п.

Собственно, по большому счету все. Остальное запоминать не обязательно, потому что мощным помощником выступает сам Excel/Word, позволяя записывать все «ручные» действия пользователя в макросы.

Приступим. Первый этап — размещение данных на нужном листе. Здесь пользуемся приведенной ранее иерархией:

var
  Excel, Book, Sheet:OleVariant;
  i:Integer;
begin
  Excel:=CreateOleObject('Excel.Application');
  Excel.Visible:=True;
  Book:=Excel.Workbooks.Add;
  Sheet:=Book.Worksheets[1];
  for i := 1 to 5 do
    begin
      Sheet.Cells[i, 1].Formula:=i;
      Sheet.Cells[i, 2].Formula:=Sin(i);
    end;

Замечательно то, что большинство свойств принимает тип Variant, то есть — практически любые значения: строки, integer, Double и т.п.

Есть несколько способов задать значение ячейке: Formula, FormulaR1C1, Value, etc. Нужно понимать их различия и пользоваться необходимыми соответственно задаче. Чаще всего используются именно Formula и FormulaR1C1

Так же полезно понимать, что каждая ячейка на самом деле это объект Range, то есть представляет собой любое, произвольное количество ячеек и работа с несколькими ячейками из состава Range не отличается от работы с одной ячейкой, полученной через Cells.

Далее необходимо на лист добавить график. Мы не знаем, как это сделать, да и из-за однократности задачи помнить, где этот график находится в иерархии объектов — расточительно.

Заходим в меню «Вид», нажимаем «Макросы — Запись макроса» и нажимаем «ОК». Переходим на вкладку «Вставка» и добавляем простую гистограмму. Далее выбираем дипазон данных (я взял B1-B5), изменяем подписи (выбрал A1-A5) подтверждаем изменения и останавливаем запись макроса («Вид» — «Макросы» — «Остановить запись»). Теперь осталось войти внутрь макроса («Вид» — «Макросы» — «Макросы»-«Изменить»). Должен получиться примерно такой код VBA:

ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlColumnClustered
ActiveChart.SetSourceData Source:=Range("B1:B5")
ActiveChart.SeriesCollection(1).XValues = "=Лист1!$A$1:$A$5"

И вот тут нам понадобится справка, потому что дальше не все так тривиально. Разберем по строчкам:

ActiveSheet.Shapes.AddChart.Select — последний метод (Select) нас не интересует, поскольку он просто выделяет добавленную фигуру на листе. Для программной работы выделение объекта излишне. А вот AddChart добавляет объект Shape, а нам нужен объект Chart. VBA дальше идет по пути наименьшего сопротивления — использует свойство Application.ActiveChart (ActiveChart.ChartType = xlColumnClustered и т.п.). Но нам это не подходит, поскольку (повторюсь) при программной работе с Excel нежелательно использовать «активные элементы», нужно работать именно с тем, что мы добавили. Выясняем, что у объекта Shape есть свойство Chart, именно оно нам нужно. Соответственно, всю дальнейшую работу строим именно на этом, переводя код VBA в Delphi:

    Shape:=Sheet.Shapes.AddChart; // повторюсь - Select нам не нужен.
    // но при желании потом можно сделать Shape.Select
    Shape.Chart.ChartType := xlColumnClustered; // вместо ActiveChart - наш Shape.Chart
    Shape.Chart.SetSourceData(Source:=Sheet.Range['B1:B5']);
    Shape.Chart.SeriesCollection(1).XValues := Format('=%s!$A$1:$A$5', [Sheet.Name]);

Здесь следует обратить внимание, что мы избегаем называть возможно локализованное имя листа (оно может зависеть от языка Office, пользователь может его переименовать и т.п.). Поэтому берем реальное наименование из свойства Sheet.Name.

Вот и все. Полный получившийся код:

procedure TForm8.btn2Click(Sender: TObject);
var
  Excel, Book, Sheet, Shape:OleVariant;
  i:Integer;
begin
  Excel:=CreateOleObject('Excel.Application');
  Excel.Visible:=True;
  Book:=Excel.Workbooks.Add;
  Sheet:=Book.Worksheets[1];
  for i := 1 to 5 do
    begin
      Sheet.Cells[i, 1].FormulaR1C1:=i;
      Sheet.Cells[i, 2].FormulaR1C1:=Sin(i);
    end;

  Shape:=Sheet.Shapes.AddChart;
  Shape.Chart.ChartType := xlColumnClustered;
  Shape.Chart.SetSourceData(Source:=Sheet.Range['B1:B5']);
  Shape.Chart.SeriesCollection(1).XValues := Format('=%s!$A$1:$A$5', [Sheet.Name]);
end;

В заключение замечание по поводу используемых констант xlColumnClustered и подобных: можно подключить в uses модуль Excel2010, ExcelXP или другой, имеющийся в вашей версии Delphi. Но можно и подставлять значения констант вручную, через поиск в Google (лучше брать ссылки на первоисточник — microsoft). Например, поиск по xlColumnClustered первой же ссылкой дает перечень констант XlChartType Enumeration

 
agisland ©
 
(2005-04-26 01:23)
[0]

Как нарисовать из делфи диаграмму в excel

var
Excel,Book,List,Value,Chart:Variant;
LSID:Integer;
begin
try
Excel:=GetActiveOleObject(«Excel.Application»);
except
Excel := CreateOleObject(«Excel.Application»);
end;
LSID:=GetUserDefaultLCID;
Book:=Excel.WorkBooks.Add();
List:=Book.WorkSheets.Add();
а дальше…  Допустим диаграмма нужна по ячейкам a1:a5, b1:b5


 
Ольга
 
(2005-04-26 07:48)
[1]

//  создание диаграммы
   Book.Charts.Add;
//  название диаграммы
   Book.ActiveChart.HasTitle := True;
   Book.ActiveChart.ChartTitle.Characters.Text := Title;
//  тип диаграммы
   Book.ActiveChart.ChartType:= xlLineStacked;
// источник данных  
   Range1:= Sheet.Range[Cells[r1, c1], Cells[r1, c2]];
   Range2:= Sheet.Range[Cells[r2, c3], Cells[r2, c4]];
   Book.ActiveChart.SetSourceData(Range1, PlotBy);
   Book.ActiveChart.SeriesCollection(1).XValues := Range2;

       PlotBy:= xlColumns;     //  по колонкам
   PlotBy:= xlRows;          //  по рядам

//  расположение диаграммы в книге
   Book.ActiveChart.Location(xlLocationAsNewSheet, NameSheet);  //   на  новом листе
   Book.ActiveChart.Location(xlLocationAsObject, NameSheet);       //  на  листе NameSheet
// ось абсцисс (значений)
  Book.ActiveChart.HasAxis(xlValue, xlPrimary) := True;
// отображение основных линий на диаграмме
  Book.ActiveChart.Axes(xlValue).HasMajorGridlines := True;
// отображение промежуточных линий на диаграмме
  Book.ActiveChart.Axes(xlValue).HasMinorGridlines := False;
//  заголовок оси
  Book.ActiveChart.Axes(xlValue).HasTitle := True;
  Book.ActiveChart.Axes(xlValue).AxisTitle.Characters.Text := TitleY;
   //  ось ординат (категорий)
   Book.ActiveChart.HasAxis(xlCategory, xlPrimary) := True;
   // отображение основных линий на диаграмме
   Book.ActiveChart.Axes(xlCategory).HasMajorGridlines := True;      
   // отображение промежуточных линий на диаграмме
   Book.ActiveChart.Axes(xlCategory).HasMinorGridlines := False;
//  заголовок оси
   Book.ActiveChart.Axes(xlCategory, xlPrimary).HasTitle := True;
   Book.ActiveChart.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text := TitleX;

// добавить новую серию на диаграмму
  Range3:= Sheet.Range[Cells[r3, c1], Cells[r3, c4]];
  NewSeries:=Book.ActiveChart.SeriesCollection.Add(Range3);     //   диапазон значений
  Book.ActiveChart.SeriesCollection[1].XValues:= Range2;            //  диапазон категорий
  NewSeries:=Book.ActiveChart.SeriesCollection[Book.ActiveChart.SeriesCollection.Count];
  NewSeries.Name:=Caption;        // заголовок серии
  NewSeries.Border.Color:=SeriesColor;      //  цвет
  NewSeries.MarkerBackgroundColor:=SeriesColor;
  NewSeries.MarkerForegroundColor:=SeriesColor;
  NewSeries.Smooth:= True;     // сглаживание графика


 
КиТаЯц ©
 
(2005-05-14 12:03)
[2]

>Ольга   (26.04.05 07:48) [1]

Круто!

Может кто знает как передать в Excel готовую tDBChart???
Ну, типа as image…


 
andrey__
 
(2005-05-16 16:12)
[3]

>agisland ©   (26.04.05 01:23)  

Если у тебя получилось или у кого-то ещё то приведите полный пример. А то у меня на строке:
  Book.ActiveChart.HasTitle := True;
пишет «Нельзя установить свойство HasTitle класса Chart.»


 
HeadLess
 
(2005-05-17 14:35)
[4]

А не проще ли подготовить макросы постороения диаграммы, а потом их просто вызывать из программы строчкой типа :

var
Excel,Book,List,Value,Chart:Variant;


Excel.run(«My_Chart_Macro»);


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
uses
  ... ComObj, ActiveX;
//...
Procedure TCalcOfDefl.RWExcel;
var
  SIR: boolean;
  APID: String;
  App, Ch, Range: Variant;
  i, j: integer;
begin
  // Указать программный идентификатор приложения-сервера
  APID := 'Excel.Application';
  SIR := False;
  // Создать один экземпляр сервера
  App := CreateOleObject(APID);
  SIR := True;
  // показать окно приложения на экране
  App.Visible := True;
  // Редактируем документ
  App.WorkBooks.Add;
 
// ...
 
// данные для диаграмм:
  Range := App.WorkBooks[1].WorkSheets[1].Range['D:D'];
  // добавляем новыю диаграмму на активный лист
  App.ActiveWorkBook.ActiveSheet.ChartObjects.Add(100, 10, 500, 400);
  // выбираем последнюю добавленную диаграмму
  Ch := App.WorkBooks[1].WorkSheets[1].ChartObjects
    [App.WorkBooks[1].WorkSheets[1].ChartObjects.Count];
 
  Ch.Chart.ChartWizard(Source := Range, Gallery := xlLine{Вот здесь всегда ошибка, если оставить
так, то  E2003 Undeclared identifier: 'xlLine'; если взять в любые скобки ругается, если апострофы
поставить:'xlLine' то компилируется но выдает ошибку Method 'ChartWizard' not supported by
automation object; если использовать любое значение: xlArea, xlBar, xlColumn, xlLine, xlPie,
xlRadar, xlXYScatter, xlCombination, xl3DArea, xl3DBar, xl3DColumn, xl3DLine, xl3DPie, xl3DSurface,
xlDoughnut, xlDefaultAutoFormat всеравно всегда ошибка}, Format := 5,
    PlotBy := 2, CategoryLabels := 1, SeriesLabels := 1, HasLegend := False,
    Title := 'График зависимости прогиба от угла', CategoryTitle := 'f',
    ValueTitle := 'φ');
 
  if not SIR then
    App.Quit;
  App := Unassigned;
end;

Like this post? Please share to your friends:
  • Диаграммы excel диаграмма одной строкой
  • Диаграмму создавать для excel
  • Диаграмму на весь лист в word
  • Диаграмме excel скрыть данные
  • Диаграмма ямазуми в excel