[DUG] Component that knows when a click occurs elsewhere
(secondtry)
Karl Reynolds
karlreynolds at xtra.co.nz
Fri Nov 25 18:00:52 NZDT 2005
Hmmm, I think you'll have to hook mouse clicks for the application your
component is on if you want the ability to respond to a click on a control
that doesn't take the focus (like a speedbutton), and you want to
encapsulate the code for that within your component code. I tried it out:
here's the source for what I did:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton; // Some components for testing
CheckBox1: TCheckBox; // Some components for testing
SpeedButton1: TSpeedButton; // Some components for testing
procedure FormShow(Sender: TObject);
private
procedure WCLGotClick(Sender: TObject; APoint: TPoint);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TWCLExternalButtonClick = procedure (Sender: TObject; APoint: TPoint) of
object;
TWCL = class(TButton) // In my test I made TWCL a button descendant
private
FOnExternalButtonClick: TWCLExternalButtonClick; // An event for you to
respond to
protected
destructor Destroy; override;
public
constructor Create(AOwner: TComponent); override;
published
property OnExternalButtonClick: TWCLExternalButtonClick read
FOnExternalButtonClick write FOnExternalButtonClick;
end;
var
MHookCount: Integer = 0; // Need to keep count of the number of TWCL's you
drop around the place - this is a global count
MMouseHook: HHOOK; // Your event hook
{
CatchMouseDown: The procedure hooked for mouse events.
In this example, I am only interested in left mouse clicks,
which I pass off to the focused TWCL component (if there is
one) as an OnExternalButtonClick event
}
function CatchMouseDown(nCode: Integer; wParam: WPARAM; lParam: LPARAM):
LRESULT; stdcall;
var i: Integer;
begin
if nCode >= 0 then
begin
if wParam = WM_LBUTTONDOWN then
begin
with Screen do
if Assigned(ActiveForm) then
with ActiveForm do
for i := 0 to ComponentCount - 1 do
if Components[i] is TWCL then
with TWCL(Components[i]) do
if Focused then // Only raise the event if a TWCL is the
focused control
if Assigned(FOnExternalButtonClick) then
begin
FOnExternalButtonClick(ActiveForm.Components[i],
PMouseHookStruct(lParam)^.pt); // nb. pt is in
screen co-ordinates
end;
end;
end;
Result := CallNextHookEx(MMouseHook, nCode, wParam, lparam);
end;
procedure HookMouseEvents;
begin
if MHookCount = 0 then
MMouseHook := SetWindowsHookEx(WH_MOUSE, @CatchMouseDown, 0,
GetCurrentThreadID);
Inc(MHookCount);
end;
procedure UnhookMouseEvents;
begin
Dec(MHookCount);
if MHookCount = 0 then
UnhookWindowsHookEx(MMouseHook);
end;
{ TWCL }
constructor TWCL.Create(AOwner: TComponent);
begin
inherited;
HookMouseEvents;
end;
destructor TWCL.Destroy;
begin
UnhookMouseEvents;
inherited;
end;
// And some code to check that everything works:
{ TForm1 }
procedure TForm1.FormShow(Sender: TObject);
begin
with TWCL.Create(Self) do
begin
Left := 10;
Top := 10;
Caption := 'WCL';
OnExternalButtonClick := WCLGotClick;
Parent := Self;
SetFocus;
end;
end;
procedure TForm1.WCLGotClick(Sender: TObject; APoint: TPoint);
var LControl: TControl;
begin
{
I decided to add the name of the control clicked on to a memo here.
But you could call TWCL(Sender).OnExit, or whatever
}
LControl := ControlAtPos(ScreenToClient(APoint), True, True);
if Assigned(LControl) then
Memo1.Lines.Add(LControl.Name);
end;
end.
HTH.
Cheers,
Carl
><snip>
> I'm writing a subclass of tComponent, tWCL, that calls
> reactionMethod when the user clicks one something else - on another
> component, but also on the form..
>
> When I originally wrote tWCL, I gave it an onExit
> handler. When the
> user clicked on some other component, the tWCL object's
> onExit handler
> was called automatically, and this called reactionMethod. I also
> added the handler form.onClick, which explicitly set the tWCL
> object's enabled property to FALSE when the user clicked on the form,
> thereby also invoking the object's onExit handler, which in turn
> called reactionMethod, as required
>
> Now, however, I want to turn tWCL into a component, and I don't
> want the user to have to write a form.onClick handler.
> How can I
> get my component to detect that the user has clicked on the form, so
> that it can call reactionMethod?
>
> Thanks
> Paul
More information about the Delphi
mailing list