?
Solved

Component Writing : TGraphicControl with user (keyboard) input

Posted on 2003-03-04
7
Medium Priority
?
400 Views
Last Modified: 2011-09-20
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
0
Comment
Question by:steve_hsk
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
7 Comments
 
LVL 21

Expert Comment

by:ziolko
ID: 8063330
Write WndProc and use AllocateHwnd from Forms unit to get Handle.
ziolko.
0
 
LVL 2

Author Comment

by:steve_hsk
ID: 8064392
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;
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8065264
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.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 21

Accepted Solution

by:
ziolko earned 300 total points
ID: 8067967
hmm look ok but persnoally I dont like subcalssing so I would do it that way:
this unit defines TWindowClass

unit Unit2;

interface

uses  Classes, Controls, Messages, Windows;

type TWindowClass = class(TComponent)
private
   // Declare Internal Variables
   FHandle: THandle;
protected
   // Declare Internal Methods
   procedure WndProc(var Message: TMessage);virtual;
   procedure Loaded; override;
public
   // Declare Class Control Functions
   constructor Create(AOwner: TComponent); override;
   destructor  Destroy; override;
   procedure Perform(var Message: TMessage);
end;

implementation

uses Forms;

constructor TWindowClass.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);
 FHandle:=AllocateHWnd(WndProc);
END;

destructor  TWindowClass.Destroy;
begin
   DeallocateHWnd(FHandle);
   inherited Destroy;
end;

procedure TWindowClass.Perform(var Message: TMessage);
begin
  if FHandle <> 0 then
    WndProc(Message);
end;

procedure TWindowClass.Loaded;
begin
   inherited Loaded;
end;

procedure TWindowClass.WndProc(var Message: TMessage);
begin
  if (Message.WParam = VK_UP) or (Message.WParam = VK_DOWN) then
//    g_tparent.m_FtDataSelection.DrawSelection(Message.LParam);
   Beep(100,40)
end;

end.


this is unit with form definition (single button is on form):
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    dumm: TWindowClass;
  protected
    procedure WndProc(var Message: TMessage);override;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}


procedure TForm1.WndProc(var Message: TMessage);
begin
  if dumm <> nil then
    dumm.Perform(Message);
  inherited WndProc(Message);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  dumm:=TWindowClass.Create(Self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  dumm.Free;
end;

end.


ziolko.
0
 
LVL 2

Author Comment

by:steve_hsk
ID: 8070315
Job well done ... !

Two different implementations, both which work nicely !

Many thanks Ziolko !

:-)
0
 
LVL 2

Author Comment

by:steve_hsk
ID: 8070327
Nice suggestion, followed by a nice example !

Job well done !

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

Many thanks,
Steve
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8070622
glad to be helpfull :-)
ziolko.
0

Featured Post

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month8 days, 14 hours left to enroll

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question