[fpc-pascal] Interface delegates and the implements property specifier
Adriaan van Os
fpc at microbizz.nl
Fri Dec 27 21:39:13 CET 2019
Ryan Joseph via fpc-pascal wrote:
> Adriaan, what was your idea you had in mind when you brought this up?
Well, to give you an idea, here is an example (somewhat simplified for clarity). I am currently
porting MacApp to 64-bit. MacApp currently has
TView = class( TEventHandler)
However, I have a TQDGraphPort class with QuickDraw emulation. For the QuickDraw emulation to work
with current application code, TQDGraphPort methods (like TQDGraphPort.MoveTo, TQDGraphPort.LineTo,
etcetera) have to be methods (or be in the namespace) of TView. So, I would really need
TView = class( TQDGraphPort, TEventHandler)
The TEventHandler methods have to be methods (or be in the namespace) of TView, because existing
application code overrides the methods of TEventHandler in objects inheriting from TView. This
mechanism needs to continue working.
Other classes also inherit from TEventHandler: TDocument, TPrintHandler and TApplication.
I solved this now by defining four event-handling interfaces: IIdleHandler, IMenuHandler,
IKeyHandler, IMouseHandler, all inheriting from IEventHandler, Something like:
IEventHandler =
interface
[ 'IEventHandler']
function GetNextEventObj : TObject;
end;
IKeyHandler =
interface
( IEventHandler)
[ 'IKeyHandler' ]
function DoKeyCommand
( theChar : char;
theKeyCode : Int16;
var theEventInfo : EventInfo): TCommand;
function DoCommandKey
( theChar : char;
var theEventInfo : EventInfo): TCommand;
end;
etcetera. The event-handling classes can now import the interfaces:
TApplication = class( TRefCountObj, IKeyHandler, iMenuHandler, IIdleHandler)
TDocument = class( TDBFile, IKeyHandler, iMenuHandler, IIdleHandler)
TView = class( TMacAppGraphPort, IKeyHandler, IMenuHandler, IIdleHandler, IMouseHandler)
etcetera. The disadvantage of this approach is that for example a default DoKeyCommand must be
written three times, for TApplication, TDocument and TView, where the code for
TDocument.DoKeyCommand and TView.DoKeyCommand is identical.
Identical code is clumsy. Therefore my wish that a helper object could somehow be put in the
namespace of the importing object, including the ability to override the imported methods. I hope
that answers you question.
I admit however that with some clever interface programming, the duplicated code can be reduced in
the above case to a single line. As follows:
function GetObjEventHandler
( theObj : TObject): IEventHandler;
var
theEventHandler : IEventHandler;
begin
if ( theObj <> nil) and theObj.GetInterface
( IEventHandler, theEventHandler)
then GetObjEventHandler := theEventHandler
else GetObjEventHandler := nil
end;
function GetObjKeyHandler
( theObj : TObject): IKeyHandler;
var
theKeyHandler : IKeyHandler;
begin
if ( theObj <> nil) and theObj.GetInterface
( IKeyHandler, theKeyHandler)
then GetObjKeyHandler := theKeyHandler
else GetObjKeyHandler := nil
end;
function NextKeyCommand
( theObj : TObject;
theChar : char;
theKeyCode : Int16;
var theEventInfo : EventInfo): TCommand;
var
theEventHandler : IEventHandler;
theKeyHandler : IKeyHandler;
begin
theKeyHandler := nil;
while ( theObj <> nil) and ( theKeyHandler = nil) do
begin
theEventHandler := GetObjEventHandler
( theObj);
if theEventHandler = nil
then theObj := nil
else theObj := theEventHandler.GetNextEventObj;
theKeyHandler := GetObjKeyHandler
( theObj)
end;
if theKeyHandler <> nil
then NextKeyCommand := theKeyHandler.DoKeyCommand
( theChar, theKeyCode, theEventInfo)
else NextKeyCommand := nil
end;
function TDocument.DoKeyCommand
( theChar : char;
theKeyCode : Int16;
var theEventInfo : EventInfo): TCommand;
begin
DoKeyCommand := NextKeyCommand
( self, theChar, theKeyCode, theEventInfo)
end;
function TView.DoKeyCommand
( theChar : char;
theKeyCode : Int16;
var theEventInfo : EventInfo): TCommand;
begin
DoKeyCommand := NextKeyCommand
( self, theChar, theKeyCode, theEventInfo)
end;
Note that TDocument.DoKeyCommand and TView.DoKeyCommand are identical, but not larger than one
function call.
Regards,
Adriaan van Os
More information about the fpc-pascal
mailing list