2005. július 22., péntek

How to create context-sensitive help


How to create context-sensitive help



Windows 95 has much better context-sensitive help than Windows 3.1, with support for the small ? button in dialogs and right-button 'What's This?' help. These features allow users to get instant help in dialogs, without opening Help in a separate window. This integration between Help and your application is very user-friendly and makes the program look very professional. Also, your Help file stays smaller because you don't have to include screenshots for all dialogs. Delphi 2.0 allows you to make use of context-sensitive help, but it is not straightforward. Especially using the What's This function requires some investigation.

The goal of this document is to aid Delphi 2.0 developers in adding context-sensitive Help to their application, so that you do not have to reinvent the wheel. You are assumed to have knowledge of Delphi programming and help authoring, and have access to Delphi 2.0, the Help Workshop (provided with the Help Authoring Guide) and a word processor to create .RTF files (or whatever method you use to create help files).


Create topics in your Help file that you want to be used as popup-help for dialog controls
Create an include file which contains the mapping of Pascal constants to help identifiers (say mapping.inc)
Add two lines helpcontextidentifier=uniquenumber and ';' i.e. helpokbutton = 1000; for each help topic. The second line with the semi-colon is necessary to allow us to use the include file both in Delphi and Help Workshop
In your Help project file, specify mapping.inc as the Map file
Create a data module in your Delphi project, if you didn't already have one
In the data module add an include statement {$I mapping.inc} preceded by a const statement
Add a TPopupMenu component to the data module, and add one menu-item with the text 'What's This?'
Create an event handler for the OnClick event of this menu item, and add the code shown in bold

The resulting data module code (without any other components you may have in it) should now look like this (I named the module dmMain):

unit Datamodule;


  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, RegFiles, Menus;

  TdmMain = class(TDataModule)
    PopupMenu1: TPopupMenu;
    procedure WhatsThis1Click(Sender: TObject);
    { Private declarations }
    { Public declarations }

  dmMain: TdmMain;


{$R *.DFM}

procedure TdmMain.WhatsThis1Click(Sender: TObject);
  P: TControl;
  with PopupMenu1 do
    if PopupComponent is TControl then
      P := PopupComponent as TControl;
      {locate the closest ancestor with a valid HelpContext}
      while (P <> nil) and (not (P is TWinControl) or ((P as TWinControl).HelpContext = 0)) do
        P := P.Parent;
      if (P <> nil) then
        Application.HelpCommand(HELP_CONTEXTPOPUP, Longint((P as TWinControl).HelpContext));

In the dialog form, be sure to specify the bordericons as [biHelp] or [biSystemMenu, biHelp] and the border style as bsSingle, to enable the small ? button in the caption of the form
For each control you want What's This help, specify the dmMain.PopupMenu1 as the PopupMenu property
In the OnCreate event handler for the form containing the controls, add a line for each control in the form of: Control1.HelpContext := helpcontextidentifier; where helpcontextidentifier is the constant defined in mapping.inc for this control.

That's it! Compile the Delphi project and the Help project and everything should work. Note that I used a single TPopupMenu for all controls across all dialogs - this is the strength of the data module at work. Now that you have this framework set up, providing context-sensitive help for each new control you add consists of just four steps:

Create a topic for it in the Help source
Create an entry in the mapping file
Add one line in the OnCreate of the form containing the control
Set the PopupMenu of the control to the data module popupmenu.


According to the documentation in the Help Authoring Guide, you should create a WndProc in your form to catch the WM_CONTEXTMENU message and respond to it by calling WinHelp() with the control id (coming from Msg.wParam) as the handle, plus an array containing (handle,help topic) pairs. However, apart from being rather cumbersome, this doesn't work for controls which have a parent (like controls on a PageControl) because the handle being passed is the parent's, not the child's. The Help system itself does provide a popup menu (using the HELP_CONTEXTMENU command), so recreating it in the Delphi project is not elegant. However, using the HELP_CONTEXTPOPUP command from Delphi and avoiding the messy WndProc business in my opinion outweighs this minor inelegance by far.

Nincsenek megjegyzések:

Megjegyzés küldése