Сделайте диалоги совместимыми с "большими шрифтами".

Каковы, на ваш взгляд, наилучшие практики для того, чтобы сделать диалог окон совместимым как со стандартными шрифтами (96 точек на дюйм), так и с настройкой "больших шрифтов" (120 точек на дюйм), чтобы объекты не перекрывались и не обрезались?

Кстати: на всякий случай, если это актуально, мне интересно сделать это для диалогов Delphi.

Заранее спасибо!

5 ответов

Решение

В файле справки D2007 есть довольно хорошая статья в разделе " Соображения при динамическом изменении размеров форм и элементов управления" (обратите внимание, что URL-адрес относится к самому файлу справки, а не к веб-странице как таковой).

Эту же тему под тем же именем можно найти в файле справки D2010 (то же самое относится к URL, как указано выше) или в docwiki.

Также стоит (хотя бы чуть-чуть) изучить TForm.Scaled и TForm.ScaleBy.

В общем случае для этой цели следует использовать менеджеры компоновки. Вот для чего они предназначены.

Delphi (долгое время не работал с ним) не имеет таких менеджеров, но с тех пор может обрабатывать различные dpi. Вы должны использовать свойство autosize для компонентов, чтобы гарантировать, что они имеют правильный размер для текста, который они отображают. Чтобы предотвратить наложение компонентов, расположите их в форме, используя свойства выравнивания и привязки. В конце концов, вам нужно сгруппировать компоненты в контейнеры, чтобы получить правильное расположение.

Вот как я пытаюсь работать с пикселями 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;

Вы должны изменить PixelsPerInch перед созданием экземпляра потомка TForm, включая диалоги VCL Delphi.

  • Никогда не помещайте элемент управления и его описание рядом друг с другом, всегда помещайте ярлык поверх него.

Но кроме этого? Может быть:

  • Оставьте достаточно места справа и снизу надписей, чтобы они не перекрывались с другими элементами управления при использовании больших шрифтов.

Я никогда не пытался использовать TLabeledEdit в этом сценарии, может быть, они делают это автоматически?

Существуют предполагаемые коммерческие решения (Developer Express VCL Layout Manager). Но я не доверяю ни одному из них. Я подозреваю, что Embarcadero должен рассматривать это как критический недостаток в текущем наборе компонентов пользовательского интерфейса (VCL).

Я думаю, что сторонний набор компонентов может быть вашим самым быстрым решением прямо сейчас. Это коммерческий, но не очень дорогой.

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

Другие вопросы по тегам