Ryan Joseph wroteAdriaan, 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