ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

もっと楽にGUIとの連携がしたい:Python + Delphi = P4D(Python for Delphi)

前回は、wxPythonGUIに使った VisualWx による開発を ちろっと紹介しました。
で、Blogを書きつつ関係する情報が無いか探している時、Rubyでは Apollo ってライブラリがあるのに気付きました。


Apolloってのは、GUIDelphiを使うってライブラリで、Delphi を知っている人ならば、多分使いやすいと思います。
で、似たような奴がPythonにも無いかな?と後で調べてみたら、Python for Delphi ってライブラリがあるようです。


Delphiなら VCL(GUIライブラリ)の説明が豊富なので、結構良いチョイスかも知れません。
ただ、この Python for Delphi なんですが、オフィシャルページでは Python 2.3 を要求しているようなんですよね。
現在、主力が Python 2.4 に移行しつつある(してるんですよね?)状態で、これは ちょっと痛い。
(試しに、セットアップしてみたんですが、 Python 2.4 を認識してくれませんでした)


Python 2.4対応している Python for Delphi って無いのかな?と思って、色々ぐぐるってみたら、見つけました。Python 2.4対応の奴。


ちなみに省略名が P4D みたいです。一瞬、ドリルプリンセスを思い出しました。わはは。

インストール

インストールは簡単です。
ページ下部に、ダウンロードページへのリンクがあるので、そこにジャンプしてインストーラをダウンロードします。


Windows Installerなので、非常に楽です。
リンクにも書かれていますが、インストール前に、Delphi(or C++ Builder)とPythonを予めインストールしておく必要があります。

P4D Installer (5 052 Kb)
Windows Installer
Requires Delphi 3-7/2005 or C++Builder 3-5, and Python 1.5 to 2.4

Delphiだけでなく C++ Builderにも対応しているので、「Delphiなんてわから〜ん」という人もOKです。(自分は、C++ Builderより高速コンパイルで安定しているDelphiの方が好きですけどね)


インストールが完了すると、Pythonタブが追加されています。
P4D1
P4D1 posted from フォト蔵


使い方は、Python for Delphiがインストールされているフォルダの「Demos」の下に、合計32くらい(Delphi 6の場合)のサンプルが収録されているので、そちらを見るのが良いでしょう。

簡単な使い方

サンプルを見るのが一番なんですが、それじゃぁ あんまりにもあんまりなんで、ちょっくら試してみます。


Delphiを起動したら、Pythonタブから PythonEngine コンポーネントと、Standardタブから Button コンポーネントをフォームに置きます。
P4D3
P4D3 posted from フォト蔵


次に、ButtonコンポーネントのClickイベントに、以下のコードを記述します。

procedure TForm1.Button1Click(Sender: TObject);
var
    v: PPyObject;
begin
    v := PythonEngine1.EvalString('2+4');
    ShowMessage(PythonEngine1.PyObjectAsString(v));
end;


早速実行してみます。
P4D4
P4D4 posted from フォト蔵

簡単ですね。

Pythonのprint出力を、DelphiのMemoコンポーネントで表示する

Pythonスクリプトなので、printで結果を出力するケースが多いです。
この出力を、Delphiに取り出すには、PythonGUIInputOutput コンポーネントを使用します。


先ほどのフォームに、PythonGUIInputOutputコンポーネントとMemoコンポーネントを追加します。
P4D5
P4D5 posted from フォト蔵


それから、各種コンポーネントをプロパティウィンドウから連携させます。

  • PythonEngine1のIOプロパティに、PythonGUIInputOutput1を設定します。
    P4D6
    P4D6 posted from フォト蔵
  • PythonGUIInputOutput1のOutputプロパティに、Memo1を設定します。
    P4D7
    P4D7 posted from フォト蔵


次に、ButtonコンポーネントのClickイベントを、以下のように書き換えます。

procedure TForm1.Button1Click(Sender: TObject);
begin
    PythonEngine1.ExecString('print "hello Python"');
end;


早速実行してみます。
P4D8
P4D8 posted from フォト蔵

このように、print出力をフックできます。便利ですね。

DelphiPythonとの間でデータをやり取りする

何かアプリケーションを作ろうとする場合、PythonDelphiとの間でデータをやり取りする必要があります。
例えば、フォーム上のエディットボックスの値を、Pythonから参照したりですね。
そういう場合は、PythonDelphiVarコンポーネントを使用します。


先ほどのフォームに、PythonDelphiVarコンポーネントとEditコンポーネントを追加します。
P4D9
P4D9 posted from フォト蔵


次に、PythonDelphiVarコンポーネントのVarNameプロパティを、以下のように書き換えます。

  • VarName: var1

P4D10
P4D10 posted from フォト蔵


それから、PythonDelphiVarコンポーネントのOnGetDataイベントとOnSetDataイベントに以下のコードを追加します。

procedure TForm1.PythonDelphiVar1GetData(Sender: TObject;
  var Data: Variant);
begin
    Data := Edit1.Text;
end;

procedure TForm1.PythonDelphiVar1SetData(Sender: TObject; Data: Variant);
begin
    Edit1.Text := Data;
end;


次に、ButtonコンポーネントのClickイベントを、以下のように書き換えます。

procedure TForm1.Button1Click(Sender: TObject);
begin
    PythonEngine1.ExecString('print var1.Value; var1.Value = var1.Value + " add Python"');
end;


早速実行してみます。
エディットボックスに適当な文字を書いて…。
P4D11
P4D11 posted from フォト蔵
ボタンを押すと、変化します。
P4D12
P4D12 posted from フォト蔵

要するに、PythonDelphiVarコンポーネントを仲介者としている訳ですね。なるほど〜。

Delphiの関数を、Pythonから呼び出す

データのやり取りが出来たなら、次は関数の呼び出しです。
PythonからDelphiで記述したコードを呼び出すには、PythonModuleコンポーネントを使います。


先ほどのフォームに、PythonModuleコンポーネントを置きます。
P4D13
P4D13 posted from フォト蔵


次に、PythonModuleコンポーネントのModuleNameプロパティを以下のように書き換えます。


それから、PythonModuleコンポーネントのOnInitializationイベントに以下のコードを追加します。

procedure TForm1.PythonModule1Initialization(Sender: TObject);
begin
  with Sender as TPythonModule do
    begin
      AddMethod( 'test', hoge1_test, 'test' );
    end;
end;


次に、Unit1のソースコード中に、以下を追加します。

function hoge1_test(self, args: PPyObject ): PPyObject; cdecl;
begin
    with GetPythonEngine do
    begin
        ShowMessage(PyObjectAsString(args));
        Result := ReturnNone;
    end;
end;


早速実行してみます。
P4D15
P4D15 posted from フォト蔵

PythonModuleを使うと、Delphiで作成した関数を呼び出せるようです。
cdecl宣言が必要なのは、多分 C++ Builder でも動かせるように、という意味でしょうね。

配布について(予想)

配布なんですが、PythonEngineコンポーネントに、DllNameプロパティとDllPathプロパティがあります。
P4D16
P4D16 posted from フォト蔵


ここから予想するに、アプリケーションと一緒に このライブラリを一緒に配布すれば(同じカレントフォルダに置けばいいでしょう)、Pythonをインストールする事なく、動作できると思います。

PythonスクリプトからVCLを直接操作する

今までは、Delphi上でコンポーネントを貼り付けて作業していました。

Python for Delphiのインストールされているフォルダの下に、「Module/Delphi」フォルダがあり、ここのDelphi.dprプロジェクトを開いてビルドすると、Delphi.pyd ファイルが出来ます。
これを、Python24/DLLs フォルダ下にコピーすると、PythonスクリプトからVCLライブラリを呼び出せるようになります。


Module/TestApp.pyのサンプルを実行すると、以下のようなフォームが簡単に呼び出せます。
P4D2
P4D2 posted from フォト蔵


"import Delphi"した後、"help(Delphi)"したり、"dir(Delphi)"してみたんですが、一通りのDelphiVCLコンポーネントが呼び出せるっぽいですね。
(ヘルプシステムが内蔵されているで、こういう時 Pythonって便利です)

>>> dir(Delphi)
['Abort', 'Application', 'BasicAction', 'Bevel', 'BitBtn', 'Bitmap', 'BoundLabel
', 'Button', 'Canvas', 'CheckBox', 'Collection', 'ColorBox', 'ComboBox', 'Compon
ent', 'Control', 'ControlBar', 'CreateComponent', 'CustomActionList', 'CustomCon
trol', 'CustomDrawGrid', 'CustomEdit', 'CustomForm', 'CustomGrid', 'CustomMemo',
 'DateTimePicker', 'DelphiDefaultContainer', 'DelphiDefaultIterator', 'DrawGrid'
, 'Edit', 'Form', 'FreeConsole', 'Graphic', 'GroupBox', 'Header', 'IDABORT', 'ID
CANCEL', 'IDCLOSE', 'IDCONTINUE', 'IDHELP', 'IDIGNORE', 'IDNO', 'IDOK', 'IDRETRY
', 'IDTRYAGAIN', 'IDYES', 'Icon', 'Image', 'Label', 'LabeledEdit', 'ListBox', 'M
B_ABORTRETRYIGNORE', 'MB_APPLMODAL', 'MB_DEFBUTTON1', 'MB_DEFBUTTON2', 'MB_DEFBU
TTON3', 'MB_DEFBUTTON4', 'MB_HELP', 'MB_ICONASTERISK', 'MB_ICONERROR', 'MB_ICONE
XCLAMATION', 'MB_ICONHAND', 'MB_ICONINFORMATION', 'MB_ICONQUESTION', 'MB_ICONSTO
P', 'MB_ICONWARNING', 'MB_NOFOCUS', 'MB_OK', 'MB_OKCANCEL', 'MB_RETRYCANCEL', 'M
B_SYSTEMMODAL', 'MB_TASKMODAL', 'MB_YESNO', 'MB_YESNOCANCEL', 'Memo', 'Metafile'
, 'Monitor', 'Notebook', 'Object', 'Page', 'PageControl', 'PaintBox', 'Panel', '
Persistent', 'Picture', 'Point', 'RadioButton', 'RadioGroup', 'Rect', 'Screen',
'ScrollBar', 'Shape', 'Size', 'SpeedButton', 'Splitter', 'StaticText', 'StringGr
id', 'Strings', 'TabSheet', 'Timer', 'VarParameter', 'WinControl', '__doc__', '_
_file__', '__name__', 'bkAbort', 'bkAll', 'bkCancel', 'bkClose', 'bkCustom', 'bk
Help', 'bkIgnore', 'bkNo', 'bkOK', 'bkRetry', 'bkYes', 'caFree', 'caHide', 'caMi
nimize', 'caNone', 'cl3DDkShadow', 'cl3DLight', 'clActiveBorder', 'clActiveCapti
on', 'clAppWorkSpace', 'clAqua', 'clBackground', 'clBlack', 'clBlue', 'clBtnFace
', 'clBtnHighlight', 'clBtnShadow', 'clBtnText', 'clCaptionText', 'clCream', 'cl
Default', 'clDkGray', 'clFuchsia', 'clGradientActiveCaption', 'clGradientInactiv
eCaption', 'clGray', 'clGrayText', 'clGreen', 'clHighlight', 'clHighlightText',
'clHotLight', 'clInactiveBorder', 'clInactiveCaption', 'clInactiveCaptionText',
'clInfoBk', 'clInfoText', 'clLime', 'clLtGray', 'clMaroon', 'clMedGray', 'clMenu
', 'clMenuBar', 'clMenuHighlight', 'clMenuText', 'clMoneyGreen', 'clNavy', 'clNo
ne', 'clOlive', 'clPurple', 'clRed', 'clScrollBar', 'clSilver', 'clSkyBlue', 'cl
Teal', 'clWhite', 'clWindow', 'clWindowFrame', 'clWindowText', 'clYellow', 'fsBo
rder', 'fsSurface', 'gdFixed', 'gdFocused', 'gdSelected', 'mdNearest', 'mdNull',
 'mdPrimary', 'mrAbort', 'mrAll', 'mrCancel', 'mrIgnore', 'mrNo', 'mrNoToAll', '
mrNone', 'mrOk', 'mrRetry', 'mrYes', 'mrYesToAll', 'ssAlt', 'ssCtrl', 'ssDouble'
, 'ssLeft', 'ssMiddle', 'ssRight', 'ssShift']

KylixPythonを連携する

Python for Delphiをインストールすると付いてくるドキュメントに、"Kylix Notes"というのが付いてきます。
Kylix1/2に、Python for Delphiをインストールする事が出来るようです。


自分の周りの環境には、Kylixを入れてないので、試してません。どなたか興味のある方は、試してくださいまし。

まとめ

  • Python for Delphi(P4D)を使うと、Delphi上で画面設計してPythonで制御コードを記述する事が簡単にできます。
  • PythonDelphiとの間のデータ連携や関数呼び出しも、コンポーネントを使う事で楽に記述できます。
  • Module/Delphiのプロジェクトをビルドすれば、Pythonスクリプトから直接VCLを制御できます。
  • ここでは説明してませんが、PythonDatabaseコンポーネントがあり、データベースの連携も可能なようです。
  • Delphiだけでなく、C++ BuilderやKylixとも連携できるようです。

今回試してみて、非常に練られているのに 吃驚しました。
日本語での紹介記事が、あまり見当たらないのは何でなんでしょうね?(これだけの完成度で、Freewareなんですよ。勿体ない)