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
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
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(HookedM sgProc);
END;
DESTRUCTOR TWindowClass.Destroy;
BEGIN
FreeObjectInstance(FNewPro c);
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_FtDataSelectio n.DrawSele ction(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(FWin Control.Ha ndle, 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;
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
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(HookedM
END;
DESTRUCTOR TWindowClass.Destroy;
BEGIN
FreeObjectInstance(FNewPro
UnhookWindow;
inherited Destroy;
END;
PROCEDURE TWindowClass.Loaded;
BEGIN
FWinControl := FForm;
HookWindow;
inherited Loaded;
END;
PROCEDURE TWindowClass.HookedMsgProc
BEGIN
if (Msg.WParam = VK_UP) or (Msg.WParam = VK_DOWN)then
BEGIN
g_tparent.m_FtDataSelectio
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(FWin
SetWindowLong(FWinControl.
END;
PROCEDURE TWindowClass.UnhookWindow;
BEGIN
IF FOldProc <> NIL THEN
BEGIN
SetWindowLong(FWinControl.
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.
ziolko.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Job well done ... !
Two different implementations, both which work nicely !
Many thanks Ziolko !
:-)
Two different implementations, both which work nicely !
Many thanks Ziolko !
:-)
ASKER
Nice suggestion, followed by a nice example !
Job well done !
<< have increased my morning coffee intake two-fold ;-)
Many thanks,
Steve
Job well done !
<< have increased my morning coffee intake two-fold ;-)
Many thanks,
Steve
glad to be helpfull :-)
ziolko.
ziolko.
ziolko.