Turbocharging Delphi 2010 #2: Adding dynamic functionality to 3rd parties – the solution

Kubrik

Kubrik

First of all, let me stress that once again it is shown that the community is way smarter than any individual alone. And of course, when I say any individual, I mean any individual, regardless of company at which he’s working ;-). That’s why I think that the feedback was, is and will be the main innovation power, especially in our industry were, due of the very intellectual nature of our job we can make very easy mistakes if we advance alone. Only in this way we can approach to the naturalism and neutrality of perfection. Yes, I put the Stanley Kubrik‘s photo on purpose.

The man of the day in this case is Heinz Z. (Heinz, if you want, I can make public your full name 🙂 ) which on my latest post about different techniques to extend the functionality of a class which we cannot control, gave a very simple and effective solution. Rather than leaving his answer there I think that’s appropriate to make a special post here giving him the pen:… (Note: I slightly adapted his example – comments and other miscellanea at the end)

Hello,

after I read your idea here I have an other that use normal inheritance so all the problems you describe are gone. I have tested it with Delphi 2006 but I think it should work in every Delphi versions. The base idea is to replace a type like TLabel from StdCtrls with an other TLabel defined by myself. The Designer only knows StdCtrls.TLabel but the compiler see only my own definition of TLabel and create the desired instance. Have a look at the source:


unit LabelHelper;

interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
  TLabel = class(StdCtrls.TLabel)
  private
    FLines: TStrings;
  protected
    function GetLabelText: string; override;
    procedure LinesChanged(Sender: TObject);
  public
    constructor Create(AComponent: TComponent); override;
    destructor Destroy; override;
    property Lines: TStrings read FLines write FLines;
  end;

implementation

constructor TLabel.Create(AComponent: TComponent);
begin
  inherited;

  FLines := TStringList.Create;
  TStringList(FLines).OnChange := LinesChanged;
end;

destructor TLabel.Destroy;
begin
  FLines.Free;
  FLines := nil;
  inherited;
end;

function TLabel.GetLabelText: string;
begin
  Result := FLines.Text;
end;

procedure TLabel.LinesChanged(Sender: TObject);
begin
  AdjustBounds;
end;

end.

…and to use it one must be aware of Delphi’s unit precedence (ie. right to left in the uses clause) so you must put your helper unit after the unit of the helped class:


unit MainFormU;

interface
uses
  ...StdCtrls,...LabelHelper...; //etc.

I think that’s really nice.

So what was left is a compiler warning (which of course is needed not only for this case) saying that “The ‘TLabel’ definition from LabelHelper.pas hides the definition from StdCtrls.pas” Also perhaps a keyword (something like TLabel = class helper for (StdCtrls.TLabel)… 🙂 ) will suppress the warning. Hmmm… I’m wondering if the class helpers doesn’t work exactly in this way…

Or perhaps I’m missing something?

10 thoughts on “Turbocharging Delphi 2010 #2: Adding dynamic functionality to 3rd parties – the solution

    • Yes. The funny thing is that I’ve also used (and perhaps others) many times but only for bug-fixing VCL. Usually we copy the VCL unit in our directory and make our changes inside. But here (and what your links provide) is used for other purpose(s). Technically speaking the things is almost the same but from human POV the things are different. Thanks for the links once again.

  1. To be independent from Delphi’s unit precedence and for a better documentation it is worth to write

    type
       TLabel = LabelHelper.TLabel;
    
       TForm1 = class(TForm)
       ...
    
    • Yep, good point. But I would also like a compiler warning or something similar. For ex. TLabel = class(StdCtls.TLabel) would give a warning while TLabel = class(StdCtls.Label) override will not.

        • And to press the team to support also URLs in the compiler directives, isn’t? 🙂

          Seriously though, is definitely a good idea with which we can live. OTOH, we must be careful to put it in order to appear only if that “thing” will be actually used (ie. linked). I didn’t make tests but I think that if my interceptor class will not be used and I have this in one of its methods the message will not appear.

  2. I don’t like interceptor classes very much. I use it as a ‘last resort’ technique for solving some problems.
    The problem is that the code lies, so only ones that know about the trick can actually read the correctly.
    Class helpers are not much better though….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s