Каковы, по вашему мнению, лучшие методы для создания диалогового окна Windows, совместимого со стандартными шрифтами (96 dpi) и "большими шрифтами" (120 dpi), чтобы объекты не перекрывались или не обрезались?
BTW: На всякий случай это актуально, я заинтересован в том, чтобы делать это для диалогов Delphi.
Спасибо заранее!
В файле справки 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, включая диалоги Delphi VCL.
class helper
для своего собственного класса TAppScreen
? Все члены class
должны быть в TAppScreen
классе TAppScreen
. Нет необходимости использовать class helper
для TAppScreen
вообще. Что касается получения доступа к TScreen.FPixelsPerInch
, рассмотрите возможность использования расширенного RTTI через модуль System.Rtti
, который может получать доступ к закрытым и общедоступным полям, а не только к опубликованным свойствам, таким как Legacy RTTI из TypInfo
.
Существуют коммерческие решения (Developer Express VCL Layout Manager). Но я не доверяю никому из них. Я подозреваю, что Embarcadero должен рассматривать это как критическую слабость в текущем наборе компонентов пользовательского интерфейса (VCL).
Я думаю, что сторонний набор компонентов может быть вашим самым быстрым решением прямо сейчас. Это коммерчески, но не очень дорого.
Но кроме этого? Может быть:
Я никогда не пробовал использовать TLabeledEdit в этом сценарии, возможно, они это делают автоматически?