這是個(gè)困惑我很長(zhǎng)時(shí)間的問題,到今天終于得到解決了。
話說Delphi有個(gè)很強(qiáng)的窗體設(shè)計(jì)器,這一點(diǎn)讓VC粉絲垂涎三尺而不可得。但是,Delphi里設(shè)計(jì)的窗體并沒有自動(dòng)適應(yīng)屏幕分辨率的屬性,也就是說,軟件設(shè)計(jì)時(shí)調(diào)整完美的窗體控件布局,在不同屏幕分辨率的機(jī)器上運(yùn)行時(shí)可能會(huì)變得面目全非。控件之間會(huì)相互移位,有的甚至移出窗體再也找不到了。
這個(gè)問題在網(wǎng)上搜索過多次,但大都依據(jù)控件方法ScaleBy或者ChangeScale。采用這兩個(gè)方法進(jìn)行自適應(yīng)調(diào)整,我自己都試過,但效果并不理想。后來我自己也寫了一個(gè)繼承自窗體的基類,覆蓋構(gòu)造函數(shù),調(diào)用自己的一個(gè)設(shè)備分辨率自適應(yīng)方法,該方法遍歷窗體上所有控件,并按照設(shè)計(jì)時(shí)的屏幕分辨率和當(dāng)前屏幕分辨率的比值,逐一計(jì)算控件的位置和尺寸。這個(gè)想法是不錯(cuò),效果也是有的,比單純的采用ScaleBy或者ChangeScale方法要好,但也不是非常理想,沒有達(dá)到自己設(shè)想的要求。原因在哪里,一直不知道。
我原來的代碼曾經(jīng)發(fā)布在Delphi盒子和CSDN上。
這個(gè)問題今天終于得以徹底解決了??!
原因是,我原以為將所有控件的Align屬性設(shè)為alnone,Anchors屬性設(shè)為空[],控件位置和尺寸就不會(huì)受其容器尺寸改變的影響。今天我在設(shè)計(jì)期對(duì)此進(jìn)行試驗(yàn)時(shí),發(fā)現(xiàn)不是這樣。當(dāng)窗體大小改變的時(shí)候,即使某個(gè)控件的Align:=alNone,Anchors:=[],它依然會(huì)隨著窗體尺度的變化而變化。這意味著我需要一個(gè)數(shù)組事先保存所有控件的原始位置和尺寸。在窗體因?yàn)槠聊环直媛实母淖兌詣?dòng)調(diào)整時(shí),計(jì)算的依據(jù)依然是不變的原始窗體位置尺寸數(shù)據(jù),這樣問題就解決了。
閑話少說,上源碼。
unit uMyClassHelpers;
interface
Uses
SysUtils,Windows,Classes,Graphics, Controls,Forms,Dialogs,
uMySysUtils;
Const //記錄設(shè)計(jì)時(shí)的屏幕分辨率
OriWidth=1366;
OriHeight=768;
Type
TfmForm=Class(TForm) //實(shí)現(xiàn)窗體屏幕分辨率的自動(dòng)調(diào)整
Private
fScrResolutionRateW: Double;
fScrResolutionRateH: Double;
fIsFitDeviceDone: Boolean;
fPosition:Array of TRect;
procedure FitDeviceResolution;
Protected
Property IsFitDeviceDone:Boolean Read fIsFitDeviceDone;
Property ScrResolutionRateH:Double Read fScrResolutionRateH;
Property ScrResolutionRateW:Double Read fScrResolutionRateW;
Public
Constructor Create(AOwner: TComponent); Override;
End;
TfdForm=Class(TfmForm) //增加對(duì)話框窗體的修改確認(rèn)
Protected
fIsDlgChange:Boolean;
Public
Constructor Create(AOwner: TComponent); Override;
Property IsDlgChange:Boolean Read fIsDlgChange default false;
End;
implementation
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
i:Integer;
LocList:TList;
LocFontSize:Integer;
LocFont:TFont;
LocCmp:TComponent;
LocFontRate:Double;
LocRect:TRect;
LocCtl:TControl;
begin
LocList:=TList.Create;
Try
Try
if (Screen.width<>OriWidth)OR(Screen.Height<>OriHeight) then
begin
Self.Scaled:=False;
fScrResolutionRateH:=screen.height/OriHeight;
fScrResolutionRateW:=screen.Width/OriWidth;
Try
if fScrResolutionRateH<fScrResolutionRateW then
LocFontRate:=fScrResolutionRateH
Else
LocFontRate:=fScrResolutionRateW;
Finally
ReleaseDC(0, GetDc(0));
End;
For i:=Self.ComponentCount-1 Downto 0 Do
Begin
LocCmp:=Self.Components[i];
If LocCmp Is TControl Then
LocList.Add(LocCmp);
If PropertyExists(LocCmp,'FONT') Then
Begin
LocFont:=TFont(GetObjectProperty(LocCmp,'FONT'));
LocFontSize := Round(LocFontRate*LocFont.Size);
LocFont.Size:=LocFontSize;
End;
End;
SetLength(fPosition,LocList.Count+1);
For i:=0 to LocList.Count-1 Do
With TControl(LocList.Items[i])Do
fPosition[i+1]:=BoundsRect;
fPosition[0]:=Self.BoundsRect;
With LocRect Do
begin
Left:=Round(fPosition[0].Left*fScrResolutionRateW);
Right:=Round(fPosition[0].Right*fScrResolutionRateW);
Top:=Round(fPosition[0].Top*fScrResolutionRateH);
Bottom:=Round(fPosition[0].Bottom*fScrResolutionRateH);
Self.SetBounds(Left,Top,Right-Left,Bottom-Top);
end;
i:= LocList.Count-1;
While (i>=0) Do
Begin
LocCtl:=TControl(LocList.Items[i]);
If LocCtl.Align=alClient Then
begin
Dec(i);
Continue;
end;
With LocRect Do
begin
Left:=Round(fPosition[i+1].Left*fScrResolutionRateW);
Right:=Round(fPosition[i+1].Right*fScrResolutionRateW);
Top:=Round(fPosition[i+1].Top*fScrResolutionRateH);
Bottom:=Round(fPosition[i+1].Bottom*fScrResolutionRateH);
LocCtl.SetBounds(Left,Top,Right-Left,Bottom-Top);
end;
Dec(i);
End;
End;
Except on E:Exception Do
Raise Exception.Create('進(jìn)行屏幕分辨率自適應(yīng)調(diào)整時(shí)出現(xiàn)錯(cuò)誤'+E.Message);
End;
Finally
LocList.Free;
End;
end;
{ TfdForm }
constructor TfdForm.Create(AOwner: TComponent);
begin
inherited;
fIsDlgChange:=False;
end;
end.
上面包括兩個(gè)類,一個(gè)是普通窗體類,一個(gè)是其子類對(duì)話框型窗體類。在實(shí)際應(yīng)用過程中只要自己創(chuàng)建的窗體類繼承自以上兩個(gè)類中的一個(gè),例如 TForm1 = class(TfdForm),則不需添加任何源碼,設(shè)計(jì)出窗體會(huì)自動(dòng)調(diào)整其上控件的尺寸,以適應(yīng)不同的屏幕分辨率。
以上源碼經(jīng)過驗(yàn)證,效果非常好,解決了一個(gè)多年未決的問題!
聯(lián)系客服