How to send a message to a specific control on a TForm #105

Question
Is it possible to send a message to a control on a form? I have the name of the component.

You can send a message to any TControl descendant, whether it has a window handle or not, by using the Perform method.

Any control owned by a form can be found by searching through the form's Components property.

The following method can be added to a form (or frame) to let you send a message to a named control. It will return true if the control was found.

function TForm1.SendMessageToCtrl(const Name: string;
  const Msg: Cardinal; WParam, LParam: Integer): Boolean;
var
  Idx: Integer;
  Ctrl: TControl;
begin
  Result := False;
  // scan all components owned by the form
  for Idx := 0 to Pred(ComponentCount) do
  begin
    if Components[Idx] is TControl then
    begin
      // we have a TControl: check its name (case insensitive)
      Ctrl := Components[Idx] as TControl;
      if AnsiSameText(Ctrl.Name, Name) then
      begin
        // found it: send message and bail out
        Ctrl.Perform(Msg, WParam, LParam);
        Result := True;
        Exit;
      end;
    end;
  end;
end;

Demo code

A ready made project containing this demo code is available. View the project.

To see SendMessageToCtrl in action start a new Delphi VCL application then:

  • Add a few components to the form, making sure you include at least one of each of a TCheckBox, TLabel, TEdit and TButton. Keep the default names.
  • Create an OnClick event handler for Button1.
  • Name the form "Form1", save the form unit as Unit1.pas and code the unit as follows:
unit Unit1;

interface

uses
  SysUtils, Forms, StdCtrls, Controls, Classes, Messages, Windows;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Edit1: TEdit;
    Button1: TButton;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
  private
    function SendMessageToCtrl(const Name: string;
      const Msg: Cardinal; WParam, LParam: Integer): Boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.SendMessageToCtrl(const Name: string;
  const Msg: Cardinal; WParam, LParam: Integer): Boolean;
var
  Idx: Integer;
  Ctrl: TControl;
begin
  Result := False;
  // scan all components owned by the form
  for Idx := 0 to Pred(ComponentCount) do
  begin
    if Components[Idx] is TControl then
    begin
      // we have a TControl: check its name (case insensitive)
      Ctrl := Components[Idx] as TControl;
      if AnsiSameText(Ctrl.Name, Name) then
      begin
        // found it: send message and bail out
        Ctrl.Perform(Msg, WParam, LParam);
        Result := True;
        Exit;
      end;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  AText: PChar = 'I got a message';
begin
  // send a click to the checkbox: this will check it
  SendMessageToCtrl('CheckBox1', WM_LBUTTONDOWN, MK_LBUTTON, 0);
  SendMessageToCtrl('CheckBox1', WM_LBUTTONUP, MK_LBUTTON, 0);
  // set the text of the label
  SendMessageToCtrl('Label1', WM_SETTEXT, 0, Integer(AText));
  SendMessageToCtrl('Label1', CM_TEXTCHANGED, 0, 0);
  // set the text of the edit control
  SendMessageToCtrl('Edit1', WM_SETTEXT, 0, Integer(AText));
end;

end.

When you click Button1 you will see the text of the label named "Label1" and the edit control named "Edit1" change. The checkbox named "CheckBox1" will become checked. The comments in TForm1.Button1Click explain what's happening.

Author: Peter Johnson
Added: 2009/09/14
Last updated: 2010/03/16