Рассылка закрыта
При закрытии подписчики были переданы в рассылку "О карьере и профессиональном развитии IT-специалистов" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Август 2005 → | ||||||
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
|
30
|
31
|
Статистика
-4 за неделю
Программирование для начинающих и не только
Информационный Канал Subscribe.Ru |
По материалам сайта www.gigabyte.iatp.org.ua
Внедрение питона в Delphi
Внедрение тех или иных средств расширения функциональности разрабатываемых Вами приложений уже давно вышло за пределы чего-то отдаленного и недоступного. А сегодня с растущей популярностью языка Python соответственно расширяются и сферы эго применения. И если Microsoft и Open Office используют бейсик-подобный язык макрокоманд то ничего не мешает нам использовать Питон в своих приложениях для тех же целей.
Кому это выгодно?
Естественный ответ на этот вопрос: Всем.
Во-первых это выгодно Вам как разработчику приложения так как единожды написав базовый интерфейс программы Вы сможете по мере необходимости добавлять в него соответствующую функциональность без перекомпиляции всего приложения. А если при этом вы еще и используете один из популярных языков для написания плагинов, то сможете и вовсе не беспокоиться о написании дополнительных модулей так как использование макроязыков снимает необходимость в компиляции кода, а соответственно отчасти лишает вас необходимости сидеть над отладкой и настройкой внешних модулей и их <привинчиванию> к главной программе.
Во-вторых это выгодно заказчику. Так если у него в наличии есть нормальный программист, то он сам сможет добавить недостающую функциональность базовому приложению и тем самым настроить его под себя, что в конечном итоге позитивно скажется на эффективности работы программы, и, опять таки, снимет с Вас большую часть головной боли по поддержке и сопровождению Вашего программного продукта.
Джентльменский набор инструментов
Для внедрения макропитона в разрабатываемое вами приложение нам потребуется:
- Свежий интерпретатор Python, который можно найти на сайте www.python.org или на КП диске;
- Портированные с C файлы хедеров Python API, которые вы можете либо преобразовать вручную или с помощью одной из утилит h2pas или же загрузить уже готовые порты для Delphi например с адреса: http://membres.lycos.fr/marat/delphi/PythonForDelphi.exe (или же на КП диске)
- Ну и естественно Delphi. Здесь без него никак не обойтись.
После инсталляции интерпретатора и Delphi-портов у вас в арсенале Delphi-компонентов появится новая палитра компонентов "Python" с 8-ю новыми компонентами которые отвечают за соответствующую часть работы (см. таблицу).
Описание компонентов входящих в состав пакета PythonForDelphi | |
---|---|
Название компонента | Описание |
TPythonGUIInputOutput, TPythonInputOutput | Транзитные компоненты для вывода результатов выполнения команд питона в указанный текстовый компонент |
TPythonEngine | "Движок" питона. Компонент который собственно и отвечает за выполнение макрокоманд |
TAtomPythonEngine | Наследник TPythonEngine отвечающий за обработку команд переданных посредством COM - технологии. |
TPythonType | Компонент отвечающий за создание и обработку новых типов данных в Python. |
TPythonModule | Компонент отвечающий за создание и обработку новых модулей в Python |
TPythonDelphiVar | Компонент представляющий собой переменную Python. |
TPythonDatabase | Копмонент предоставляющий возможность доступа к базам данных подключенных к Delphi-приложению из макросов Python. |
Привет мир!

Не нарушая традиций ознакомления с языками программирования мы сперва поприветствуем весь мир с тем что наша программа заработала. Для этого мы после запуска Delphi кинем на форму нового приложения два компонента TMemo, а также компоненты TPythonEngine и TPythonGUIInputOutput для вывода результата (см.рис.1). последующая настройка потребует от нас минимума напряга мозгов и не больше ловкости рук для определения компонента Memo1 для вывода результата (см. рис. 2 левый) и подстановки в TPythonEngine компонента
TPythonGUIInputOutput для вывода результата (см. рис. 2 правый). Далее, в реакции кнопки на нажатие записываем следующий код:
И запускаем программу. (см. рис. 3-4).procedure TForm1.Button1Click(Sender: TObject); begin PythonEngine1.ExecStrings(Memo2.Lines); end;


Использование модулей
Один из важнейших элементов будущего расширяемого приложения - объектная модель т.е. совокупность тех специфических методов (объектов, свойств и т.д.) которые по существу выполняют базовые функции и предоставляют макросам доступ тем или иным базовым функциям главного приложения. Одним из простейших методов реализации собственной объектной модели в Python - это использование модулей. Для создания модуля мы воспользуемся компонентом TPythonModule. Перекинув его с палитры компонентов, и установив соответствующие значения его свойств: Engine := PythonEngine1, ModuleName :='mymath' мы тем самым создали новый Python-модуль который в тексте макроса вызывается через команду:import mymath,а используется командой: mymath.<имя функции>.
Для добавления функции осуществляется в событии TPythonModule.OnInitialization посредством метода AddDelphiMethod:
function AddDelphiMethod(MethodName:PChar;DelphiMethod:TDelphiMethod;DocString:PChar) : PPyMethodDef;
-
где
- MethodName - название метода в Python;
- DelphiMethod - ссылка на метод который будет вызван главной программой
- DocString - строка, комментирующая данную функцию.
Реализация добавления метода к Python-модулю осуществляется так:
сам же метод реализуется в одном из компонентов Delphi и подлежит строгой типизации на основе шаблона:procedure TForm1.PythonModule1Initialization(Sender: TObject); begin with (Sender as TPythonModule) do AddDelphiMethod('power',PyPower,'Delphi Power method'); end;
TDelphiMethod = function ( self, args : PPyObject ) : PPyObject of object; cdecl;
Где self - ссылка на объект вызвавший данный метод, args - ссылка на переданные этому методу параметры.
Сама реализация этого метода выглядит в Delphi выглядит следующим образом:
Здесь во первых через глобальную функцию GetPythonEngine вызывается Python-интерпретатор, дальше идет преобразование аргументов переданных методу в тип Variant с последующим вычислением степени и выводом результата.function TForm1.PyPower(pself,args:PPyObject):PPyObject; var base,exponent:Extended; V:Variant; begin with GetPythonEngine do begin V:=PyObjectAsVariant(args); base:=V[0]; exponent:=V[1]; Result:=PyFloat_FromDouble(Power(base,exponent)); end; end;
В тексте Python-макроса вызов этого метода будет выглядеть следующим образом:
А результат выполнения данной команды показан на рисунке 5.Import mymath; Var1 = mymath.power(2,2); Var2 = mymath.power(2,8); Print Var1*Var2;

Использование переменных
Наиболее простым способом доступа к тем или иным параметрам главного приложения из макросов есть использование переменных. Для создания Python-переменных в Delphi используется специальный компонент TPythonDelphiVar. С его помощью создается глобальная или модульная переменная произвольного типа чтение и запись которой вызывают соответствующую реакцию главного приложения. При создании Python-переменной нам следует перекинуть на форму компонент TPythonDelphiVar и заполнить его свойство VarName значением которое в среде Python будет интерпретироваться как переменная. Если при этом оставить значение свойства module по умолчанию (__main__), то будет создана глобальная переменная. Если же задать значение свойства отличное от определенного по умолчанию, то будет создана модульная переменная и доступ к ней будет возможен, после импортирования соответствующего модуля.
Чтение и запись переменной реализуется через соответствующие события компонента TPythonDelphiVar. Если при этом мы записываем простые (ординарные) данные, то можно использовать события OnGetData и OnSetData, если же используются более сложные типы (классы, словари и т.п.) то рекомендуется использовать события OnExtGetData, OnExtSetData.
Для примера мы введем в нашу объектную модель модульную переменную buttonname модуля mymath которая будет отвечать за изменение названия нашей кнопки (Button1). Приведенный ниже код показывает как реализуется обработка чтения и записи в эту переменную:
Этот код должен быть занесен в события OnGetData, OnSetData и OnChange соответственно. Использование же этой переменной в Python-макросе осуществляется следующим образом:procedure TForm1.PythonDelphiVar1GetData(Sender: TObject; var Data: Variant); begin Data:=Button1.Caption; end; procedure TForm1.PythonDelphiVar1SetData(Sender: TObject; Data: Variant); begin Button1.Caption:=Data; end; procedure TForm1.PythonDelphiVar1Change(Sender: TObject); begin Button1.Caption:=(Sender as TPythonDelphiVar).ValueAsString; end;
,а результат выполнения этой команды показан на рис.6.import mymath; print mymath.buttonname; print mymath.buttonname.Value; mymath.buttonname.Value="Testing";

Как видим название кнопки изменилось с <Button1> на <Testing>. Хочу заметить, что при обращении к переменной только по ее имени вы получите информационное значение:
Создание новых типов данных
Если типы данных используемые для работы с макросами в Python полностью не удовлетворяют ваших потребностей, то создать новый тип данных, который бы реализовывал недостающие возможности встроенных типов данных. Для этого предназначен компонент TPythonType. А его использование приведено в листинге. По сути для реализации нового типа данных в главной программе создается объект - наследник TPyObject в котором реализуются все необходимые функции (в нашем случае суммирование и вычитание комплексных чисел). После этого в специальных методах класса регистрируются все возможные операции над этим типом данных после чего с ним можно работать в интерпретаторе. (см.рис.7)

Заключение
Этих базовых возможностей при правильной реализации будет вполне достаточно для того, чтоб организовать хорошо документируемый, макроязык на основе Python, который сможет не только <выводить числа> в текстовое поле, но также создавать свои формы, диалоги, кнопки и др., а изучив синтаксическую мощь и логическую простоту языка Python вы превратите процесс усовершенствования вашего приложения в легкий и приятный труд.
Под конец хочу Вас предупредить, что для нормальной работы приложений использующих Python как макроязык Вам следует учесть что у большинства пользователей он (дистрибутив Python) не установлен, так что при инсталляции вам следует это учесть и заранее запихнуть в инсталляционный пакет подходящую версию интерпретатора.
unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, PythonEngine, PythonGUIInputOutput, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; Memo2: TMemo; Button1: TButton; PythonGUIInputOutput1: TPythonGUIInputOutput; PythonEngine1: TPythonEngine; PythonModule1: TPythonModule; PythonDelphiVar1: TPythonDelphiVar; PythonType1: TPythonType; procedure Button1Click(Sender: TObject); procedure PythonModule1Initialization(Sender: TObject); procedure PythonDelphiVar1GetData(Sender: TObject; var Data: Variant); procedure PythonDelphiVar1SetData(Sender: TObject; Data: Variant); procedure PythonDelphiVar1Change(Sender: TObject); procedure PythonType1Initialization(Sender: TObject); private function PyPower(pself,args:PPyObject):PPyObject;cdecl; { Private declarations } public { Public declarations } end; TPyComplex = class(TPyObject) re,im:Extended; Name:String; constructor Create(APythonType:TPythonType);override; constructor CreateWith(PythonType:TPythonType;args:PPyObject);override; function Repr:PPyObject;override; class procedure RegisterMethods(PythonType:TPythonType);override; class procedure RegisterMembers(PythonType:TPythonType);override; class procedure RegisterGetSets(PythonType:TPythonType);override; procedure Add(ARe,AIm:Extended); procedure Sub(ARe,AIm:Extended); function DoAdd(args:PPyObject):PPyObject;cdecl; function DoSub(args:PPyObject):PPyObject;cdecl; end; var Form1: TForm1; implementation uses Math; {$R *.dfm} function TForm1.PyPower(pself,args:PPyObject):PPyObject; var base,exponent:Extended; V:Variant; begin with GetPythonEngine do begin V:=PyObjectAsVariant(args); base:=V[0]; exponent:=V[1]; Result:=PyFloat_FromDouble(Power(base,exponent)); end; end; procedure TForm1.Button1Click(Sender: TObject); begin PythonEngine1.ExecStrings(Memo2.Lines); end; procedure TForm1.PythonModule1Initialization(Sender: TObject); begin with (Sender as TPythonModule) do AddDelphiMethod('power',PyPower,'Delphi Power method'); end; procedure TForm1.PythonDelphiVar1GetData(Sender: TObject; var Data: Variant); begin Data:=Button1.Caption; end; procedure TForm1.PythonDelphiVar1SetData(Sender: TObject; Data: Variant); begin Button1.Caption:=Data; end; procedure TForm1.PythonDelphiVar1Change(Sender: TObject); begin Button1.Caption:=(Sender as TPythonDelphiVar).ValueAsString; end; procedure TForm1.PythonType1Initialization(Sender: TObject); begin PythonType1.PyObjectClass:=TPyComplex; end; constructor TPyComplex.Create(APythonType:TPythonType); begin inherited Create(APythonType); re:=0; im:=0; end; constructor TPyComplex.CreateWith(PythonType:TPythonType;args:PPyObject); var V:Variant; begin inherited; with GetPythonEngine do begin V:=PyObjectAsVariant(args); re:=V[0]; im:=V[1]; end; end; function TPyComplex.Repr:PPyObject; begin with getPythonEngine do Result:=VariantAsPyObject(Format('(%3.2f %3.2f)',[re,im])); end; function TPyComplex_GetName(obj:PPyObject;context:Pointer):PPyObject;cdecl; begin with GetPythonEngine do Result:=PyString_FromString(PChar(TPyComplex(PythonToDelphi(Obj)).Name)); end; function TPyComplex_SetName(obj,value:PPyObject;context:Pointer):integer;cdecl; begin with GetPythonEngine do begin if PyString_Check(value) then begin TPyComplex(PythonToDElphi(Obj)).Name:=PyObjectAsString(Value); Result:=0; end else begin Result:=-1; PyErr_SetString(PyExc_AttributeError^,'attribute Name expected a string value'); end; end; end; class procedure TPyComplex.RegisterMethods; begin inherited; with PythonType do begin AddMethod('Add',@TPyComplex.DoAdd,'PyComplex.Add(re,im)'); AddMethod('Sub',@TPyComplex.DoSub,'PyComplex.Sub(re,im)'); end; end; class procedure TPyComplex.RegisterMembers; begin inherited; with PythonType do begin AddMember('re',mtDouble,Integer(@TPyComplex(nil).re),mfDefault,'Real part'); AddMember('im',mtDouble,Integer(@TPyComplex(nil).im),mfDefault,'Imaginary part'); end; end; class procedure TPyComplex.RegisterGetSets; begin inherited; with PythonType do AddGetSet('Name',TPyComplex_GetName,TPyComplex_SetName,'Name of number',nil); end; procedure TPyComplex.Add(Are:Extended;AIm:Extended); begin RE:=Re+ARE; Im:=Im+AIm; end; procedure TPyComplex.Sub(ARe:Extended;AIm:Extended); begin Re:=RE-ARE; Im:=Im-AIm; end; function TPyComplex.DoAdd(args:PPyObject):PPyObject; var V:Variant; begin with GetPythonEngine do begin V:=PyObjectAsVariant(args); Add(V[0],V[1]); Result:=ReturnNone; end; end; function TPyComplex.DoSub(args:PPyObject):PPyObject; var V:Variant; begin with GetPythonEngine do begin V:=PyObjectAsVariant(args); Sub(V[0],V[1]); Result:=ReturnNone; end; end; end.
Subscribe.Ru
Поддержка подписчиков Другие рассылки этой тематики Другие рассылки этого автора |
Подписан адрес:
Код этой рассылки: comp.soft.prog.programmershelp |
Отписаться
Вспомнить пароль |
В избранное | ||