下面包括两个类,一个是普通窗体类,一个是其子类对话框型窗体类。在实际应用过程中只要自己创建的窗体类继承自以上两个类中的一个,例如 TForm1 = class(TfdForm),则不需添加任何源码,设计出窗体会自动调整其上控件的尺寸,以适应不同的屏幕分辨率。
经测试代码可用!uMyClassHelpers
unit uMyClassHelpers;
{实现窗体自适应调整尺寸以适应不同屏幕分辩率的显示问题。
陈小斌,2012年3月5日
使用时,主窗体直接继承TfdForm Tform1=class(TfdForm)
或TfmForm Tform1=class(TfmForm)即可
-----haiou327测试 }
interface
uses
SysUtils, Windows, Classes, Graphics, Controls, Forms, Dialogs, Math,
TypInfo;
const //记录设计时的屏幕分辨率
OriWidth = 1024;
OriHeight = 768;
type
TfmForm = class(TForm) //实现窗体屏幕分辨率的自动调整
private
fScrResolutionRateW: Double;
fScrResolutionRateH: Double;
fIsFitDeviceDone: Boolean;
procedure FitDeviceResolution;
protected
property IsFitDeviceDone: Boolean read fIsFitDeviceDone;
property ScrResolutionRateH: Double read fScrResolutionRateH;
property ScrResolutionRateW: Double read fScrResolutionRateW;
public
constructor Create(AOwner: TComponent); override;
function PropertyExists(const AObject: TObject;const APropName:String):Boolean;
function GetObjectProperty(
const AObject : TObject;
const APropName : string
):TObject;
end;
TfdForm = class(TfmForm) //增加对话框窗体的修改确认
protected
fIsDlgChange: Boolean;
public
constructor Create(AOwner: TComponent); override;
property IsDlgChange: Boolean read fIsDlgChange default false;
end;
implementation
function TfmForm.PropertyExists(const AObject: TObject;const APropName:String):Boolean;
//判断一个属性是否存在
var
PropInfo:PPropInfo;
begin
PropInfo:=GetPropInfo(AObject.ClassInfo,APropName);
Result:=Assigned(PropInfo);
end;
function TfmForm.GetObjectProperty(
const AObject : TObject;
const APropName : string
):TObject;
var
PropInfo:PPropInfo;
begin
Result := nil;
PropInfo:=GetPropInfo(AObject.ClassInfo,APropName);
if Assigned(PropInfo) and
(PropInfo^.PropType^.Kind = tkClass) then
Result := GetObjectProp(AObject,PropInfo);
end;
constructor TfmForm.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fScrResolutionRateH := 1;
fScrResolutionRateW := 1;
try
if not fIsFitDeviceDone then
begin
FitDeviceResolution;
fIsFitDeviceDone := True;
end;
except
fIsFitDeviceDone := False;
end;
end;
procedure TfmForm.FitDeviceResolution;
var
LocList: TList;
LocFontRate: Double;
LocFontSize: Integer;
LocFont: TFont;
locK: Integer;
{计算尺度调整的基本参数}
procedure CalBasicScalePars;
begin
try
Self.Scaled := False;
fScrResolutionRateH := screen.height / OriHeight;
fScrResolutionRateW := screen.Width / OriWidth;
LocFontRate := Min(fScrResolutionRateH, fScrResolutionRateW);
except
raise;
end;
end;
{保存原有坐标位置:利用递归法遍历各级容器里的控件,直到最后一级}
procedure ControlsPostoList(vCtl: TControl; vList: TList);
var
locPRect: ^TRect;
i: Integer;
locCtl: TControl;
locFontp: ^Integer;
begin
try
New(locPRect);
locPRect^ := vCtl.BoundsRect;
vList.Add(locPRect);
if PropertyExists(vCtl, 'FONT') then
begin
LocFont := TFont(GetObjectProperty(vCtl, 'FONT'));
New(locFontp);
locFontP^ := LocFont.Size;
vList.Add(locFontP);
// ShowMessage(vCtl.Name+'Ori:='+InttoStr(LocFont.Size));
end;
if vCtl is TWinControl then
for i := 0 to TWinControl(vCtl).ControlCount - 1 do
begin
locCtl := TWinControl(vCtl).Controls[i];
ControlsPosToList(locCtl, vList);
end;
except
raise;
end;
end;
{计算新的坐标位置:利用递归法遍历各级容器里的控件,直到最后一层。
计算坐标时先计算顶级容器级的,然后逐级递进}
procedure AdjustControlsScale(vCtl: TControl; vList: TList; var vK: Integer);
var
locOriRect, LocNewRect: TRect;
i: Integer;
locCtl: TControl;
begin
try
if vCtl.Align <> alClient then
begin
locOriRect := TRect(vList.Items[vK]^);
with locNewRect do
begin
Left := Round(locOriRect.Left * fScrResolutionRateW);
Right := Round(locOriRect.Right * fScrResolutionRateW);
Top := Round(locOriRect.Top * fScrResolutionRateH);
Bottom := Round(locOriRect.Bottom * fScrResolutionRateH);
vCtl.SetBounds(Left, Top, Right - Left, Bottom - Top);
end;
end;
if PropertyExists(vCtl, 'FONT') then
begin
Inc(vK);
LocFont := TFont(GetObjectProperty(vCtl, 'FONT'));
locFontSize := Integer(vList.Items[vK]^);
LocFont.Size := Round(LocFontRate * locFontSize);
// ShowMessage(vCtl.Name+'New:='+InttoStr(LocFont.Size));
end;
Inc(vK);
if vCtl is TWinControl then
for i := 0 to TwinControl(vCtl).ControlCount - 1 do
begin
locCtl := TWinControl(vCtl).Controls[i];
AdjustControlsScale(locCtl, vList, vK);
end;
except
raise;
end;
end;
{释放坐标位置指针和列表对象}
procedure FreeListItem(vList: TList);
var
i: Integer;
begin
for i := 0 to vList.Count - 1 do
Dispose(vList.Items[i]);
vList.Free;
end;
begin
LocList := TList.Create;
try
try
if (Screen.width <> OriWidth) or (Screen.Height <> OriHeight) then
begin
CalBasicScalePars;
// AdjustComponentFont(Self);
ControlsPostoList(Self, locList);
locK := 0;
AdjustControlsScale(Self, locList, locK);
end;
except on E: Exception do
raise Exception.Create('进行屏幕分辨率自适应调整时出现错误' + E.Message);
end;
finally
FreeListItem(locList);
end;
end;
{ TfdForm }
constructor TfdForm.Create(AOwner: TComponent);
begin
inherited;
fIsDlgChange := False;
end;
end.