I have a legacy Delphi application that I need to automate for testing purposes. I'm having difficulty with directing the automation requests to the correct component. The included example demonstrates the issue (on my environment anyway). Heres a simple Delphi application I'm wanting to control:
Project1.dpr
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Unit1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
CheckBox1: TCheckBox;
Timer1: TTimer;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Label2: TLabel;
Panel1: TPanel;
procedure ControlClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ControlClick(Sender: TObject);
begin
Memo1.Lines.Add (Format ('Control "%s" clicked', [TControl (Sender).Name])) ;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if Assigned(Screen.ActiveControl) then
begin
Panel1.Caption := Screen.ActiveControl.Name ;
end
else
begin
Panel1.Caption := 'None.' ;
end ;
end ;
end.
Unit1.dfm
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 212
ClientWidth = 407
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Label2: TLabel
Left = 73
Top = 193
Width = 32
Height = 13
Caption = 'Focus:'
end
object Memo1: TMemo
Left = 24
Top = 8
Width = 201
Height = 177
TabOrder = 0
end
object Button1: TButton
Left = 304
Top = 11
Width = 75
Height = 25
Caption = '1'
TabOrder = 1
OnClick = ControlClick
end
object CheckBox1: TCheckBox
Left = 296
Top = 171
Width = 97
Height = 17
Caption = 'CheckBox1'
TabOrder = 6
OnClick = ControlClick
end
object Button2: TButton
Left = 304
Top = 42
Width = 75
Height = 25
Caption = '2'
TabOrder = 2
OnClick = ControlClick
end
object Button3: TButton
Left = 304
Top = 73
Width = 75
Height = 25
Caption = '3'
TabOrder = 3
OnClick = ControlClick
end
object Button4: TButton
Left = 304
Top = 104
Width = 75
Height = 25
Caption = '4'
TabOrder = 4
OnClick = ControlClick
end
object Button5: TButton
Left = 304
Top = 135
Width = 75
Height = 25
Caption = '5'
TabOrder = 5
OnClick = ControlClick
end
object Panel1: TPanel
Left = 116
Top = 191
Width = 109
Height = 17
TabOrder = 7
end
object Timer1: TTimer
Interval = 300
OnTimer = Timer1Timer
Left = 240
Top = 152
end
end
Automate.py
import pywinauto
from pywinauto import application
def Click (AForm, AControlName):
FControl = AForm [AControlName]
FControl.click()
return ()
FormTitle = "Form1"
try:
app = application.Application().connect(title=FormTitle)
form1 = app[FormTitle]
Click (form1, "Button1")
Click (form1, "Button2")
Click (form1, "Button3")
Click (form1, "Button4")
Click (form1, "Button5")
Click (form1, "Checkbox1")
exit (0)
except pywinauto.application.ProcessNotFoundError:
print(f"No running instance of {FormTitle} found.")
exit (1)
except Exception as e:
print(f"An error occurred: {str(e)}")
exit (1)
All is good, except that the buttons are reversed. If I direct a click to Button1, Button5 registers a click. Other experiments have shown that it's not necessarily predictable as to how it is going to redirect the request - the checkbox is OK for example, though I never tried a larger number of those. All I want is an unambiguous way of referencing a control - because the control name doesn't cut it.
UPDATE Further experiments have seemed to indicate that the control's caption is what I need to pass to the call to send a click message to the control.
Access by attribute or by item performs a typo resistant search procedure. The indexing in this procedure is different. This is described in more details in the Getting Started Guide.
For search by exact caption you need to make search criteria this way (it works faster!):
If you want to know the correct specification, just dump it:
So you can copy-paste such
child_windowspecifications from this dump.BTW, there is a known issue with
connectmethod that requires explicit timeout for now:connect(title=FormTitle, timeout=10)