Font smoothing in Delphi
Asked Answered
C

4

20

I had cause to need a label with a large font on a Delphi form and noticed that its curves were still slightly jagged. I compared this with the same size and font in MSWord which was much smoother. After research I found code that allowed me to smooth my fonts but it's messy and I was wondering if there was a better way? Looking in the VCL source, TFont seems wedded to NONANTIALIASED_QUALITY which is rather frustrating...

Thanks Bri

procedure TForm1.SetFontSmoothing(AFont: TFont);
var
  tagLOGFONT: TLogFont;
begin
  GetObject(
    AFont.Handle,
    SizeOf(TLogFont),
    @tagLOGFONT);
  tagLOGFONT.lfQuality  := ANTIALIASED_QUALITY;
  AFont.Handle := CreateFontIndirect(tagLOGFONT);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  I : integer;
begin
  For I :=0 to ComponentCount-1 do
    If Components[I] is TLabel then
      SetFontSmoothing( TLabel( Components[I] ).Font );
end;
Countless answered 28/5, 2009 at 14:51 Comment(3)
So does this code work (and you just want to clean it and find some easy way) or is it still not smooth enough or doesn't work?Unbated
Which part of this code do you consider messy?Hellespont
It seems wasteful that I've got to poke every font on every label when the VCL has already done this. I looked for something I could override or subclass but with no luck. I guess this is the only way of achieving what I want. BriCountless
I
29

You can trick the VCL into creating your own class that inherits from TLabel. This is proof-of-concept code, tested with Delphi 4, which should get you started.

Create a new unit for your own TLabel class:

unit AntiAliasedLabel;

interface

uses
  Windows, Messages, SysUtils, Controls, StdCtrls, Graphics;

type
  TLabel = class(StdCtrls.TLabel)
  private
    fFontChanged: boolean;
  public
    procedure Paint; override;
  end;

implementation

procedure TLabel.Paint;
var
  LF: TLogFont;
begin
  if not fFontChanged then begin
    Win32Check(GetObject(Font.Handle, SizeOf(TLogFont), @LF) <> 0);
    LF.lfQuality := ANTIALIASED_QUALITY;
    Font.Handle := CreateFontIndirect(LF);
    fFontChanged := TRUE;
  end;
  inherited;
end;

end.

Now modify your form unit that contains the label, adding the AntiAliasedLabel unit after StdCtrls. This results in your own class AntiAliasedLabel.TLabel being created where normally StdCtrls.TLabel would be created.

Indifferentism answered 28/5, 2009 at 16:17 Comment(0)
C
7

IMHO, the VCL should be checking the System default font smoothing and applying that as the default at run-time. If not, at least it should default to a more reasonable smoothing. One could argue, in this case, that ClearType would be a better default, considering > 50% of monitors these days are LCD (and greater than 50% of machines are running XP or better).

This is an acknowledged hack (and as Ken White mentions, not the best approach if there are alternatives), but I needed a way to fix this globally for forms containing literally hundreds of 3rd-party component types (making component inheritance unrealistic).

I changed the default Font Quality in Graphics.pas, TFont.GetHandle as follows:

// lfQuality := DEFAULT_QUALITY;

lfQuality := 5; // (HACK) CLEARTYPE_QUALITY, forces cleartype

Conias answered 28/5, 2009 at 21:35 Comment(0)
C
5

From: http://objectmix.com/delphi/725245-tlabel-antialiasing-possibile-3.html

"simply using a font that supports font smoothing should fix this. Delphi uses (or at least used to use) MS Sans Serif as default, which does not support smoothing (ClearType or otherwise). if you set your font to Tahoma (best for XP) or Segoe UI (best for Vista), you will automatically get font smoothing according to system settings in your Delphi app."

Confirmed, it works beautifully using Delphi XE and Win7. Busy changing all my fonts right now ;-)

Calvities answered 21/10, 2011 at 11:57 Comment(0)
I
3

The easiest way is to create your own component based on TLabel, such as TSmoothLabel or TAntiAliasedLabel, and add your smoothing code to it. Then you use your component instead of the standard TLabel.

Imperil answered 28/5, 2009 at 15:4 Comment(4)
True, but I'm loading an existing DFM that specifies the TLabel class, so your suggestion could work if there is a way of re-registering TLAbel. BriCountless
There is a way but it requires replacing the TLabel.NewInstance VMT entry by an own method at runtime. The JCL (JEDI Code Library) has functions to do this.Gossip
@Brian: Why can't you just fix the DFM and PAS files (from outside the IDE) to use your new class? Alternative: If you're using a version of Delphi that supports them, you could use a class helper for TLabel. (Specify which Delphi in the future.) I don't recommend the class helper route if there's any other way, though, because it will affect any TLabel that's in it's scope.Imperil
@Andreas: This is the wrong approach. That affects every single TLabel everywhere, and relies on things being in the same place in future versions of the VCL. NEVER do things that are hacks when there are other ways of doing them that aren't.Imperil

© 2022 - 2024 — McMap. All rights reserved.