Chart, ChartObject, Shape, Picture
Пожалуй, самым популярным использованием Excel является применение его для построения диаграмм (Chart). Это заметно по большому количеству примеров, статей и различных FAQ в Интернете по этой теме.
Chart Object
ChartObject Object Model
Shapes Collection Object Model
Chart Class
Как добавить Chart в отдельный лист книги? Как внедрить Chart в лист книги?
Chart может существовать как отдельный лист книги, так и как внедренный в лист объект ChartObject. Принципиальная разница только в том, ChartObject — это уже объект Shape, содержащий в себе Chart.
Чтобы добавить Chart как отдельный лист книги, нужно воспользоваться методом Add коллекции Sheets.
var oChart: _Chart; oSheet: _Worksheet; ... oChart := XL.Sheets.Add(EmptyParam, oSheet, 1, xlChart, lcid) as _Chart;
Внимание! Не пытайтесь добавить Chart, используя коллекцию Charts — вы получите OLE исключение, т.к. Charts — это коллекция-подмножество Sheets, содержащее ссылки на листы Chart.
Чтоб добавить Chart, как внедренный в лист объект, можно воспользоваться методом Add коллекции листа ChartObjects (здесь существует возможность сразу задать координаты и размеры внедряемого Chart, как будто это объект Shape).
oChart := (oSheet.ChartObjects(EmptyParam, lcid) as ChartObjects).Add( oSheet.Range['B9', EmptyParam].Left, oSheet.Range['B9', EmptyParam].Top + 8, oSheet.Range['I9', EmptyParam].Left - oSheet.Range['B9', EmptyParam].Left, oSheet.Range['B30', EmptyParam].Top - oSheet.Range['B9', EmptyParam].Top).Chart as _Chart;
Внимание! При преобразовании Chart в ChartObject (или наоборот) лист Chart (или объект ChartObject) исчезнет (будет утерян), поэтому необходимо всегда получать ссылку на новый объект Chart, возвращаемый функцией Locate.
Charts
Location Method
How to: Add Chart Controls to Worksheets
Как добавить картинке гиперссылку?
Смотрите " Как добавить URL? Как сделать гиперссылку для рисунка?"
Hyperlink Property
Как добавить новый ряд (Series) в Chart?
with (oChart.SeriesCollection(EmptyParam, lcid) as SeriesCollection).NewSeries do
begin
Values := oSheet.Range['H2', 'H6']; Name := '="Q4"'; end;
Также можно воспользоваться методом Extend, который "расширяет" область данных диаграммы.
NewSeries Method
Extend Method
Как добавить в лист объект Shape и записать в него текст?
Объект Shape — это контейнер для многих других объектов, таких как TextBox, PolyLine, ChartObject и др. Также и свойство Comment объекта Range, по возможностям и набору свойств, можно отнести к Shape. Все объекты-наследники Shape содержатся в коллекции Shapes листа.
Внимание! Не забудьте явно указать namespace при присвоении типа объекта Shape, т.к. возможен конфликт с объектом Shape namespace Office:
var
AShape: ExcelXP.Shape; // или
AShape: Excel2000.Shape;
Примеры:
// Rectangle
AShape := ASheet.Shapes.AddShape( msoShapeRectangle, ASheet.Range['A1', EmptyParam].Width / 2, ASheet.Range['A1', EmptyParam].Height, ASheet.Range['D1', EmptyParam].Left - ASheet.Range['A1', EmptyParam].Width / 2, ASheet.Range['D9', EmptyParam].Top - ASheet.Range['A1', EmptyParam].Height ); AShape.TextFrame.Characters(EmptyParam, EmptyParam).Text := 'Rectangle';
// Oval
AShape := ASheet.Shapes.AddShape( msoShapeOval, ASheet.Range['E1', EmptyParam].Left, ASheet.Range['F2', EmptyParam].Top, ASheet.Range['I1', EmptyParam].Left - ASheet.Range['E1', EmptyParam].Left, ASheet.Range['F12', EmptyParam].Top - ASheet.Range['F2', EmptyParam].Top ); AShape.TextFrame.Characters(EmptyParam, EmptyParam).Text := 'Oval'; AShape.TextFrame.HorizontalAlignment := xlCenter; AShape.TextFrame.VerticalAlignment := xlCenter;
// TextBox
AShape := ASheet.Shapes.AddShape( msoTextOrientationVerticalFarEast, ASheet.Range['B1', EmptyParam].Left, ASheet.Range['B11', EmptyParam].Top, ASheet.Range['E1', EmptyParam].Left - ASheet.Range['B1', EmptyParam].Left, ASheet.Range['B18', EmptyParam].Top - ASheet.Range['B10', EmptyParam].Top ); AShape.TextFrame.Characters(EmptyParam, EmptyParam).Text := 'Rhombus'; AShape.TextFrame.HorizontalAlignment := xlCenter; AShape.TextFrame.VerticalAlignment := xlCenter;
// Hedgehog
AShape := ASheet.Shapes.AddShape( msoShape32pointStar, ASheet.Range['D1', EmptyParam].Left, ASheet.Range['E19', EmptyParam].Top, ASheet.Range['G1', EmptyParam].Left - ASheet.Range['D1', EmptyParam].Left, ASheet.Range['E30', EmptyParam].Top - ASheet.Range['E19', EmptyParam].Top ); AShape.TextFrame.Characters(EmptyParam, EmptyParam).Text := 'Hedgehog'; AShape.TextFrame.HorizontalAlignment := xlCenter; AShape.TextFrame.VerticalAlignment := xlCenter; AShape.TextFrame.Orientation := msoTextOrientationUpward; // 2
Shapes Collection
Shapes
Shape Object
TextFrame Property
ShapeRange Collection
Как изменить цвет линии и фона Shape?
Delphi:
(AShape.Fill as FillFormat).ForeColor.SchemeColor := 41; (AShape.Line as LineFormat).ForeColor.SchemeColor := 62;
C#:
AShape.Fill.ForeColor.SchemeColor = 43; AShape.Line.ForeColor.SchemeColor = 53;
Fill Property
Line Property
Как изменить цвет серии в Chart?
with (oChart.SeriesCollection(1, lcid) as Series).Interior do begin
Color := RGB(0, 0, 255); Pattern := xlSolid; end;
Interior Property
Border Property
Fill Property
Как изменить яркость или контрастность картинки?
(AShape.PictureFormat as PictureFormat).Brightness := 0.25; // 25% яркости
(AShape.PictureFormat as PictureFormat).Contrast := 0.75; // 75% контрастность
PictureFormat Property
Как изменить размер картинки и вписать ее в размер определенной области ячеек?
Если пытаться изменять размер картинки, то она, по умолчанию, будет менять размер пропорционально. Такую особенность задает свойство LockAspectRatio объекта Shape. Если установить LockAspectRatio равным msoFalse, то картинка будет менять размеры непропорционально.
// Картинка будет вписана в область D12:J18 с сохранением пропорций
AShape.Width := ASheet.Range['K12', EmptyParam].Left - ASheet.Range['D12', EmptyParam].Left; AShape.Height := ASheet.Range['D19', EmptyParam].Top - ASheet.Range['D12', EmptyParam].Top;
// Картинка будет вписана во всю область D12:J18 без сохранения пропорций
AShape.LockAspectRatio := msoFalse; AShape.Width := ASheet.Range['K12', EmptyParam].Left - ASheet.Range['D12', EmptyParam].Left; AShape.Height := ASheet.Range['D19', EmptyParam].Top - ASheet.Range['D12', EmptyParam].Top;
LockAspectRatio Property
Как изменять заголовки Chart и его осей?
Например, так:
// Заголовок диаграммы
HasTitle[lcid] := True; ChartTitle[lcid].Characters[EmptyParam, EmptyParam].Text := 'Sales';
// Ось Х - заголовка нет
(Axes(xlCategory, xlPrimary, lcid) as Axis).HasTitle := False;
// Оси Y - заголовок "у.е."
(Axes(xlValue, xlPrimary, lcid) as Axis).HasTitle := True; (Axes(xlValue, xlPrimary, lcid) as Axis).AxisTitle. Characters[EmptyParam, EmptyParam].Text := 'у.е.'; (Axes(xlValue, xlPrimary, lcid) as Axis).AxisTitle.Orientation := xlUpward;
Axes Method
Как назначить подписи значениям оси Х (ось категорий) из области ячеек?
Для отображения подписей оси X предназначено свойство XValues объекта Series.
// значения по категориям
(oChart.SeriesCollection(1, lcid) as Series).XValues := oSheet.Range['C2:C6', EmptyParam];
XValues Property
Как получить доступ к ряду (series) Chart?
Например, в цикле присвоим всем сериям новое имя.
for i := 1 to (oChart.SeriesCollection(EmptyParam, lcid) as SeriesCollection).Count do
(oChart.SeriesCollection(i, lcid) as Series).Name := Format('="Q%d"', [i]);
Обратиться к серии (ряду) можно не только по индексу, но и по имени, например
(oChart.SeriesCollection('Q1', lcid) as Series).Interior.Color := RGB(0, 0, 255);
SeriesCollection Collection Object
Series Object
Как сгруппировать несколько объектов Shape на листе?
// Сгруппируем все объекты Shapes на листе
AShape := (ASheet.DrawingObjects(EmptyParam, lcid) as DrawingObjects).ShapeRange.Group; AShape.Name := 'MyGroup1';
// группировка через вариантный массив
V := VarArrayCreate([1, 2], varVariant); // !!!
// сгруппируем 2-й и 4-й Shape
V[1] := 2; V[2] := 4; AShape := ASheet.Shapes.Range[V].Group; AShape.Name := 'MyGroup2';
// Если заранее известно, какие Shape будут сгруппированы,
// то можно и так
AShape := ASheet.Shapes.Range[VarArrayOf([2, 4])].Group; AShape.Name := 'MyGroup3';
// Теперь, на закуску, через Selection
// Выберем 2-й, 3-й и 4-й Shape
ASheet.Shapes.Item(2).Select(True); ASheet.Shapes.Item(3).Select(False); ASheet.Shapes.Item(4).Select(False); // сгруппируем выделенные Shape
AShape := (XL.Selection[lcid] as DrawingObjects).ShapeRange.Group; AShape.Name := 'MyGroup4';
// Разгруппировать
AShape.Ungroup;
Заметьте, что после того, как объекты Shape были сгруппированы, их количество на листе (Shapes.Count) уменьшится. После "группировки" можно обратиться к отдельному Shape, включенному в группу, используя коллекцию GroupItems объекта Shape, полученного в результате группировки.
Group Method
Regroup Method
Ungroup Method
GroupItems Property
Как убрать легенду из Chart?
Легенду можно просто "спрятать", указав, что ее "нет". Также вы можете изменять любые атрибуты легенды (Font, Interior и другие), получив доступ к свойству Legend объекта Chart.
oChart.HasLegend[lcid] := False;
Legend Object
HasLegend
Как указать источник данных объекту Chart?
Для указания источника данных, можно воспользоваться методом SetSourceData объекта Chart или (мне кажется, что это даже удобнее) методом ChartWizard.
var oRng: ExcelRange; ... oRng := oSheet.Range['E2:H6', EmptyParam];
// Указываем источник данных методом SetSourceData
with oChart do begin
SetSourceData(oRng, xlColumns); // источник данных и PlotBy
ChartType := xl3dColumn; // тип диаграммы
end;
// Указываем источник методом ChartWizard, в котором можно сразу
// задать многие параметры диаграммы
oChart.ChartWizard( oRng, // Source: OleVariant;
xl3dColumn, // Gallery: OleVariant;
EmptyParam, // Format: OleVariant;
// данные серий - в колонках
xlColumns, // PlotBy: OleVariant;
EmptyParam, // CategoryLabels: OleVariant;
EmptyParam, // SeriesLabels: OleVariant;
True, // HasLegend: OleVariant;
'Sales', // Title: OleVariant;
EmptyParam, // CategoryTitle: OleVariant;
'у.е.', // ValueTitle: OleVariant;
EmptyParam, // ExtraTitle: OleVariant;
lcid);
SetSourceData Method
ChartWizard Method
Как вставить в лист картинку?
var
AShape: Excel_TLB.Shape; APic: Picture; // Excel_TLB
Img: TImage; // ExtCtrls
MyFormat: Word; // для копирования картинки в БО
AData: THandle; // для копирования картинки в БО
APalette: HPALETTE; // для копирования картинки в БО
... // Первый метод
// Вставляем картинку из файла с "нулевым" размером в
// позицию ячейки B2. "Нулевой" размер потому, что
// мы не знаем заранее размера картинки
with ASheet.Range['B2', EmptyParam] do
AShape := ASheet.Shapes.AddPicture(ExpandFileName('common.gif'), msoFalse, msoTrue, Left, Top, 0, 0); // После вставки получаем ссылку на объект Shape, содержащий
// нашу картинку. "Реанимируем" оригинальный размер картинки
AShape.ScaleHeight(1, msoTrue, EmptyParam); AShape.ScaleWidth(1, msoTrue, EmptyParam); AShape.Name := 'Picture1';
// Второй метод - вставляем в выделенную ячейку
ASheet.Range['C7', EmptyParam].Select;
APic := (ASheet.Pictures(EmptyParam, lcid) as Pictures).Insert(ExpandFileName('common.gif'), EmptyParam); APic.Name := 'Picture2';
// Третий метод - вставка через буфер обмена
// Загрузим картинку с диска в TImage
Img.Picture.LoadFromFile(ExpandFileName('common.bmp')); MyFormat := CF_PICTURE; AData := Img.Picture.Bitmap.Handle; APalette := Img.Picture.Bitmap.Palette; // и помещаем в буфер обмена
Img.Picture.SaveToClipboardFormat(MyFormat, AData, APalette); Clipboard.SetAsHandle(MyFormat, AData); // из буфера обмена вставим в ячейку D12
ASheet.Paste(ASheet.Range['D12', EmptyParam], EmptyParam, lcid);
Все добавленные картинки будут включены в коллекцию Shapes листа.
AddPicture Method
Worksheet.Pictures Method
Paste Method
Creating Charts in Excel 2003 Using Visual Basic for Applications Code
How To Create Excel Chart w/OLE Automation from Visual Basic
Microsoft Excel Charting FAQs
Excel Charts and Graphs Help from Mr Excel
Excel Chart Tips
How to automate Microsoft Excel from Microsoft Visual C# .NET
How To Automate Excel from an HTML Web Page Using JScript
VBA Samples for Working with Excel 2003 Worksheets
XL97: How to Create a GIF File from a Microsoft Excel Chart
COM Tips & Tricks
Как подключить книгу Excel как базу данных, используя поставщика данных Jet OLE DB Provider?
Для подключения книги Excel как базы данных нужно воспользоваться Microsoft Jet OLE DB провайдером и указать в свойстве соединения Extended Properties=Excel 8.0.
Delphi:
const
ConStr = 'Provider=Microsoft.Jet.OLEDB.4.0;' + 'Data Source=%s;' + 'Extended Properties="Excel 8.0;HDR=Yes;";';
var
Conn: TADOConnection; ... Conn.ConnectionString := Format(ConStr, [ExpandFileName('DbDemos.xls')]); Conn.Open;
C#:
System.Data.OleDb.OleDbConnection oConn = new System.Data.OleDb.OleDbConnection(); oConn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Environment.CurrentDirectory + @"\DbDemos.xls;" + "Extended Properties=\"Excel 8.0;HDR=Yes;\";"; oConn.Open;
ADO Provider Properties and Settings
Connect to Excel with ADO
ExcelADO demonstrates how to use ADO to read and write data in Excel workbooks
HOW TO: Use Jet OLE DB Provider 4.0 to Connect to ISAM Databases
How To Transfer Data from ADO Data Source to Excel with ADO
OLE DB Tutorial (C# Programmer's Reference)
Как получить данные из ADODataSet?
Если у вас есть открытый RecordSet (свойство всех наследников TCustomADODataSet), то из него в любую ячейку листа можно получить данные. В примере данные из ADODataSet1 будут вставлены в область, начиная с ячейки A2.
Delphi:
ASheet := (XL.Sheets[1] as _Worksheet); ASheet.Range['A2', EmptyParam].CopyFromRecordset( ADODataSet1.Recordset, EmptyParam, EmptyParam );
C#:
ADODB._Recordset objRS = null; object objRecAff = null; ADODB.Connection objConn = new ADODB.Connection(); // Excel Excel.Worksheet oSheet = null; Excel.Range oRng = null; Excel.Application XL = new Excel.Application(); try { XL.Visible = true; objConn.Open("Provider=\"Microsoft.Jet.OLEDB.4.0\";Data Source=\"" + Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles) + "\\Borland Shared\\Data\\dbdemos.mdb\";Persist Security Info=False;", "", "", 0); objRS = (ADODB._Recordset) objConn.Execute("employee", out objRecAff, (int) ADODB.CommandTypeEnum.adCmdTable); XL.Workbooks.Add(Type.Missing); oSheet = (Excel.Worksheet) XL.ActiveSheet; oRng = oSheet.get_Range("A1", Type.Missing); for (int i = 0; i < objRS.Fields.Count; i++) { oRng.get_Offset(0, i).Value2 = objRS.Fields[i].Name; } oRng = oSheet.get_Range("A2", Type.Missing); oRng.CopyFromRecordset(objRS, Type.Missing, Type.Missing); oRng = oSheet.UsedRange.EntireColumn; oRng.AutoFit(); XL.ActiveWorkbook.Saved = true; } finally { objConn.Close(); objConn = null; objRS = null; objRecAff = null; oRng = null; oSheet = null; XL.UserControl = true; XL = null; }
Т.к. в ADO.NET не существует такого объекта как RecordSet, то в C# приходится подключаться к старому знакомому ADODB (не забудьте добавить в References проекта "Microsoft ActiveX Data Objects 2.8 Library" на вкладке "COM Imports").
How to transfer data to an Excel workbook by using Visual C# 2005 or Visual C# .NET
CopyFromRecordset Method
How To Transfer Data from an ADO Recordset to Excel with Automation
Range.CopyFromRecordset Method
Как получить данные из таблицы (листа) Excel SQL запросом?
Данные из листа Excel, подключенного через ADO, можно показать в DBGrid, добавлять, править, удалять строки. Используем подключение из предыдущего примера.
Delphi:
ADODataSet1.Connection := Conn;
ADODataSet1.CommandText := 'select * from [Лист1$]'#10 + 'where [HireDate] >= #01/01/1994#'; ADODataSet1.Open;
// Можно использовать именованную область ячеек, названную "MyRange"
ADODataSet1.CommandText := 'select * from MyRange'; ADODataSet1.Open;
// Возможно использовать указаную область ячеек
ADODataSet1.ParamCheck := False; // ОБЯЗАТЕЛЬНО, иначе exception!!!
ADODataSet1.CommandText := 'select * from [Лист1$A12:F42]';
C#:
System.Data.OleDb.OleDbCommand oCmd = new System.Data.OleDb.OleDbCommand(); System.Data.OleDb.OleDbDataAdapter oAdapt = new System.Data.OleDb.OleDbDataAdapter(); System.Data.DataSet oDS = new System.Data.DataSet("DbDemos"); oCmd.Connection = oConn; // Выборка данных из одной таблицы (листа) с именем "Employee" oCmd.CommandText = "select * from [Employee$]"; // Выборка данных из именованной области ячеек c именем "MyRange" oCmd.CommandText = "select * from MyRange"; // Выборка из заданной области ячеек oCmd.CommandText = "select * from [Employee$A10:F40]"; // Выборка из 3 связанных таблиц (листов) книги oCmd.CommandText = "SELECT O.OrderNo, O.SaleDate, O.PaymentMethod, O.ItemsTotal,\n" + "E.FirstName, E.LastName, C.Company\n" + "FROM [customer$] AS C\n" + " INNER JOIN ([employee$] AS E\n" + " INNER JOIN [orders$] AS O ON E.EmpNo = O.EmpNo)\n" + " ON C.CustNo = O.CustNo"; // Получам данные в DataSet посредством OleDbDataAdapter'а oAdapt.SelectCommand = oCmd; oAdapt.Fill(oDS, "Employee"); // Покажем данные в DataGrid'е dataGrid1.DataSource = oDS.Tables["Employee"];
Внимание! Если данные были получены в DataSet из именованной области ячеек, то, при попытке добавить новые строки, вы получите исключение "Cannot expand named range". Если данные были получены с указанием области ячеек, то новые записи будут добавляться после последней строки диапазона, но, если будет вызван метод Requey, эти новые строки не будут включены в DataSet.
Retrieve and Edit Excel Data with ADO
How to query and display excel data by using ASP.NET, ADO.NET, and Visual C# .NET
You receive error messages when you try to use ADO.NET OLEDbDataAdapter to modify an Excel workbook
How To Use ADO with Excel Data from Visual Basic or VBA
Как получить данные в Excel, используя QueryTable?
Delphi:
var
AQueryTbl: ExcelQueryTable; ... XL := StartExcel; try
ASheet := (XL.Sheets[1] as _Worksheet); R := ASheet.Range['A1', EmptyParam]; // начальная ячейка для данных
AQueryTbl := ASheet.QueryTables.Add( 'OLEDB;Provider=Microsoft.Jet.OLEDB.4.0;' + 'Data Source=' + ExpandFileName('DbDemos.xls') + ';' + 'Extended Properties="Excel 8.0;";', R, 'select * from [employee$]'
); AQueryTbl.RefreshStyle := xlInsertEntireRows; AQueryTbl.Refresh(False);
C#:
Excel.Worksheet oSheet = null; Excel.Range oRng = null; Excel.QueryTable oQT = null; Excel.Application XL = new Excel.Application(); try { XL.Visible = true; XL.Workbooks.Add(Type.Missing); oSheet = (Excel.Worksheet) XL.ActiveSheet; oRng = oSheet.get_Range("A1", Type.Missing); oQT = (Excel.QueryTable) oSheet.QueryTables.Add( "OLEDB;Provider=\"Microsoft.Jet.OLEDB.4.0\";Data Source=\"" + Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles) + "\\Borland Shared\\Data\\dbdemos.mdb\";Persist Security Info=False;", oRng, "select * from Employee"
); oQT.RefreshStyle = Excel.XlCellInsertionMode.xlInsertEntireRows; oQT.Refresh(false); XL.ActiveWorkbook.Saved = true; } finally { oQT = null; oRng = null; oSheet = null; XL.UserControl = true; XL = null; }
После получения данных, в книгу будет добавлена именованная область ячеек, содержащая импортированную таблицу.
QueryTables Property
Add Method
QueryTable Object
Как вставить данные из таблицы Access в таблицу Excel, используя ADO?
Заметьте, что при вставке данных таблица в Excel должна быть уже предварительно создана, т.е. должен быть лист с именем, например, "Country" и в первой строке листа заданы имена полей таблицы.
Delphi:
const
InsCmd = 'insert into [Country$]'#10 + // Country - имя листа в книге
'select * from Country in "%s"'; // Country - имя таблицы в
var Conn: TADOConnection; ... Conn.Execute(Format(InsCmd, ['dbdemos.mdb']));
INSERT INTO Statement
IN Clause
Какие существуют ограничения при использовании книги Excel как БД?
Размер листа (таблицы): 65 536 строк на 256 столбцов;
Содержимое ячейки (текст): 32 767 символов;
Листов в книге: ограничено доступной памятью;
Имен в книге: ограничено доступной памятью.
Хотя книга Excel и может выступать в качестве базы данных, не стоит думать, что это полноценная БД. Таблицы там "голые" — ни индексов, ни триггеров, ни хранимых процедур и других возможностей "стандартных" баз данных. Также велика вероятность неправильного определения типа поля таблицы при открытии ее в DataSet при помощи ADO.
Огромная благодарность Елене Филипповой за помощь и поддержку при написании FAQ.
How To Use ADO with Excel Data from Visual Basic or VBA
Excel Source
Excel Destination
Working with ADO.NET Datasets in Microsoft Office
Microsoft Excel 2003 Language Reference
Understanding the Excel Object Model from a .NET Developer's Perspective
Chapter 6: ActiveX Data Objects
Automating Microsoft Office 97 and Microsoft Office 2000
К материалу прилагаются файлы:
Demo-проект на Delphi (63 K) обновление от 6/14/2006 9:06:00 AM
Demo-проект на C# (32 K) обновление от 6/14/2006 9:06:00 AM