views:

1000

answers:

3

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;
+2  A: 

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.

Ken White
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.Bri
Brian Frost
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.
Andreas Hausladen
@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.
Ken White
@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.
Ken White
+18  A: 

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.

mghie
+1 very interesting solution!
Smasher
+1 Woah - I had no idea you could get away with tricks like that. Thanks for opening my eyes!
robsoft
+3  A: 

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

tikinoa