Link to home
Start Free TrialLog in
Avatar of steve_hsk
steve_hsk

asked on

Component Writing : TGraphicControl with user (keyboard) input

I am writing a network monitoring screen logging component. Due to the speed of the output, I am using TGraphicControl as the main drawing Canvas in the component, which I've provided Line and Page updates for.

I have used the mouse button up msg to detect when and where the user has clicked on the screen. However, to provide a more professional finish, I really need to let the user navigate the captured data with the arrow keys.

I'm aware of the procedure necessary to grab the arrow keys :
PROCEDURE WMGetDlgCode (VAR MESSAGE : TWMGetDlgCode); MESSAGE WM_GetDlgCode;

But I think I need a method of adding/simulating key down events on this (or a sub/child) control, as TGraphicControl doesn't naturally own a window's handle from which to receive WM_KEYDOWN ?!?

Any ideas would be much appreciated.
Many thanks.
Steve
Avatar of Lukasz Zielinski
Lukasz Zielinski
Flag of Poland image

Write WndProc and use AllocateHwnd from Forms unit to get Handle.
ziolko.
Avatar of steve_hsk
steve_hsk

ASKER

Hi ziolko ...

This method appears to work :-)

Have used it before to grab the Window's Caption Control, but for some reason it didn't occur to me here. Needed more coffee ;-)

The points are yours. As a last query, did you have a better way of implementation than below ? (may as well try and make ya work for it :-) ) ...

NOTE : Here for others reference also ...

TYPE TWindowClass = CLASS (TComponent)
PUBLIC
    // Declare Class Control Functions
    CONSTRUCTOR Create(AOwner: TComponent); OVERRIDE;
    DESTRUCTOR  Destroy; OVERRIDE;
PRIVATE
    // Declare Internal Variables
    FForm       : TWinControl;
    FNewProc    : Pointer;
    FOldProc    : Pointer;
    FWinControl : TWinControl;

    // Declare Internal Methods
    PROCEDURE HookedMsgProc (VAR Msg: TMessage);
    PROCEDURE Loaded; OVERRIDE;
    PROCEDURE HookWindow;
    PROCEDURE UnhookWindow;
END;

CONSTRUCTOR TWindowClass.Create(AOwner: TComponent);
VAR tFormParent : TWinControl;
BEGIN
  INHERITED Create(AOwner);
  tFormParent := TWinControl(AOwner);

  WHILE (tFormParent <> NIL) AND (NOT (tFormParent IS TForm)) DO
  BEGIN
        tFormParent := tFormParent.Parent;
  END;

  FForm := tFormParent;

  FNewProc := MakeObjectInstance(HookedMsgProc);
END;

DESTRUCTOR  TWindowClass.Destroy;
BEGIN
    FreeObjectInstance(FNewProc);
    UnhookWindow;
    inherited Destroy;
END;

PROCEDURE TWindowClass.Loaded;
BEGIN
    FWinControl := FForm;
    HookWindow;
    inherited Loaded;
END;

PROCEDURE TWindowClass.HookedMsgProc (VAR Msg: TMessage);
BEGIN
    if (Msg.WParam = VK_UP) or (Msg.WParam = VK_DOWN)then
    BEGIN
        g_tparent.m_FtDataSelection.DrawSelection(Msg.LParam);
    END
    ELSE
    BEGIN
        Msg.Result := CallWindowProc(FOldProc, FWinControl.Handle, Msg.Msg, Msg.WParam, Msg.LParam);
    END;

    INHERITED;
END;

PROCEDURE TWindowClass.HookWindow;
BEGIN
    FOldProc := Pointer(GetWindowLong(FWinControl.Handle, GWL_WNDPROC));
    SetWindowLong(FWinControl.Handle, GWL_WNDPROC, Integer(FNewProc));
END;

PROCEDURE TWindowClass.UnhookWindow;
BEGIN
    IF FOldProc <> NIL THEN
    BEGIN
        SetWindowLong(FWinControl.Handle, GWL_WNDPROC, Integer(FOldProc));
        FOldProc := nil;
    END;
END;
Hi steve if You dont mind I'll take a look at it tomorrow morning. I'll rather go to sleep then drink more coffe :-)))
ziolko.
ASKER CERTIFIED SOLUTION
Avatar of Lukasz Zielinski
Lukasz Zielinski
Flag of Poland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Job well done ... !

Two different implementations, both which work nicely !

Many thanks Ziolko !

:-)
Nice suggestion, followed by a nice example !

Job well done !

<< have increased my morning coffee intake two-fold ;-)

Many thanks,
Steve
glad to be helpfull :-)
ziolko.