使对话框与“大字体”兼容。 [复制]

Posted

技术标签:

【中文标题】使对话框与“大字体”兼容。 [复制]【英文标题】:Make dialogs compatible with "large fonts". [duplicate] 【发布时间】:2011-02-02 21:08:18 【问题描述】:

您认为使 Windows 对话框同时兼容标准字体 (96 dpi) 和“大字体”设置 (120 dpi) 以使对象不会重叠或被截断的最佳做法是什么?

顺便说一句:以防万一,我有兴趣为 Delphi 对话框执行此操作。

提前致谢!

【问题讨论】:

11 个赞,还没有答案!听起来是个好问题。 这个问题有点不具体。回答特定问题会更容易。所以答案的范围也很广。 这个问题的范围也很广。我更喜欢有一个适用于所有情况的解决方案,而不是针对可能无法很好地协同工作的特定问题的多个小解决方案。 The age of the question is irrelevant when deciding something is a duplicate or not. 唯一重要的是问题/答案的质量(在这种情况下,我没有资格对此发表任何评论)。 【参考方案1】:

一般来说,为此目的应该使用布局管理器。这就是它们的设计目的。

Delphi(很长时间没有使用它)没有这样的管理器,但从那时起就能够处理不同的 dpi。您必须使用组件的 autosize 属性来确保它们具有适合所显示文本的大小。为了防止组件重叠,使用对齐和锚属性将它们排列在表单上。最终,您必须将组件分组到容器中以实现正确的布局。

【讨论】:

我认为简短的回答是“这是一个巨大的德尔福弱点”。 XAML 在这方面做得更好。 Java/Swing 在这方面做得更好。坦率地说,其他一切都比德尔福做得更好。即使是像 Glade 这样基于布局管理器的开源软件也能做得更好。 现代 Delphi 版本确实有布局管理组件,至少在 FireMonkey 中:FireMonkey Layouts Strategies。不过,有可用于 VCL 的 3rd 方布局组件。【参考方案2】:

在“Considerations When Dynamically Resizing Forms and Controls”下的 D2007 帮助文件中有一篇很好的文章(请注意,该 URL 指向帮助文件本身,而不是网页本身)。

可以在D2010 help file(与上面的URL 相同的警告)或docwiki 中找到同名的相同主题。

检查 TForm.Scaled 和 TForm.ScaleBy 也是值得的(至少一点点)。

【讨论】:

【参考方案3】:

这就是我尝试处理 Delphi VCL 的像素的方式,而不管 Window 的字体大小设置如何。

unit App.Screen;

interface

uses Controls;

type
  TAppScreen = class(TObject)
  private
    FDefaultPixelsPerInch: integer;
    FPixelsPerInch: integer;
    function GetPixelsPerInch: integer;
    procedure SetPixelsPerInch(const Value: integer);
  public
    procedure AfterConstruction; override;
    function DefaultPixelsPerInch: integer;
    function InAcceptableRange(const aPPI: integer): boolean;
    procedure ScaleControl(const aControl: TWinControl);
    property PixelsPerInch: integer read GetPixelsPerInch write SetPixelsPerInch;
  end;

  TAppScreenHelper = class helper for TAppScreen
  private
    class var FInstance: TAppScreen;
    class function GetInstance: TAppScreen; static;
  public
    class procedure Setup;
    class procedure TearDown;
    class property Instance: TAppScreen read GetInstance;
  end;

implementation

uses
  TypInfo, Windows, SysUtils, Forms, Graphics;

type
  TScreenEx = class(TScreen)
  published
    property PixelsPerInch;
  end;

  TScreenHelper = class helper for TScreen
  public
    procedure SetPixelsPerInch(Value: integer);
  end;

procedure TScreenHelper.SetPixelsPerInch(Value: integer);
begin
  PInteger(Integer(Self) + (Integer(GetPropInfo(TScreenEx, 'PixelsPerInch').GetProc) and $00FFFFFF))^ := Value;
end;

procedure TAppScreen.AfterConstruction;
begin
  inherited;
  FDefaultPixelsPerInch := Screen.PixelsPerInch;
  FPixelsPerInch := FDefaultPixelsPerInch;
end;

function TAppScreen.DefaultPixelsPerInch: integer;
begin
  Result := FDefaultPixelsPerInch;
end;

function TAppScreen.GetPixelsPerInch: integer;
begin
  Result := FPixelsPerInch;
end;

function TAppScreen.InAcceptableRange(const aPPI: integer): boolean;
begin
  if DefaultPixelsPerInch > aPPI then
    Result := DefaultPixelsPerInch * 0.55 < aPPI
  else if DefaultPixelsPerInch < aPPI then
    Result := DefaultPixelsPerInch * 1.55 > aPPI
  else
    Result := True;
end;

procedure TAppScreen.ScaleControl(const aControl: TWinControl);
begin
  aControl.ScaleBy(PixelsPerInch, DefaultPixelsPerInch);
end;

procedure TAppScreen.SetPixelsPerInch(const Value: integer);
begin
  FPixelsPerInch := Value;
  Screen.SetPixelsPerInch(FPixelsPerInch);
end;

class function TAppScreenHelper.GetInstance: TAppScreen;
begin
  if FInstance = nil then
    FInstance := TAppScreen.Create;
  Result := FInstance;
end;

class procedure TAppScreenHelper.Setup;
begin
  TAppScreen.Instance;
end;

class procedure TAppScreenHelper.TearDown;
begin
  FInstance.Free;
  FInstance := nil;
end;

initialization
  TAppScreen.Setup;
finalization
  TAppScreen.TearDown;
end.

尝试以下测试不同像素值的效果:

TAppScreen.Instance.PixelsPerInch := 120;
TAppScreen.Instance.PixelsPerInch := 96;
TAppScreen.Instance.PixelsPerInch := 150;

您应该在实例化 TForm 的后代(包括 Delphi 的 VCL 对话框)之前更改 PixelsPerInch。

【讨论】:

你为什么要为你自己的TAppScreen 类使用class helper?所有class 成员都应该在TAppScreen 类本身中。根本不需要为TAppScreen 使用class helper。至于访问TScreen.FPixelsPerInch 成员,请考虑通过System.Rtti 单元使用增强型RTTI,它可以访问私有和公共字段,而不仅仅是来自TypInfo 单元的传统RTTI 等已发布属性。【参考方案4】: 切勿将控件及其描述标签并排放置,始终将标签放在其顶部。

但除此之外呢?也许:

在标签的右侧和底部留出足够的空间,以便在使用大字体时它们不会与其他控件重叠。

我从未尝试在那种情况下使用 TLabeledEdit,也许他们会自动这样做?

【讨论】:

【参考方案5】:

据称有商业解决方案(Developer Express VCL 布局管理器)。但我不相信他们中的任何一个。我怀疑 Embarcadero 应该将此作为当前 UI 组件集 (VCL) 中的一个关键弱点来解决。

我认为第三方组件集可能是您目前最快的解决方案。它是商业的,但并不昂贵。

http://www.devexpress.com/products/VCL/ExLayoutControl/

【讨论】:

现代 Delphi 版本是否已经支持这个主题? (XE 及以上) 不适用于高 DPI 显示器,这是根本问题,“大字体尺寸”实际上意味着高于 96 DPI 显示器,以及微软使用的“DPI hack”(假 DPI 放大字体)。

以上是关于使对话框与“大字体”兼容。 [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何使底部工作表对话框的角变圆? [复制]

nsis error解决方法

如何使 jquery 对话框与 themeroller 主题一起使用?

我开QQ时总弹出一个对话框,说啥无法定位程序输入点。怎么回事??

如何解决tcs2010与wps2019不兼容的问题

MFC学习笔记3---使对话框风格与系统统一