Title: Adjust the Tab Order with the Wizard
Question: How to use open tool api to set tab order?
Answer:
This time I show a wizard, which use Delphi Open Tools API to auto adjust tab order on a form. After the wizard has done, the tab order of all the control in the form will be set from left to right, from top to bottom.
My friend Hong Liang writes this unit. I got the permit with him, you can use it freely.
Here is the source code of Autotab.pas:
unit AutoTab;
interface
uses
Windows, Dialogs, ExptIntf, ToolIntf,
FileCtrl, SysUtils, EditIntf, classes;
type
POrderComponent = ^TOrderComponent;
TOrderComponent = record
ParentName: string;
SelfName: string;
Left: Integer;
Top: Integer;
TabOrder: Integer;
end;
TAutoTab = class (TIExpert)
private
procedure SortList; //sort ComponentList
procedure SetListOrder; //set TabOrder's value
public
function GetStyle: TExpertStyle; override;
function GetName: string; override;
function GetAuthor: string; override;
function GetComment: string; override;
function GetPage: string; override;
function GetGlyph: HICON; override;
function GetState: TExpertState; override;
function GetIDString: string; override;
function GetMenuText: string; override;
procedure Execute; override;
end;
procedure Register;
var
ComponentList: TList;
implementation
procedure Register;
begin
RegisterLibraryExpert(TAutoTab.Create);
end;
function TAutoTab.GetStyle: TExpertStyle;
begin
Result := esStandard;
end;
function TAutoTab.GetName: String;
begin
Result := 'Auto Set TabOrder Wizard'
end;
function TAutoTab.GetAuthor: string;
begin
Result := 'LightHong';
end;
function TAutoTab.GetComment: String;
begin
Result := 'First expert';
end;
function TAutoTab.GetPage: string;
begin
Result := '';
end;
function TAutoTab.GetGlyph: HICON;
begin
Result := 0;
end;
function TAutoTab.GetState: TExpertState;
begin
// always enabled, never checked
Result := [esEnabled];
end;
function TAutoTab.GetIDString: String;
begin
// must be unique
Result := 'LightHong.BlankWizard'
end;
function TAutoTab.GetMenuText: String;
begin
Result := '&Auto Set TabOrder Wizard'
end;
function ChildrenCallBack(Param: Pointer;
ComponentInterface: TIComponentInterface): Boolean stdcall;
var
pComponent: POrderComponent;
begin
if ComponentInterface nil then
begin
New(pComponent);
pComponent.ParentName := string(Param);
ComponentInterface.GetPropValueByName('Name', pComponent.SelfName);
ComponentInterface.GetPropValueByName('Left', pComponent.Left);
ComponentInterface.GetPropValueByName('Top', pComponent.Top);
ComponentList.Add(pComponent);
ComponentInterface.GetChildren(PChar(pComponent.SelfName), ChildrenCallBack);
end;
Result := True;
end;
function MyEnumProc(Param: Pointer; const FileName, UnitName,
FormName: string): Boolean stdcall;
var
aFormModule: TIModuleInterface;
aFormInterface: TIFormInterface;
aFormComponent: TIComponentInterface;
aChildComponent: TIComponentInterface;
strFile, strName: string;
i, j: Integer;
PComponent: POrderComponent;
begin
if FormName = '' then
begin
Result := True;
Exit;
end;
strFile := toolservices.getcurrentfile;
strFile := ExtractFileName(strFile);
Delete(strFile, Pos('.', strFile), Length(strFile) - Pos('.', strFile) + 1);
if UnitName = strFile then
begin
aFormModule := ToolServices.GetFormModuleInterface(FormName);
aFormInterface := aFormModule.GetFormInterface;
aFormComponent := aFormInterface.GetFormComponent;
aFormComponent.GetPropValueByName('Name', strName);
if not Assigned(Param) then
//?componentList;
aFormComponent.GetChildren(PChar(strName), ChildrenCallBack)
else begin
//set componentlist order
// showmessage('set order');
for i := 0 to ComponentList.Count - 1 do
begin
PComponent := POrderComponent(ComponentList.Items[i]);
for j := 0 to aFormComponent.GetComponentCount - 1 do
begin
aChildComponent := aFormComponent.GetComponent(j);
aChildComponent.GetPropValueByName('Name', strName);
if PComponent.SelfName = strName then
begin
aChildComponent.SetPropByName('TabOrder', PComponent.TabOrder);
Break;
end;
end;
end;
end;
aFormModule.Free;
aFormInterface.Free;
aFormComponent.Free;
end;
Result := True;
end;
procedure FreeComponentList;
var
i: Integer;
begin
for i := 0 to ComponentList.Count - 1 do
Dispose(ComponentList.Items[i]);
ComponentList.Free;
end;
procedure TAutoTab.Execute;
var
Order: Pchar;
begin
New(Order);
ComponentList := TList.Create;
try
ToolServices.EnumProjectUnits(MyEnumProc, nil);
// showmessage('sort');
SortList;
// showmessage('set');
SetListOrder;
// showmessage('change');
ToolServices.EnumProjectUnits(MyEnumProc, Order);
finally
FreeComponentList;
Dispose(Order);
end;
ShowMessage('Auto Set TabOrder Finished');
end;
procedure TAutoTab.SetListOrder;
var
i: Integer;
intOrder: Integer;
PComponent: POrderComponent;
strPrevParentName: string;
begin
if ComponentList.Count = 0 then
Exit;
PComponent := POrderComponent(ComponentList.Items[0]);
PComponent.TabOrder := 0;
strPrevParentName := PComponent.ParentName;
intOrder := 0;
for i := 1 to ComponentList.Count - 1 do
begin
PComponent := POrderComponent(ComponentList.Items[i]);
if PComponent.ParentName = strPrevParentName then
begin
Inc(intOrder);
PComponent.TabOrder := intOrder;
end
else begin
strPrevParentName := PComponent.ParentName;
PComponent.TabOrder := 0;
intOrder := 0;
end;
end;
end;
procedure TAutoTab.SortList;
var
i, j: Integer;
piComponent, pjComponent: POrderComponent;
bolSameParent: Boolean;
begin
for i := 0 to ComponentList.Count - 1 do
begin
piComponent := POrderComponent(ComponentList.Items[i]);
bolSameParent := False;
for j := 0 to i - 1 do
begin
pjComponent := POrderComponent(ComponentList.Items[j]);
if pjComponent.ParentName piComponent.ParentName then
begin
if bolSameParent then
begin
ComponentList.Move(i, j);
Break;
end
end
else begin
if PiComponent.Top begin
ComponentList.Move(i, j);
Break;
end
else begin
if PiComponent.Top = PjComponent.Top then
begin
if PiComponent.Left begin
ComponentList.Move(i, j);
Break;
end
end;
end;
bolSameParent := True;
end;
end;
end;
end;
end.
( A little history about the unit: After I have finished my component TCcTab that translate Enter to Tab, I found to adjust tab order of a form manually cost me many time. If a program sort it, I can do little work. So I ask Hong Liang (English name LightHong) to write it, he does it. When I ask him to paste some articles in here, he said it's too difficult for him to write articles in English. So I do it.
Hong Liang is very good at Component writing, Database, MIDAS, Open Tools API, you can connect it with lighthong@sina.com)