Re: What is What'sThis pointing to?


[ Related Articles and Replies ] [ DelphiLand FAQ ] [ Delphi Tutorials ]

Posted by webmaster Guido on December 11, 2001 at 19:37:37:

In Reply to: What is What'sThis pointing to? posted by Tomas on November 29, 2001 at 16:00:01:

: I'm implementing a help system and I need some help myself.
: When I use the WhatIsThis pointer, the component pointed to does not get focus, so I can't use ActiveControl to find out what I'm pointing to.
: What can I use instead?

----

When the "What's this?" button is clicked, we can proceed as follows:
1. Change the cursor to the help-cursor.
2. Wait for a Windows "message" that tells us that the mouse was clicked or a key was pressed.
3. Change the cursor back to normal.
4. If the message was caused by a click with the left mouse-button on a "windowed control", display the corresponding help information.

To test this, we start a new project and we drop some visual components on the form: a couple of TEdits, a TButton, a ListBox, whatever (as long as the components are *visible* :) Next, we drop a speedbutton near the top of the form, we name it btnWhatsThis and we create an OnClick event handler. Here's an example of the code:

procedure TForm1.btnWhatsThisClick(Sender: TObject);
var
  HelpMessage: string;
  WhatsThisMode: Boolean;
  Msg: TMsg;
  TheControl: TWinControl;
begin
  Screen.Cursor := crHelp; // show help cursor
  HelpMessage := '';
  WhatsThisMode := True;
  { Handle all messages until the mouse is clicked or a key is depressed }
  while WhatsThisMode do begin
    if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin
      if Msg.message = WM_LBUTTONDOWN then begin
        TheControl := FindControl(Msg.hwnd);
        HelpMessage := 'Control clicked: ' + TheControl.Name;
      end;
      { Leave the loop if there was a mouseclick or a keypress, 
        stay in the loop if it was another message } 
      case Msg.message of
        WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_KEYFIRST..WM_KEYLAST:
          WhatsThisMode := False;
      end;
    end;
  end;
  Screen.Cursor := crDefault;
  if HelpMessage <> '' then ShowMessage(HelpMessage);
end;

Instead of showing the help info yourself like in this very simple example, in a real application you would get the "help-context" property from the control that was clicked and if it was not zero, send it to the help-system.


For those that are interested how this works:

Windows generates a "message" at each input event, for example, when a mousebutton goes down or is released, when a key is pressed or released, when the mouse is moved. With the function PeekMessage() we can check if there is a message waiting in the "message queue" and if there is one, its data can be found in a "message structure".

PeekMessage is defined as:

PeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);

- lpMsg: pointer to a message-structure, that contains the message information.
- hWnd: handle of the window whose messages are to be examined. If it is NULL, PeekMessage retrieves messages for any window that belongs to the current thread.
- wMsgFilterMin, wMsgFilterMax: filters for the messages to be examined. If wMsgFilterMin and wMsgFilterMax are both zero, all available messages are examined.
- wRemoveMsg: if this parameter is set to PM_REMOVE, the message is removed from the queue, so that none of the controls will receive the mouseclick (or keypress,...): no "normal" event handlers will be triggered. This is of course the behaviour that we want in our "What's this?" helpmode.
If wRemoveMsg is set to PM_NOREMOVE, the message is not removed from the queue.

Here are a few fields of the "message structure" that we can examine:

- MSG.hwnd: handle of the "window" that received the message. Note that "window" is not limited to what in Delphi is called a "form": also some visual components have a "window". For example, a TEdit is a "windowed control", but a TLabel is not; a TEdit can receive "focus" and it also has a help-context property, a TLabel doesn't.
- MSG.message: depends from the action that caused the message. Can have values such as WM_LBUTTONDOWN (left mousebutton was pushed down), WM_RBUTTONDOWN, WM_KEYFIRST (keypress), and so on.
- MSG.wParam and MSG.lparam: additional info, whose exact meaning depends on the value of MSG.message. For more details, see the WinAPI help files.


Related Articles and Replies


[ Related Articles and Replies ] [ DelphiLand Discussion Forum ]