共通デスクトップ環境 プログラマーズ・ガイド (ヘルプ・システム編)

第 10 章 ヘルプ要求への応答

この章では、ヘルプ・ダイアログ・ウィジェットのリソースの設定によってさまざまなヘルプ情報を表示する方法を説明します。

ヘルプの要求

アプリケーションの使用中にユーザがヘルプを要求したときは、どのヘルプ・トピックを表示するべきか、アプリケーション側で決定します。

コンテキストの検知

「バージョン」のヘルプ (通常は著作権のトピックが表示されます) など、特定の情報を明示的に要求するヘルプ要求もあります。ただしそれ以外のヘルプ要求では、コンテキストを要求します。つまり、アプリケーションにおけるユーザの現在のコンテキストに基づいて適切なヘルプ・トピックを選ぶ処理が必要です。

たとえばアプリケーションは、適切なヘルプ・トピックを判断するため、モードや設定のステータスをテストすることがあります。あるいは、入力フィールドの値をテストし、その値が有効でなければ詳細ヘルプを、有効であれば一般ヘルプを表示することもあります。

エントリ・ポイント

エントリ・ポイントとはヘルプ・ボリューム内の特定の場所のことで、通常はトピックの先頭です。アプリケーション内でヘルプを要求すると、エントリ・ポイントに直接アクセスできます。

設計者の見地から言えば、エントリ・ポイントはヘルプ・ボリュームの適切な場所に ID を指定することにより設定されます。プログラマの見地から言えば、ユーザがヘルプを要求できるようにし、特定のヘルプが要求されたときに適切な ID を使用することでエントリ・ポイントが作成されます。

ユーザがヘルプを要求する方法には次の 4 つがあります。

ヘルプ・トピックの表示

ヘルプが要求されると、アプリケーションが表示するヘルプ・トピックを決定します。次にヘルプ・ダイアログを (必要であれば) 作成し、管理して、ヘルプ・トピックを表示するのに適切なリソースを設定します。

ほとんどの要求については、アプリケーションのヘルプ・ボリュームの一部であるヘルプ・トピックが表示されます。しかしヘルプ・システムのヘルプ・ダイアログは、マニュアル・ページ、テキスト・ファイル、単一テキスト文字列を表示することもできます。

ヘルプ・システムのヘルプ・ダイアログは Xt イントリンシクスと OSF/Motif プログラミングに明示的に基づいているので、他のウィジェットと同じように、リソースを設定することによりヘルプ・ダイアログ内で値を変更できます。

DtNhelpType リソースは、表示するべき情報の種類を決定します。次のいずれかの値が設定されます。

上記の値は Help.h ファイルで定義されています。

関連項目

ヘルプ・トピックを表示するには

  1. ヘルプ・ダイアログを作成します。

  2. 次のようなヘルプ・ダイアログのリソースを設定します。

    DtNhelpType

    DtHELP_TYPE_TOPIC を設定します。

    DtNhelpVolume

    アプリケーションのボリューム名を設定します。

    DtNlocationId

    表示するトピックの ID を設定します。

    サイズやタイトルなど、その他の値も設定できます。

  3. XtManageChild() を使用してダイアログを管理します。

次のプログラム・セグメントは、ID である getting-started が付いたトピックを、ボリューム MyVolume に表示します。

ac = 0;
XtSetArg (al[ac], DtNhelpType,   DtHELP_TYPE_TOPIC);  ac++;
 XtSetArg (al[ac], DtNhelpVolume,  "MyVolume");         ac++;
 XtSetArg (al[ac], DtNlocationId,  "getting-started");  ac++;
 XtSetArg (al[ac], DtNcolumns,    40);                  ac++;
 XtSetArg (al[ac], DtNrows,       12);                  ac++;
 XtSetValues (helpDialog, al, ac);
 XtManageChild (helpDialog);

ヘルプ・ボリューム MyVolume が登録されていない場合、DtNhelpVolume の値を指定するためには、MyVolume.sdl ファイルへの絶対パスが必要です。

テキスト文字列を表示するには

  1. 簡易ヘルプ・ダイアログを作成します。

    一般ヘルプ・ダイアログも使用できますが、このダイアログの機能は文字列データにほとんど適用されないので、使用しないようにしてください。

  2. 次のようなヘルプ・ダイアログのリソースを設定します。

    DtNhelpType

    DtHELP_TYPE_DYNAMIC_STRING (行の折り返しを使用する場合) または DtHELP_TYPE_STRING (改行を有効にしたい場合) を設定します。

    DtNstringData

    表示する文字列を設定します。文字列のコピーは内部的に保持されるので、保存する必要はありません。

    サイズやタイトルなど、その他の値も設定できます。

  3. XtManageChild() を使用してダイアログを管理します。

次のプログラム・セグメントは、変数 descriptionString に格納された文字列を表示します。

ac = 0;
 XtSetArg (al[ac], DtNhelpType,   DtHELP_TYPE_DYNAMIC_STRING); ac++;
 XtSetArg (al[ac], DtNstringData, (char *)descriptionString);   ac++;
 XtSetValues (quickHelpDialog, al, ac);
 XtManageChild (quickHelpDialog);

ヘルプ・ダイアログはデータのコピーを自身で作成するので、文字列が不要になった場合はメモリを解放できます。

XtFree (descriptionString);

テキスト・ファイルを表示するには

  1. 簡易ヘルプ・ダイアログを作成するか、ダイアログ・キャッシュの 1 つを取り出します。

    一般ヘルプ・ダイアログも使用できますが、このダイアログの機能のほとんどが標準ヘルプ・トピックについてのみ有効なので、使用しないようにしてください。

  2. 次のようなヘルプ・ダイアログのリソースを設定します。

    DtNhelpType

    DtHELP_TYPE_FILE を設定します。

    DtNhelpFile

    表示するファイル名を設定します。アプリケーションの現在のディレクトリにファイルがない場合は、ファイルへのパスを指定してください。

    サイズやタイトルなど、その他の値も設定できます。特に幅はテキスト・ファイルの標準である 80 に設定します。

  3. XtManageChild() を使用してダイアログを管理します。

次のプログラム・セグメントは、ファイル /tmp/printer.list を表示します。ダイアログのサイズもテキスト・ファイルにより適応するように設定します。

ac = 0;
 XtSetArg (al[ac], DtNhelpType, DtHELP_TYPE_FILE);      ac++;
 XtSetArg (al[ac], DtNhelpFile,  "/tmp/printer.list");  ac++;
 XtSetArg (al[ac], DtNcolumns,  80);                    ac++;
 XtSetArg (al[ac], DtNrows,     20);                    ac++;
 XtSetValues (quickHelpDialog, al, ac);
 XtManageChild (quickHelpDialog);

マニュアル・ページを表示するには

  1. 簡易ヘルプ・ダイアログを作成します。

    一般ヘルプ・ダイアログも使用できますが、このダイアログの機能のほとんどが標準ヘルプ・トピックについてのみ有効なので、使用しないようにしてください。

  2. 次のようなヘルプ・ダイアログのリソースを設定します。

    DtNhelpType

    DtHELP_TYPE_MAN_PAGE を設定します。

    DtNmanPage

    マニュアル・ページ名を設定します。このリソースの値は、システムの man コマンドへ直接渡されます。したがって特定のセクションを指定するときは、通常 man コマンドを入力するときのように、セクション番号の前にマニュアル・ページ名を付けてください。

    サイズやタイトルなど、その他の値も設定できます。

  3. XtManageChild() を使用してダイアログを管理します。

次のプログラム・セグメントは、grep コマンドのマニュアル・ページを表示します。ダイアログのサイズもマニュアル・ページに適応するように設定します。

ac = 0;
 XtSetArg (al[ac], DtNhelpType, DtHELP_TYPE_MAN_PAGE);  ac++;
 XtSetArg (al[ac], DtNmanPage,   "grep");                ac++;
 XtSetArg (al[ac], DtNcolumns,  80);                     ac++;
 XtSetArg (al[ac], DtNrows,     20);                     ac++;
 XtSetValues (quickHelpDialog, al, ac);
 XtManageChild (quickHelpDialog);

ヘルプ・キー ([F1] キー) を使用可能にする

ヘルプ・キー機能は、すべての OSF/Motif マネージャ・ウィジェットとプリミティブ・ウィジェットに組み込まれています。ヘルプ・キーをアクティブにしたいウィジェットにヘルプ・コールバックを追加すると、ヘルプ・キーが使用可能になります。

アプリケーション内では、ヘルプに固有のエントリ・ポイントが必要なウィジェットすべてに、それぞれヘルプ・コールバックを追加してください。そのコールバックを呼び出すまで、ヘルプ・コールバック機能は自動的にウィジェット階層を (シェル・ウィジェットまで) 上ります。

ヘルプ・コールバックをマネージャ・ウィジェットに追加する場合、ヘルプ・キーを任意の子のために押すと、(子ウィジェットに独自のヘルプ・コールバックがなければ) マネージャのヘルプ・コールバックが呼び出されます。

ヘルプ・コールバックを追加するには

    XtAddCallback() 関数を次のように使用します。

XtAddCallback (
       Widget          widget,
       String          DtNhelpCallback,
       XtCallbackProc  HelpRequestCB,
       XtPointer       clientData );
widget

ヘルプ・キーをアクティブにする場所のウィジェット

HelpRequestCB()

ユーザがヘルプ・キーを押したときにヘルプ要求を処理するアプリケーションの関数

clientData

HelpRequestCB() 関数に渡すデータ。通常は表示するトピックを示します。

ユーザがヘルプ・キーを押すと、ウィジェットのヘルプ・コールバックが現在のキーボード・フォーカスと共に呼び出されます。ウィジェットにヘルプ・コールバックがない場合、ヘルプ・コールバックを持つ最も近い先祖のコールバックが呼び出されます。

ヘルプ・コールバックが見つからない場合は何も処理されません。この場合、ヘルプ・コールバックをアプリケーションの各シェルに追加するようにしてください。こうすると、ユーザのヘルプ要求が失われることがありません。

ヘルプ・コールバックをダイアログ・シェルに追加すると、自動的にダイアログの [ヘルプ] ボタンでヘルプ・コールバックを呼び出せるようになります。

クライアント・データの重要性

追加したそれぞれのヘルプ・コールバックで clientData に固有の値を指定すると、各ヘルプ・コールバックを処理するために別々の関数を書かずに済みます。アプリケーションにはすべてのヘルプ要求を処理する 1 つのコールバック・プロシージャを持たせることができます (「ヘルプ・コールバックを追加するには」を参照してください)。コールバック・プロシージャでは、ユーザが要求したヘルプを識別するのに clientData を使用します。つまり、ヘルプ・コールバックを追加するたびに、clientData に固有の値を設定してください。

次の例は、ID をエントリ・ポイントに指定する方法の 1 つを示しています。HelpEntryIds.h ファイルは、各ヘルプ・コールバックの clientData に固有の整数を定義するのに使用します。各ウィジェットに対する 2 つの ID 文字列も定義されます。1 つは通常の [F1] ヘルプ用、もう 1 つはアイテムヘルプ・モード (ユーザがウィジェットから記述を取得する場所) 用です。

たとえば、アプリケーションのユーザ・インタフェースが、Name、Address、Telephone Number という 3 つの入力フィールドを持つメイン・ウィンドウだとします。次の例は HelpEntryIds.h ファイルの内容です。

#define HELP_volumeName            "MyVolume"
 #define HELP_MainWindow            100
 #define HELP_MainWindow_ID         "basic-tasks"
 #define HELP_MainWindow_ITEM_ID    "main-window-desc" 
 #define HELP_NameField             101
 #define HELP_NameField_ID          "specifying-a-name"
 #define HELP_NameField_ITEM_ID     "name-field-desc" 
 #define HELP_AddressField          102
 #define HELP_AddressField_ID       "specifying-an-address"
 #define HELP_AddressField_ITEM_ID  "address-field-desc" 
 #define HELP_PhoneField            103
 #define HELP_PhoneField_ID         "specifying-a-phone-no"
 #define HELP_PhoneField_ITEM_ID    "phone-field-desc"

最初にウィジェットを作成したアプリケーションの一部で、次のようにヘルプ・コールバックが各ウィジェットに追加されます。

XtAddCallback (mainWindow, DtNhelpCallback,
               HelpRequestCB, HELP_MainWindow);
 XtAddCallback (nameField, DtNhelpCallback,
                HelpRequestCB, HELP_NameField);
 XtAddCallback (addressField, DtNhelpCallback,
                HelpRequestCB, HELP_AddressField);
 XtAddCallback (phoneField, DtNhelpCallback,
                HelpRequestCB, HELP_PhoneField);

HelpRequestCB() 関数では、ヘルプ要求を (switch() 文によって) ディスパッチするために clientData パラメータを使用します。ヘルプ・コールバックが [F1] キーによって呼び出された (フラグは「false」) のか、アイテムヘルプ・モードでユーザがウィジェットを選択した (フラグは「true」) のかを調べるため、グローバル・フラグ itemHelp の値が調べられます。

XtCallbackProc HelpRequestCB (
       Widget     w,
       XtPointer  clientData,
       XtPointer  callData )
 {
    char    *topicToDisplay;
    Boolean  useQuickHelpDialog;
    /* Determine the topic ID for the given ` clientData.' */
    switch ((int)clientData)
      {
        case HELP_MainWindow:
          useQuickHelpDialog = False;
          if (itemHelpFlag)
            topicToDisplay = HELP_MainWindow_ITEM_ID;
          else
            topicToDisplay = HELP_MainWindow_ID;
          break;       case HELP_NameField:
          useQuickHelpDialog = True;
          if (itemHelpFlag)
            topicToDisplay = HELP_NameField_ITEM_ID;
          else
            topicToDisplay = HELP_NameField_ID;
          break;       case HELP_AddressField:
          useQuickHelpDialog = True;
          if (itemHelpFlag)
            topicToDisplay = HELP_AddressField_ITEM_ID;
          else
            topicToDisplay = HELP_AddressField_ID;
          break;       case HELP_PhoneField:
          useQuickHelpDialog = True;
          if (itemHelpFlag)
            topicToDisplay = HELP_PhoneField_ITEM_ID;
          else
            topicToDisplay = HELP_PhoneField_ID;
          break;       default:
          /* An unknown clientData was received. */
          /* Put your error handling code here. */
          return;
          break;
      }
    /* Display the topic. */
    ac = 0;
    XtSetArg (al[ac], DtNhelpType,   DtHELP_TYPE_TOPIC); ac++;
    XtSetArg (al[ac], DtNhelpVolume, HELP_volumeName);    ac++;
    XtSetArg (al[ac], DtNhelpType,   topicToDisplay);     ac++;
    if (useQuickHelpDialog)
      {
         XtSetValues (mainQuickHelpDialog, al, ac);
         XtManageChild (mainQuickHelpDialog);
      }
    else
      {
         XtSetValues (mainHelpDialog, al, ac);
         XtManageChild (mainHelpDialog);
      }
    /* Clear the ` item help' flag. */
    itemHelpFlag = False;
  }

上記の関数は、アプリケーションがすべてのヘルプ要求に対して 2 つのヘルプ・ダイアログ (mainHelpDialogmainQuickHelpDialog) を使用し、これらのダイアログがすでに作成されていると想定しています。また、(Xt 引き数リストで使用される) alac が別の場所で宣言されたものと見なしています。

[ヘルプ] メニューの提供

共通デスクトップ環境 スタイル・ガイド』では、各メニュー・バーに [ヘルプ] メニューを含むことを推奨しています。[ヘルプ] メニューには、ユーザがアプリケーションでさまざまなオンライン・ヘルプにアクセスできるように多数のコマンドが入っています。

最も重要なコマンドは次のとおりです。

関連項目

アイテムヘルプ・モードのサポート

一部のアプリケーションは、[ヘルプ] メニューに [アイテムヘルプ] コマンドまたは [ヘルプ・モード] コマンドを備えています。このコマンドはマウス・ポインタを一時的に ? (クエスチョン・マーク) として再定義し、ユーザに画面の項目を選択するようプロンプト要求します。項目を選択すると、その項目の説明をアプリケーションが表示します。

便利な関数に DtHelpReturnSelectedWidgetId() がありますが、これはポインタをクエスチョン・マークに変更してユーザがウィジェットを選択するのを待ちます。選択したウィジェットの ID が返されます。この関数は XmTrackingLocate() に似ていますが、ユーザがエスケープ・キーを押してオペレーションを取り消すと NULL を返す点が異なります。

選択した項目のヘルプを表示するには、単に返されたウィジェットのヘルプ・コールバックを呼び出すだけです。これはウィジェットの使用中にユーザが [F1] キーを押すのと同じことです。

アイテムヘルプと F1 ヘルプとを区別させる場合は、ウィジェットのヘルプ・コールバックを呼び出す前にフラグを設定します。こうすると、アイテムヘルプの結果として呼び出すコールバックを判別するのにそのフラグを使用し、それに従って応答するようになります。

アイテムヘルプのサポートを追加するには

  1. DtHelpReturnSelectedWidgetId() 関数を使用して関数を記述します。この関数では、選択したウィジェットのヘルプ・コールバックを呼び出します。次のステップではこの関数を ProcessOnItemHelp() と呼びますが、他の名前を付けることもできます。

  2. [ヘルプ] メニューに [アイテムヘルプ] というラベルの付いたコマンドを追加します。ProcessOnItemHelp() 関数を呼び出すアクティブ・コールバックを追加します。

  3. アイテム・ヘルプを使用するアプリケーションの各ウィジェットに、ヘルプ・コールバックを追加します。

選択したウィジェットにヘルプ・コールバックがない場合、アプリケーションはその親ウィジェットの検索を試みます。同様に、親ウィジェットにない場合はその上の階層を検索し、ヘルプ・コールバックが見つかるまで試行を繰り返します。

次のプロシージャは ProcessOnItemHelp() 関数の例ですが、これは [ヘルプ] メニューから [アイテムヘルプ] を選択すると呼び出されます。

void  ProcessOnItemHelp(
   Widget widget)
 {
  /* Declare a variable for the selected widget. */ 
  Widget selWidget=NULL;
   int status=DtHELP_SELECT_ERROR;
  /* Get an application shell widget from our widget hierarchy to
        * pass into DtHelpReturnSelectedWidgetId().
    */
  while (!XtIsSubclass(widget, applicationShellWidgetClass))
                    widget = XtParent(widget);
  status = DtHelpReturnSelectedWidgetId(widget, NULL, &selWidget);
  switch ((int)status)
     {
       case DtHELP_SELECT_ERROR:
         printf("Selection Error, cannot continue¥n");
      break;
      case DtHELP_SELECT_VALID:
          /* We have a valid widget selection, now let's look for a registered help
                        * callback to invoke.
           */
         while (selWidget != NULL)
           {
             if ((XtHasCallbacks(selWidget, XmNhelpCallback)
                                      == XtCallbackHasSome))
               {
                 /* Found a help callback, so just call it */
                XtCallCallbacks((Widget)selWidget,
                                 XmNhelpCallback,NULL);
                 break;
               }
            else
              /* No help callback on current widget, so try the widget's parent  */
                 selWidget = XtParent(selWidget);
           }
      break;
       case DtHELP_SELECT_ABORT:
         printf("Selection Aborted by user.¥n");
      break;
      case DtHELP_SELECT_INVALID:
         printf("You must select a component within your app.¥n");
      break;
     }
 }