实现窗体自适应调整尺寸以适应不同屏幕分辩率

本文介绍了一种窗体自适应屏幕分辨率的方法,通过继承特定基类实现不同分辨率下的界面元素自动调整。适用于Delphi等环境。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面包括两个类,一个是普通窗体类,一个是其子类对话框型窗体类。在实际应用过程中只要自己创建的窗体类继承自以上两个类中的一个,例如 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.



                
这是针对access2000所做的自动调整窗体和控件大小的控件,使你的窗口在缩放的时候各控件位置和大小自动调整。这样你的程序即可在640*480分辨率下运行,也可在800*600下运行,而且在任何大小情况下,窗体里的控件都会随着窗体大小而变化,保证你可以看到整个窗体的所有内容。只要改变窗体大小,包括标签、文本框、下拉框、列表框、选项框、检查框、图片、普通子窗体、数据子窗体等控件都会自动按相应的比例实时改变大小。写这个控件的初衷主要是以前在开发VB程序时用到resize的控件,觉得比较好用,而当时找遍所有的资料,都找不到类似针对ACCESS的控件(VB的RESIZE控件在ACCESS中会出现一些奇怪的现象,主要是因为ACCESS窗体的特别结构),而当时我开发的一个项目需要同时适应800*600 和640*480 两种分辨率,所以触发我自己写这方面的程序。经过几次比较大的改动,现在大致可以满足我的需要。一年后,我在网络上找到Ken Getz, Paul Litwin, and Mike Gilbert写的Scale and Resize Your Access Forms演示程序,知道原来在这个世界,还有人与我有同样的想法,他们的功能做得挺棒,只可惜看不到他们的源码。不过知道他们是用API来做的。我比较了两者之间的速度,应该是差不多的。为了让大家了解,我迟点会把他们的演示程序上传。〖accResize1.0〗说明文件一、【主要功能】实现窗口在缩放的时候各控件位置和大小自动调整功能二、文件列表resize.mde 控件缩放的核心代码testresize.mdb 测试缩放效果的例子程序三、〖accResize1.0〗使用方法1. 确保你已经安装了access20002. 将下载的文件用WINRAR解压后放在同一个目录3. 用ACCESS打开(或双击)testresize.mdb,运行其中的窗体文件即可4. 如果你想在你的程序中使用这个功能,只要把resize.mde抄到你的程序目录下,然后打开你的程序,在工具菜单中选择[引用],引用resize.mde即可(你需进入代码状态才能看到工具菜单中的引用子菜单),最后在你自己程序的窗体中的resize事件中加入 resize.Form_myResize Me 这句程序即可。5. 请注意,为了加快窗体缩放的速度,所以程序有个特别注意的地方: 当你在窗体中添加新的控件或改变了位置,需在重新关闭你的程序(即关闭MDB后)再打开才能生效。实际我试过,即使增加新的控件就自动更新,速度亦差不多四、错误反馈1. 如果你发现软件中的错误,欢迎你反馈给作者。五、【使用许可/LICENSE】请仔细阅读以下使用许可,如果您不同意以下任何一点,请立即停止使用此软件。1.〖accResize1.0〗的作者王宇虹授予您对此版本的最终用户使用许可权;2.您不能对软件作任何的软件反向工程,如反汇编,跟踪等;3.您可以分发此软件,但不能收取任何费用或用于商业目的,同时,必须保证所分发的软件包含全部文件,并且不作任何修改;分发的软件应该至少包括我软件所附带的README.txt4.本软件不包含任何使用保证,不能保证适用或不出故障,由于此软件是免费提供,因此作者不对您或别的用户使用此软件所带来的理论上或实际的损失负责;5.如果您用了此软件就等于您同意以上几点许可;6.如果你觉的该软件好用,请发一封Email给作者表示感谢,这些支持将会使作者写出更好软件,谢谢!六、【软件注册费用】完全免费!!本软件所有功能都可以免费使用,完全没有限制。七、【源码费用】如果你对此软件的源码感兴趣,你可以向作者免费索取。你只要发封EMAIL给作者,说明你需要索取这个程序的源码,作者即会把源码EMAIL给你。电子信箱:wang_yu_hong@163.net tmtony@21cn.com你可以到我的主页http://www.zstmcomputer.com 或 http://tmcomputer.6to23.com 免费获得其它完整的应用软件或一些已公开的源码。八、【主要技术】具体请参照
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值