webentwicklung-frage-antwort-db.com.de

Wie stelle ich sicher, dass sich meine GUI gut verhält, wenn die Windows-Schriftgröße über 100% liegt?

Bei der Auswahl großer Schriftgrößen in der Windows-Systemsteuerung (z. B. 125% oder 150%) treten in einer VCL-Anwendung jedes Mal Probleme auf, wenn etwas pixelweise festgelegt wurde.

Nehmen Sie die TStatusBar.Panel. Ich habe die Breite so eingestellt, dass sie genau ein Etikett enthält, bei großen Schriften läuft das Etikett "über". Gleiches Problem mit anderen Komponenten.

Einige neue Laptops von Dell werden bereits mit einer Standardeinstellung von 125% ausgeliefert. In der Vergangenheit war dieses Problem also recht selten, jetzt ist es wirklich wichtig.

Was kann getan werden, um dieses Problem zu überwinden?

105
LaBracca

Ihre Einstellungen in der .dfm-Datei werden korrekt skaliert, solange ScaledTrue ist.

Wenn Sie Bemaßungen im Code festlegen, müssen Sie diese durch Screen.PixelsPerInch Geteilt durch Form.PixelsPerInch Skalieren. Verwenden Sie dazu MulDiv.

function TMyForm.ScaleDimension(const X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, PixelsPerInch);
end;

Dies ist, was das Formular-Persistenz-Framework macht, wenn ScaledTrue ist.

Tatsächlich können Sie ein schlüssiges Argument für das Ersetzen dieser Funktion durch eine Version angeben, die einen Wert von 96 für den Nenner fest codiert. Auf diese Weise können Sie absolute Bemaßungswerte verwenden und müssen sich keine Gedanken über die Änderung der Bedeutung machen, wenn Sie die Schriftskalierung auf Ihrem Entwicklungscomputer ändern und die .dfm-Datei erneut speichern. Der Grund dafür ist, dass die in der .dfm-Datei gespeicherte Eigenschaft PixelsPerInch der Wert des Computers ist, auf dem die .dfm-Datei zuletzt gespeichert wurde.

const
  SmallFontsPixelsPerInch = 96;

function ScaleFromSmallFontsDimension(const X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, SmallFontsPixelsPerInch);
end;

Wenn Sie mit dem Thema fortfahren, sollten Sie auch bedenken, dass bei der Entwicklung Ihres Projekts auf mehreren Computern mit unterschiedlichen DPI-Werten die Skalierung, die Delphi beim Speichern von .dfm-Dateien verwendet, dazu führt, dass Steuerelemente über eine Reihe von Bearbeitungen wandern . Um dies zu vermeiden, haben wir an meinem Arbeitsplatz die strikte Richtlinie, dass Formulare immer nur mit 96 dpi (100% Skalierung) bearbeitet werden.

Tatsächlich berücksichtigt meine Version von ScaleFromSmallFontsDimension auch die Möglichkeit, dass sich die Formularschrift zur Laufzeit von der zur Entwurfszeit festgelegten unterscheidet. Auf XP Maschinen, auf denen die Formulare meiner Anwendung 8pt Tahoma verwenden. Unter Vista und höher wird 9pt Segoe UI verwendet. Dies bietet einen weiteren Freiheitsgrad. Die Skalierung muss dies berücksichtigen, da die absoluten Dimensionswerte in verwendet werden Es wird angenommen, dass der Quellcode relativ zur Basislinie von 8pt Tahoma bei 96 dpi ist.

Wenn Sie Bilder oder Glyphen in Ihrer Benutzeroberfläche verwenden, müssen diese ebenfalls skaliert werden. Ein häufiges Beispiel sind die Glyphen, die in Symbolleisten und Menüs verwendet werden. Sie möchten diese Glyphen als Symbolressourcen bereitstellen, die mit Ihrer ausführbaren Datei verknüpft sind. Jedes Symbol sollte eine Reihe von Größen enthalten. Zur Laufzeit wählen Sie die am besten geeignete Größe aus und laden sie in eine Bilderliste. Einige Details zu diesem Thema finden Sie hier: Wie lade ich Symbole aus einer Ressource, ohne unter Aliasing zu leiden?

Ein weiterer nützlicher Trick ist das Definieren von Dimensionen in relativen Einheiten relativ zu TextWidth oder TextHeight. Wenn Sie also eine Größe von ungefähr 10 vertikalen Linien wünschen, können Sie 10*Canvas.TextHeight('Ag') verwenden. Dies ist eine sehr grobe und fertige Metrik, da sie keinen Zeilenabstand usw. zulässt. Oft müssen Sie jedoch nur dafür sorgen, dass die GUI mit PixelsPerInch richtig skaliert.

Sie sollten Ihre Anwendung auch als mit hoher DPI kennzeichnen. Dies erreichen Sie am besten über das Anwendungsmanifest. Da Sie mit den Build-Tools von Delphi das Manifest nicht anpassen können, müssen Sie Ihre eigene Manifest-Ressource verknüpfen.

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<Assembly xmlns="urn:schemas-Microsoft-com:asm.v1" manifestVersion="1.0">
  <asmv3:application xmlns:asmv3="urn:schemas-Microsoft-com:asm.v3">
    <asmv3:windowsSettings
         xmlns="http://schemas.Microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</Assembly>

Das Ressourcenskript sieht folgendermaßen aus:

1 24 "Manifest.txt"

wobei Manifest.txt das aktuelle Manifest enthält. Sie müssten auch den Abschnitt comctl32 v6 einschließen und requestedExecutionLevel auf asInvoker setzen. Anschließend verknüpfen Sie diese kompilierte Ressource mit Ihrer App und stellen sicher, dass Delphi nicht versucht, dasselbe mit seinem Manifest zu tun. In modernen Delphi erreichen Sie dies, indem Sie die Projektoption Runtime Themes auf None setzen.

Das Manifest ist der right Weg, um Ihre App als hoch DPI-fähig zu deklarieren. Wenn Sie es nur schnell ausprobieren möchten, ohne Ihr Manifest zu verfälschen, rufen Sie SetProcessDPIAware auf. Tun Sie dies als erstes, wenn Ihre App ausgeführt wird. Am besten in einem der frühen Abschnitte zur Geräteinitialisierung oder als erstes in Ihrer .dpr-Datei.

Wenn Sie Ihre App nicht als hoch dpi-fähig deklarieren, wird sie von Vista und höher in einem Legacy-Modus für Schriftarten mit einer Skalierung von mehr als 125% gerendert. Das sieht ziemlich schrecklich aus. Versuche zu vermeiden, in diese Falle zu tappen.

DPI-Update für Windows 8.1 pro Monitor

Ab Windows 8.1 werden DPI-Einstellungen für jeden Monitor unterstützt ( http://msdn.Microsoft.com/en-ca/magazine/dn574798.aspx ). Dies ist ein großes Problem für moderne Geräte, an die möglicherweise unterschiedliche Displays mit sehr unterschiedlichen Funktionen angeschlossen sind. Möglicherweise haben Sie einen Laptop-Bildschirm mit sehr hohen DPI-Werten und einen externen Projektor mit niedrigen DPI-Werten. Die Unterstützung eines solchen Szenarios erfordert noch mehr Arbeit als oben beschrieben.

61
David Heffernan

Es ist auch wichtig zu beachten, dass das Einhalten der DPI des Benutzers nur eine Teilmenge Ihres eigentlichen Auftrags ist:

berücksichtigung der Schriftgröße des Benutzers

Seit Jahrzehnten löst Windows dieses Problem, indem der Begriff Layout mit Dialog Units und nicht mit Pixeln ausgeführt wird. Eine "Dialogeinheit" ist so definiert, dass das durchschnittliche Zeichen der Schrift ist

  • 4 Dialogeinheiten (dlus) breit und
  • 8 Dialogeinheiten (Clus) hoch

enter image description here

Delphi wird mit einer (fehlerhaften) Version von Scaled ausgeliefert, bei der ein Formular versucht, sich automatisch basierend auf dem anzupassen

  • Windows DPI-Einstellungen des Benutzers, Verse
  • die DPI-Einstellung auf dem Computer des Entwicklers, der das Formular zuletzt gespeichert hat

Dies löst das Problem nicht, wenn der Benutzer eine andere Schriftart verwendet als die, mit der Sie das Formular erstellt haben, z.

  • entwickler entwarf das Formular mit MS Sans Serif 8pt (wobei das durchschnittliche Zeichen 6.21px x 13.00px ist, bei 96 dpi)
  • benutzer läuft mit Tahoma 8pt (wobei das durchschnittliche Zeichen 5.94px x 13.00px ist, bei 96 dpi)

    Wie bei jedem, der eine Anwendung für Windows 2000 oder Windows XP entwickelt.

oder

  • entwickler entwarf das Formular mit ** Tahoma 8pt * (wobei das durchschnittliche Zeichen 5.94px x 13.00px ist, bei 96 dpi)
  • ein Benutzer mit Segoe UI 9pt (wobei das durchschnittliche Zeichen 6.67px x 15px bei 96 dpi ist)

Als guter Entwickler werden Sie die Schrifteinstellungen Ihres Benutzers berücksichtigen. Dies bedeutet, dass Sie auch alle Steuerelemente in Ihrem Formular so skalieren müssen, dass sie der neuen Schriftgröße entsprechen:

  • alles horizontal um 12,29% erweitern (6,67/5,94)
  • strecke alles vertikal um 15.38% (15/13)

Scaled wird dies nicht für Sie erledigen.

Es wird schlimmer, wenn:

  • gestalten Sie Ihr Formular unter Segoe UI 9pt (Windows Vista, Windows 7, Windows 8-Standard)
  • der Benutzer führt Segoe UI 14pt aus (z. B. meine Präferenz). Dies ist 10.52px x 25px.

Jetzt muss man alles skalieren

  • horizontal um 57,72%
  • vertikal um 66,66%

Scaled wird dies nicht für Sie erledigen.


Wenn Sie schlau sind, können Sie sehen, wie irrelavent es ist, DPI zu ehren:

  • formular mit Segoe UI 9pt bei 96 dpi (6,67 x 15 Pixel)
  • benutzer, der mit Segoe UI 9pt @ 150dpi (10,52 x 25 Pixel) arbeitet

Sie sollten sich nicht die DPI-Einstellung des Benutzers ansehen, sondern die Schriftgröße . Zwei Benutzer laufen

  • Segoe UI 14pt bei 96 dpi (10,52 x 25 Pixel)
  • Segoe UI 9pt bei 150 dpi (10,52 x 25 Pixel)

verwenden dieselbe Schriftart . DPI ist nur eine Sache, die die Schriftgröße beeinflusst; die Vorlieben des Benutzers sind die anderen.

StandardizeFormFont

Clovis bemerkte, dass ich auf eine Funktion StandardizeFormFont verweise, die die Schriftart in einem Formular festlegt und sie auf die neue Schriftgröße skaliert. Es ist keine Standardfunktion, sondern eine ganze Reihe von Funktionen, die die einfache Aufgabe erfüllen, die Borland nie bewältigt hat.

function StandardizeFormFont(AForm: TForm): Real;
var
    preferredFontName: string;
    preferredFontHeight: Integer;
begin
    GetUserFontPreference({out}preferredFontName, {out}preferredFontHeight);

    //e.g. "Segoe UI",     
    Result := Toolkit.StandardizeFormFont(AForm, PreferredFontName, PreferredFontHeight);
end;

Windows hat 6 verschiedene Schriftarten; In Windows gibt es keine einzige "Schrifteinstellung".
Wir wissen jedoch aus Erfahrung, dass unsere Formulare der Einstellung Icon Title Font folgen sollten

procedure GetUserFontPreference(out FaceName: string; out PixelHeight: Integer);
var
   font: TFont;
begin
   font := Toolkit.GetIconTitleFont;
   try
      FaceName := font.Name; //e.g. "Segoe UI"

      //Dogfood testing: use a larger font than we're used to; to force us to actually test it    
      if IsDebuggerPresent then
         font.Size := font.Size+1;

      PixelHeight := font.Height; //e.g. -16
   finally
      font.Free;
   end;
end;

Sobald wir die Schriftgröße kennen, skalieren wir das Formular bis, erhalten die aktuelle Schrifthöhe des Formulars (in Pixel) und skalieren um diesen Faktor.

Wenn ich zum Beispiel das Formular auf -16 setze und das Formular derzeit auf -11 steht, müssen wir das skalieren gesamte Form von:

-16 / -11 = 1.45454%

Die Standardisierung erfolgt in zwei Phasen. Skalieren Sie zunächst das Formular nach dem Verhältnis der neuen zu den alten Schriftgrößen. Ändern Sie dann tatsächlich die Steuerelemente (rekursiv), um die neue Schriftart zu verwenden.

function StandardizeFormFont(AForm: TForm; FontName: string; FontHeight: Integer): Real;
var
    oldHeight: Integer;
begin
    Assert(Assigned(AForm));

    if (AForm.Scaled) then
    begin
        OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to Scaled. Proper form scaling requires VCL scaling to be disabled, unless you implement scaling by overriding the protected ChangeScale() method of the form.'));
    end;

    if (AForm.AutoScroll) then
    begin
        if AForm.WindowState = wsNormal then
        begin
            OutputDebugString(PChar('WARNING: StandardizeFormFont: Form "'+GetControlName(AForm)+'" is set to AutoScroll. Form designed size will be suseptable to changes in Windows form caption height (e.g. 2000 vs XP).'));
                    if IsDebuggerPresent then
                        Windows.DebugBreak; //Some forms would like it (to fix maximizing problem)
        end;
    end;

    if (not AForm.ShowHint) then
    begin
        AForm.ShowHint := True;
        OutputDebugString(PChar('INFORMATION: StandardizeFormFont: Turning on form "'+GetControlName(AForm)+'" hints. (ShowHint := True)'));
                    if IsDebuggerPresent then
                        Windows.DebugBreak; //Some forms would like it (to fix maximizing problem)
    end;

    oldHeight := AForm.Font.Height;

    //Scale the form to the new font size
//  if (FontHeight <> oldHeight) then    For compatibility, it's safer to trigger a call to ChangeScale, since a lot of people will be assuming it always is called
    begin
        ScaleForm(AForm, FontHeight, oldHeight);
    end;

    //Now change all controls to actually use the new font
    Toolkit.StandardizeFont_ControlCore(AForm, g_ForceClearType, FontName, FontHeight,
            AForm.Font.Name, AForm.Font.Size);

    //Return the scaling ratio, so any hard-coded values can be multiplied
    Result := FontHeight / oldHeight;
end;

Hier ist die Aufgabe, ein Formular tatsächlich zu skalieren. Es geht um Fehler in Borlands eigener Form.ScaleBy - Methode. Zuerst müssen alle Anker im Formular deaktiviert, dann die Skalierung durchgeführt und dann die Anker wieder aktiviert werden:

TAnchorsArray = array of TAnchors;

procedure ScaleForm(const AForm: TForm; const M, D: Integer);
var
    aAnchorStorage: TAnchorsArray;
    RectBefore, RectAfter: TRect;
    x, y: Integer;
    monitorInfo: TMonitorInfo;
    workArea: TRect;
begin
    if (M = 0) and (D = 0) then
        Exit;

    RectBefore := AForm.BoundsRect;

    SetLength(aAnchorStorage, 0);
    aAnchorStorage := DisableAnchors(AForm);
    try
        AForm.ScaleBy(M, D);
    finally
        EnableAnchors(AForm, aAnchorStorage);
    end;

    RectAfter := AForm.BoundsRect;

    case AForm.Position of
    poScreenCenter, poDesktopCenter, poMainFormCenter, poOwnerFormCenter,
    poDesigned: //i think i really want everything else to also follow the nudging rules...why did i exclude poDesigned
        begin
            //This was only nudging by one quarter the difference, rather than one half the difference
//          x := RectAfter.Left - ((RectAfter.Right-RectBefore.Right) div 2);
//          y := RectAfter.Top - ((RectAfter.Bottom-RectBefore.Bottom) div 2);
            x := RectAfter.Left - ((RectAfter.Right-RectAfter.Left) - (RectBefore.Right-RectBefore.Left)) div 2;
            y := RectAfter.Top - ((RectAfter.Bottom-RectAfter.Top)-(RectBefore.Bottom-RectBefore.Top)) div 2;
        end;
    else
        //poDesigned, poDefault, poDefaultPosOnly, poDefaultSizeOnly:
        x := RectAfter.Left;
        y := RectAfter.Top;
    end;

    if AForm.Monitor <> nil then
    begin
        monitorInfo.cbSize := SizeOf(monitorInfo);
        if GetMonitorInfo(AForm.Monitor.Handle, @monitorInfo) then
            workArea := monitorInfo.rcWork
        else
        begin
            OutputDebugString(PChar(SysErrorMessage(GetLastError)));
            workArea := Rect(AForm.Monitor.Left, AForm.Monitor.Top, AForm.Monitor.Left+AForm.Monitor.Width, AForm.Monitor.Top+AForm.Monitor.Height);
        end;

//      If the form is off the right or bottom of the screen then we need to pull it back
        if RectAfter.Right > workArea.Right then
            x := workArea.Right - (RectAfter.Right-RectAfter.Left); //rightEdge - widthOfForm

        if RectAfter.Bottom > workArea.Bottom then
            y := workArea.Bottom - (RectAfter.Bottom-RectAfter.Top); //bottomEdge - heightOfForm

        x := Max(x, workArea.Left); //don't go beyond left Edge
        y := Max(y, workArea.Top); //don't go above top Edge
    end
    else
    begin
        x := Max(x, 0); //don't go beyond left Edge
        y := Max(y, 0); //don't go above top Edge
    end;

    AForm.SetBounds(x, y,
            RectAfter.Right-RectAfter.Left, //Width
            RectAfter.Bottom-RectAfter.Top); //Height
end;

und dann müssen wir tatsächlich rekursiv verwenden die neue Schriftart:

procedure StandardizeFont_ControlCore(AControl: TControl; ForceClearType: Boolean;
        FontName: string; FontSize: Integer;
        ForceFontIfName: string; ForceFontIfSize: Integer);
const
    CLEARTYPE_QUALITY = 5;
var
    i: Integer;
    RunComponent: TComponent;
    AControlFont: TFont;
begin
    if not Assigned(AControl) then
        Exit;

    if (AControl is TStatusBar) then
    begin
        TStatusBar(AControl).UseSystemFont := False; //force...
        TStatusBar(AControl).UseSystemFont := True;  //...it
    end
    else
    begin
        AControlFont := Toolkit.GetControlFont(AControl);

        if not Assigned(AControlFont) then
            Exit;

        StandardizeFont_ControlFontCore(AControlFont, ForceClearType,
                FontName, FontSize,
                ForceFontIfName, ForceFontIfSize);
    end;

{   If a panel has a toolbar on it, the toolbar won't Paint properly. So this idea won't work.
    if (not Toolkit.IsRemoteSession) and (AControl is TWinControl) and (not (AControl is TToolBar)) then
        TWinControl(AControl).DoubleBuffered := True;
}

    //Iterate children
    for i := 0 to AControl.ComponentCount-1 do
    begin
        RunComponent := AControl.Components[i];
        if RunComponent is TControl then
            StandardizeFont_ControlCore(
                    TControl(RunComponent), ForceClearType,
                    FontName, FontSize,
                    ForceFontIfName, ForceFontIfSize);
    end;
end;

Wenn die Anker rekursiv deaktiviert sind:

function DisableAnchors(ParentControl: TWinControl): TAnchorsArray;
var
    StartingIndex: Integer;
begin
    StartingIndex := 0;
    DisableAnchors_Core(ParentControl, Result, StartingIndex);
end;


procedure DisableAnchors_Core(ParentControl: TWinControl; var aAnchorStorage: TAnchorsArray; var StartingIndex: Integer);
var
    iCounter: integer;
    ChildControl: TControl;
begin
    if (StartingIndex+ParentControl.ControlCount+1) > (Length(aAnchorStorage)) then
        SetLength(aAnchorStorage, StartingIndex+ParentControl.ControlCount+1);

    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        aAnchorStorage[StartingIndex] := ChildControl.Anchors;

        //doesn't work for set of stacked top-aligned panels
//      if ([akRight, akBottom ] * ChildControl.Anchors) <> [] then
//          ChildControl.Anchors := [akLeft, akTop];

        if (ChildControl.Anchors) <> [akTop, akLeft] then
            ChildControl.Anchors := [akLeft, akTop];

//      if ([akTop, akBottom] * ChildControl.Anchors) = [akTop, akBottom] then
//          ChildControl.Anchors := ChildControl.Anchors - [akBottom];

        Inc(StartingIndex);
    end;

    //Add children
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        if ChildControl is TWinControl then
            DisableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex);
    end;
end;

Und Anker werden rekursiv wieder aktiviert:

procedure EnableAnchors(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray);
var
    StartingIndex: Integer;
begin
    StartingIndex := 0;
    EnableAnchors_Core(ParentControl, aAnchorStorage, StartingIndex);
end;


procedure EnableAnchors_Core(ParentControl: TWinControl; aAnchorStorage: TAnchorsArray; var StartingIndex: Integer);
var
    iCounter: integer;
    ChildControl: TControl;
begin
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        ChildControl.Anchors := aAnchorStorage[StartingIndex];

        Inc(StartingIndex);
    end;

    //Restore children
    for iCounter := 0 to ParentControl.ControlCount - 1 do
    begin
        ChildControl := ParentControl.Controls[iCounter];
        if ChildControl is TWinControl then
            EnableAnchors_Core(TWinControl(ChildControl), aAnchorStorage, StartingIndex);
    end;
end;

Mit der Arbeit, eine Steuerelementschriftart tatsächlich zu ändern, verließ zu:

procedure StandardizeFont_ControlFontCore(AControlFont: TFont; ForceClearType: Boolean;
        FontName: string; FontSize: Integer;
        ForceFontIfName: string; ForceFontIfSize: Integer);
const
    CLEARTYPE_QUALITY = 5;
var
    CanChangeName: Boolean;
    CanChangeSize: Boolean;
    lf: TLogFont;
begin
    if not Assigned(AControlFont) then
        Exit;

{$IFDEF ForceClearType}
    ForceClearType := True;
{$ELSE}
    if g_ForceClearType then
        ForceClearType := True;
{$ENDIF}

    //Standardize the font if it's currently
    //  "MS Shell Dlg 2" (meaning whoever it was opted into the 'change me' system
    //  "MS Sans Serif" (the Delphi default)
    //  "Tahoma" (when they wanted to match the OS, but "MS Shell Dlg 2" should have been used)
    //  "MS Shell Dlg" (the 9x name)
    CanChangeName :=
            (FontName <> '')
            and
            (AControlFont.Name <> FontName)
            and
            (
                (
                    (ForceFontIfName <> '')
                    and
                    (AControlFont.Name = ForceFontIfName)
                )
                or
                (
                    (ForceFontIfName = '')
                    and
                    (
                        (AControlFont.Name = 'MS Sans Serif') or
                        (AControlFont.Name = 'Tahoma') or
                        (AControlFont.Name = 'MS Shell Dlg 2') or
                        (AControlFont.Name = 'MS Shell Dlg')
                    )
                )
            );

    CanChangeSize :=
            (
                //there is a font size
                (FontSize <> 0)
                and
                (
                    //the font is at it's default size, or we're specifying what it's default size is
                    (AControlFont.Size = 8)
                    or
                    ((ForceFontIfSize <> 0) and (AControlFont.Size = ForceFontIfSize))
                )
                and
                //the font size (or height) is not equal
                (
                    //negative for height (px)
                    ((FontSize < 0) and (AControlFont.Height <> FontSize))
                    or
                    //positive for size (pt)
                    ((FontSize > 0) and (AControlFont.Size <> FontSize))
                )
                and
                //no point in using default font's size if they're not using the face
                (
                    (AControlFont.Name = FontName)
                    or
                    CanChangeName
                )
            );

    if CanChangeName or CanChangeSize or ForceClearType then
    begin
        if GetObject(AControlFont.Handle, SizeOf(TLogFont), @lf) <> 0 then
        begin
            //Change the font attributes and put it back
            if CanChangeName then
                StrPLCopy(Addr(lf.lfFaceName[0]), FontName, LF_FACESIZE);
            if CanChangeSize then
                lf.lfHeight := FontSize;

            if ForceClearType then
                lf.lfQuality := CLEARTYPE_QUALITY;
            AControlFont.Handle := CreateFontIndirect(lf);
        end
        else
        begin
            if CanChangeName then
                AControlFont.Name := FontName;
            if CanChangeSize then
            begin
                if FontSize > 0 then
                    AControlFont.Size := FontSize
                else if FontSize < 0 then
                    AControlFont.Height := FontSize;
            end;
        end;
    end;
end;

Das ist viel mehr Code, als Sie gedacht haben. Ich kenne. Das Traurige ist, dass es außer mir keinen Delphi-Entwickler auf der Welt gibt, der seine Anwendungen tatsächlich korrekt macht.

Sehr geehrter Delphi-Entwickler: Stellen Sie Ihre Windows-Schriftart auf Segoe UI 14pt und korrigieren Sie Ihre fehlerhafte Anwendung

Anmerkung: Jeder Code wird als gemeinfrei veröffentlicht. Keine Zuordnung erforderlich.

41
Ian Boyd

Hier ist mein Geschenk. Eine Funktion, die Ihnen bei der horizontalen Positionierung von Elementen in Ihren GUI-Layouts helfen kann. Frei für alle.

function CenterInParent(Place,NumberOfPlaces,ObjectWidth,ParentWidth,CropPercent: Integer): Integer;
  {returns formated centered position of an object relative to parent.
  Place          - P order number of an object beeing centered
  NumberOfPlaces - NOP total number of places available for object beeing centered
  ObjectWidth    - OW width of an object beeing centered
  ParentWidth    - PW width of an parent
  CropPercent    - CP percentage of safe margin on both sides which we want to omit from calculation
  +-----------------------------------------------------+
  |                                                     |
  |        +--------+       +---+      +--------+       |
  |        |        |       |   |      |        |       |
  |        +--------+       +---+      +--------+       |
  |     |              |             |            |     |
  +-----------------------------------------------------+
  |     |<---------------------A----------------->|     |
  |<-C->|<------B----->|<-----B----->|<-----B---->|<-C->|
  |                    |<-D>|
  |<----------E------------>|

  A = PW-C   B = A/NOP  C=(CP*PW)/100  D = (B-OW)/2
  E = C+(P-1)*B+D }

var
  A, B, C, D: Integer;
begin
  C := Trunc((CropPercent*ParentWidth)/100);
  A := ParentWidth - C;
  B := Trunc(A/NumberOfPlaces);
  D := Trunc((B-ObjectWidth)/2);
  Result := C+(Place-1)*B+D;
end;
11
avra