Example1
Home Up

 

Using Delphi and Python together - An Example

A Delphi app which has all the business logic implemented as Python code.  A perfect marriage of two worlds!

The Delphi Code

Tip: The bold entries in the code below are references to python objects.
unit mainFrm;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  PythonEngine, AtomPythonEngine, StdCtrls, ExtCtrls, PythonGUIInputOutput,
  uHeartMachine;
type
  TfrmMain = class(TForm)
    PE: TAtomPythonEngine;
    PythonInputOutput1: TPythonInputOutput;
    pdvUser: TPythonDelphiVar;
    pdvShare: TPythonDelphiVar;
    pdvOrderManager: TPythonDelphiVar;
    pdvBankBalance: TPythonDelphiVar;
    pdvNumShares: TPythonDelphiVar;
    pdvSharePrice: TPythonDelphiVar;
    PythonDelphiVar2: TPythonDelphiVar;
    lblSharePrice: TLabel;
    bntBuy: TButton;
    btnForceStockToDrop: TButton;
    Timer1: TTimer;
    lblBankBalance: TLabel;
    lblNumShares: TLabel;
    btnSell: TButton;
    Memo1: TMemo;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    lblSharesAreWorth: TLabel;
    Label5: TLabel;
    PythonGUIInputOutput1: TPythonGUIInputOutput;
    btnForceStockToRise: TButton;
    cbNumShares: TComboBox;
    Label6: TLabel;
    cbUserLimit: TComboBox;
    Label7: TLabel;
    lblTotalWorth: TLabel;
    Label8: TLabel;
    cbNumAttempts: TComboBox;
    Label9: TLabel;
    Panel1: TPanel;
    HeartMachine1: THeartMachine;
    Panel2: TPanel;
    HeartMachine2: THeartMachine;
    Panel3: TPanel;
    HeartMachine3: THeartMachine;
    procedure PythonInputOutput1SendData(Sender: TObject;
      const Data: String);
    procedure pdvSharePriceSetData(Sender: TObject; Data: Variant);
    procedure FormShow(Sender: TObject);
    procedure bntBuyClick(Sender: TObject);
    procedure btnForceStockToDropClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure btnSellClick(Sender: TObject);
    procedure btnForceStockToRiseClick(Sender: TObject);
    procedure cbUserLimitChange(Sender: TObject);
    procedure cbNumAttemptsChange(Sender: TObject);
    procedure PEPathInitialization(Sender: TObject; var Path: String);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  TmgmStockMarketMainForm = class(TObject) // ;  // Transformation Interface
  private
    LastPrice : integer;
  public
    procedure display;
    procedure repopulateFromGui;
  end;
var
  frmMain: TfrmMain;
implementation
uses AndyDelphiPy, ComCtrls, pythonAtom, Math;
var
  Share, User, OrderManager : OleVariant;
  mgmMainForm : TmgmStockMarketMainForm;
{$R *.DFM}
procedure TfrmMain.PythonInputOutput1SendData(Sender: TObject;
  const Data: String);
begin
  PyConsoleOut(Data);
end;
procedure TfrmMain.pdvSharePriceSetData(Sender: TObject; Data: Variant);
begin
  lblSharePrice.Caption := Data;
end;
procedure TfrmMain.FormShow(Sender: TObject);
begin
  //PyExeFile('E:\Python20\Boa-0.0.5\AndysTry\Questtest.py', PE);
  PyExeFile('QuesttestFROZEN.py', PE);
  User := PyClass('User()', pdvUser, PE);
  Share := PyClass('Share("Friendly Co.", worth=10)', pdvShare, PE);
  OrderManager := PyClass('OrderManager()', pdvOrderManager, PE);
  mgmMainForm := TmgmStockMarketMainForm.Create;
  timer1.enabled := true;
end;
procedure TfrmMain.bntBuyClick(Sender: TObject);
begin
  OrderManager.AddOrder(User.myself, strtoint(cbNumShares.text), 'buy', Share.myself);
end;
procedure TfrmMain.btnSellClick(Sender: TObject);
begin
  OrderManager.AddOrder(User.myself, strtoint(cbNumShares.text), 'sell', Share.myself);
end;
procedure TfrmMain.Timer1Timer(Sender: TObject);
begin
  try
    Share.fluxtuate;
    OrderManager.ProcessOrders;
    mgmMainForm.display;
  except
    timer1.enabled := false;
    showmessage('Some error cancelled the game.');
  end;
end;
{ TmgmStockMarketMainForm }
procedure TmgmStockMarketMainForm.display;
var
  f : double;
begin
  if LastPrice = Share.CurrentPrice then
    with frmMain.lblSharePrice do
      Caption := Caption + '.'
  else
    frmMain.lblSharePrice.Caption := '$ ' + inttostr(Share.CurrentPrice);
  LastPrice := Share.CurrentPrice;
  f := User.BankBalance;
  frmMain.lblBankBalance.Caption := format('%m', [ f ]);
  frmMain.lblNumShares.Caption := User.NumSharesOwned;
  f := User.NumSharesOwned * Share.CurrentPrice;
  frmMain.lblSharesAreWorth.Caption := format('%m', [ f ]);
  f := f + User.BankBalance;
  frmMain.lblTotalWorth.Caption := format('%m', [ f ]);
  frmMain.cbNumAttempts.Text := OrderManager.MaxAttempts;
  frmMain.cbUserLimit.Text := User.SharePriceLimit;
  frmMain.HeartMachine1.AddPoint(0, min(Share.CurrentPrice, 100), 'Share Price');
  frmMain.HeartMachine2.AddPoint(0, min(User.BankBalance, 50000), 'Bank Balance');
  frmMain.HeartMachine3.AddPoint(0, min(User.NumSharesOwned, 1000), 'Num Shares Owned');
end;
procedure TmgmStockMarketMainForm.repopulateFromGui;
begin
  User.SharePriceLimit := strtoint( frmMain.cbUserLimit.Text );
  OrderManager.MaxAttempts := strtoint( frmMain.cbNumAttempts.Text );
  display;
end;
procedure TfrmMain.cbUserLimitChange(Sender: TObject);
begin
  mgmMainForm.repopulateFromGui;
end;
procedure TfrmMain.cbNumAttemptsChange(Sender: TObject);
begin
  mgmMainForm.repopulateFromGui;
end;
procedure TfrmMain.btnForceStockToRiseClick(Sender: TObject);
begin
  Share.CurrentPrice := Share.CurrentPrice + 10 + random(20);
end;
procedure TfrmMain.btnForceStockToDropClick(Sender: TObject);
begin
  Share.CurrentPrice := random(10);
end;


procedure TfrmMain.PEPathInitialization(Sender: TObject; var Path: String);
begin
  //path := 'e:\try\deploy;e:\try\deploy\lib';
end;
end.

 

Tip: The bold entries in the code above are references to python objects.

The HeartMachine Delphi component is available from here.

 

The Python Code

Note:  Not all the python code is shown, due to confidentiality issues.

# Share trading game simulator.
false = 0 ; true = 1
import random, sys
def log(s):
    print s
    #sys.stdout.flush()
class Share:
    def __init__(self, name, worth=10):
        self.CurrentPrice = worth
        self.Name = name
    def __str__(self):
        return 'Share ' + self.Name + '  Worth= $' + `self.CurrentPrice` + ' per share.'
    def fluxtuate(self):
        if random.randrange(0,2):
            self.CurrentPrice = self.CurrentPrice + random.randrange(-10,10)
        if self.CurrentPrice <= 0:
            self.CurrentPrice = 1
        ##log('..time passes.. ' + str(self))
    def myself(self):
        return self
class User:
    def __init__(self, initialBankBalance=1000, initialNumShares=0, initialSharePriceLimit=10):
        self.BankBalance = initialBankBalance
        self.NumSharesOwned = initialNumShares
        self.SharePriceLimit = initialSharePriceLimit
    def __str__(self):
        return 'User Bank balance='+`self.BankBalance` + \
               ' Number of Shares=' + `self.NumSharesOwned` + \
               ' Share Price Limit=' + `self.SharePriceLimit`
    def myself(self):
        return self
class Order:
    def candivest(self):
        return self.NumberOfShares <= self.User.NumSharesOwned
    def canafford(self):
        return (self.Share.CurrentPrice*self.NumberOfShares) < self.User.BankBalance
    def sharepricetoolow(self):
        return self.Share.CurrentPrice < self.User.SharePriceLimit
    def sharepricetoohigh(self):
        return self.Share.CurrentPrice > self.User.SharePriceLimit
    def __init__(self, user, numshares, buyorsell, share):
        self.User = user
        self.Share = share
        self.NumberOfShares = numshares
        self.Command = buyorsell
        #print 'DEBUG - self.Share.CurrentPrice', self.Share.CurrentPrice # debug !!!!
    def __str__(self):
        return 'Order to %s %d %s shares' % (self.Command, self.NumberOfShares, self.Share.Name)

etc.

 

Related 'Python for Delphi' Links on this site:

bullettutorial - Andy's Python Delphi Tutorial - Getting started with the basics.  Also use these techniques if you are using Delphi 5 or below, and Python 2.0 or below.   Includes info on getting these free components.
bulletcode - Here are Andy's Extensions  - a delphi unit that adds a few utility functions to Python for Delphi. 
bullettutorial - Here is a later tutorial using the Latest Techniques in Python for Delphi - use these if you have Delphi 6 and Python 2.1 or higher.
bulletdiscussion & tips - Here is a discussion and tips on python for delphi deployment issues.
bulletanimated slideshow tutorial  - Here is an animated visual viewlet demo of using the Python for Delphi components to build a Delphi app that talks to python.
bulletexample and screenshot of a Delphi GUI application which uses python code for all its business logic.

return to main Andy Patterns home page