Adobe Flex предоставляет весьма удобные и наглядные средства визуализации данных такие как OLAP кубы разного рода диаграммы с красивыми эффектами. Мне как то захотелось использовать такую диаграмму в своем приложении написанном на Delphi. Например.
Alternative content

Конечно я знаю что Delphi имеется аналогичные компоненты но они как мне кажется в смысле дизайна более «серым»и на фоне «Flex»cовых компонентов. Попробуем встроить Flex приложение в Delphi и передать в него данные для вывода графика.
Поскольку FlashDevelop написан на C# он требует .NET Framework и JRE чтобы скомпилировать Flex приложение. Можно скачать
Beta 4-ой версии или
стабильную 3-ю при установке нужно отметить «Install Flex SDK» при этом установщик скачает и распакует Adobe Flex SDK. Я использовал бету.
Пишем наше Flex приложение.
Запускаем FlashDevelop. Переходим меню Project > New Project, выбираем Flex 4 Project, жмем OK. Пишем имя нашего приложения(у меня «Flex»).
Вот код нашего приложения.
<?xml version="1.0" encoding="utf-8"?>
<!-- Пример диаграммы встраиваемой в программу Delphi-->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
initialize="init()">
<fx:Declarations>
<!--Небольшой Эффект -->
<mx:SeriesSlide id="slideIn"
duration="1500"
direction="up" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.external.ExternalInterface;
import mx.collections.ArrayCollection;
[Bindable]
public var danniye:ArrayCollection = new ArrayCollection;
public function fromDelphi(massiv:Array):void
{
//Записиваваем полученные данные в массив для Графика
danniye = new ArrayCollection(massiv);
}
//Эта функция вызывается при инициазизации флекс приложения
public function init():void
{
//Регистрируем внешную функцию
ExternalInterface.addCallback("fromDelphi", fromDelphi);
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout />
</s:layout>
<s:Panel title='Пример "нереального" бизнесса'>
<s:layout>
<s:VerticalLayout />
</s:layout>
<mx:ColumnChart id="myChart"
dataProvider="{danniye}"
showDataTips="true">
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{danniye}"
categoryField="MONTH" />
</mx:horizontalAxis>
<mx:series>
<mx:ColumnSeries xField="MONTH"
yField="DOHOD"
displayName="Доходы"
showDataEffect="slideIn" />
<mx:ColumnSeries xField="MONTH"
yField="RASHOD"
displayName="Расход"
showDataEffect="slideIn" />
<mx:ColumnSeries xField="MONTH"
yField="PRIB"
displayName="Прибыль"
showDataEffect="slideIn" />
</mx:series>
</mx:ColumnChart>
<mx:Legend dataProvider="{myChart}" />
</s:Panel>
</s:Application>
Для компиляции и запуска жмем F5.
Delphi приложение.
И так запустим Delphi и начнем новый проект. Свяжем наше приложение с базой данных. Для простоты я использовал ClientDataSet а данные беру из XML файл в формате cds-xml. Бросаем компонент форму указываем путь к XML файлу. Бросаем DataSource свойство DataSet устанавливаем равным ClientDataSet.
Теперь добавляем идем меню Component > Import Active X Control
В появившемся окне выбираем Shockwave Flash и нажимаем кнопку Install. В следующих окнах нажимаем OK и Yes.
Бросаем в окно программы компонент ShockwaveFlash из набора Active X. Добавим в uses XMLIntf, XMLDoc, StdCtrls и напишем процедуру для вызова функции которая будет находится внутри нашей флешки.
procedure TForm1.CdsToXml(datset:TDataSource; flash:TShockwaveFlash);
var i, j : integer;
filNode, recNode, obNode, arNode, iNode, inNode:IXMLNode;
xmldoc:TXMLDocument;
begin
try
//создем Xml документ
xmldoc:=TXMLDocument.Create(nil);
xmldoc.Active:=True;
//Главный тег
inNode:=xmldoc.AddChild('invoke');
xmldoc.Encoding:='windows-1251';
inNode.Attributes['name']:='fromDelphi';
iNode:=inNode.AddChild('arguments');
arNode:=iNode.AddChild('array');
with datset.DataSet do begin
{пребираем все записи поля таблыци и взависимосьти от типа поля
зеркалируем каждое значение в нужные теги}
first;
for I := 1 to RecordCount do begin
obNode:=arNode.AddChild('property');
obNode.Attributes['id']:=IntToStr(I-1);
recNode:=obNode.AddChild('object');
for j := 0 to FieldCount-1 do begin
filNode:=recNode.AddChild('property');
filNode.Attributes['id']:=FieldDefs.Items[j].Name;
case Fields[j].DataType of
ftString:
begin
iNode:=filNode.AddChild('string');
iNode.Text:=Fields[J].Value;
end;
ftBoolean:
if Fields[J].AsBoolean then
iNode:=filNode.AddChild('true')
else
iNode:=filNode.AddChild('false');
ftCurrency:
begin
iNode:=filNode.AddChild('number');
iNode.Text:=FloatToStr(Fields[J].AsFloat);
end;
ftBCD:
begin
iNode:=filNode.AddChild('number');
iNode.Text:=FloatToStr(Fields[J].AsFloat);
end;
ftInteger:
begin
iNode:=filNode.AddChild('number');
iNode.Text:=Fields[J].Value;
end;
ftFloat:
begin
iNode:=filNode.AddChild('number');
iNode.Text:=Fields[J].Value;
end;
ftDate:
begin
iNode:=filNode.AddChild('string');
iNode.Text:=Fields[J].Value;
end;
ftDateTime:
begin
iNode:=filNode.AddChild('string');
iNode.Text:=Fields[J].Value;
end;
ftSmallint:
begin
iNode:=filNode.AddChild('number');
iNode.Text:=Fields[J].Value
end;
else iNode:=filNode.AddChild('null');
end;
end;
Next;
end;
end;
finally
//Вызаваем фукцию во флешке
flash.CallFunction(inNode.XML);
xmldoc:=nil;
end;
end;
Эта процедура будет создаст XML документ в котором будет указанно имя вызываемой функции и ее параметры. Которая будет иметь вид типа.
<invoke name="fromDelphi">
<arguments>
<array>
<property id="0">
<object>
<property id="MONTH">
<string>Январь</string>
</property>
<property id="DOHOD">
<number>1500</number>
</property>
<property id="RASHOD">
<number>700</number>
</property>
<property id="PRIB">
<number>800</number>
</property>
</object>
</property>
<property id="1">
<object>
<property id="MONTH">
<string>Февраль</string>
</property>
<property id="DOHOD">
<number>2500</number>
</property>
<property id="RASHOD">
<number>1340</number>
</property>
<property id="PRIB">
<number>1160</number>
</property>
</object>
</property>
<property id="2">
<object>
<property id="MONTH">
<string>Март</string>
</property>
<property id="DOHOD">
<number>1100</number>
</property>
<property id="RASHOD">
<number>820</number>
</property>
<property id="PRIB">
<number>280</number>
</property>
</object>
</property>
</arguments>
</invoke>
Пишем в обработчике onCreate нашей формы.
procedure TForm1.FormCreate(Sender: TObject);
begin
//Разделитель точка
DecimalSeparator:='.';
//Указаваем путь к нашей флешки, здесь она рядом с экзешником
ShockwaveFlash1.LoadMovie(0, ExtractFilePath(Application.ExeName)+'flex.swf');
end;
Бросаем на нашу форму кнопку и вызываем процедуру приготовления XML пакета в котором указанны названия функции нашей флешки и параметры к ней.
procedure TForm1.btn1Click(Sender: TObject);
begin
ClientDataSet.Open;
CdsToXml(DataSet, ShockwaveFlash1);
end;
Компилируем Delphi приложение, находим swf файл скомпилированный на FlashDevelop и кидаем его рядом с экзешником Delphi приложения и запускаем его. Как только флешка загрузится жмем нашу единственную кнопку и радуемся результату :).
Архив с исходниками.