桐の釣魚大全のトップ > フォームアプリケーション教書 第2部
トップページに戻る

鋭意校正中です。
念のためにブラウザでF5キーを押してリロードしてからお読みください。


フォームアプリケーション教書 第2部 ― 桐のイベント処理の詳細な解説

        目次
 21   レコードの絞り込み
 21.1 桐の[検索条件]はQBE
 21.2 [絞り込み:検索条件]コマンドによるレコードの絞り込み
 21.3 [絞り込み(検索):比較式]は、ただ一つだけのマス目にしたQBE
 21.4 [絞り込み:比較式]コマンドによるレコードの絞り込み
 21.5 [絞り込み(検索):比較式]コマンドの高度な使い方
 21.6 比較式の左辺と右辺の両方に計算式を指定する
 21.7 表の[未定義値項目処理]と比較式・計算式

 22   レコードの絞り込み結果の判定
 22.1 絞り込み状態を解除する
 22.2 #eof ・ #終端行 による判定

 23   レコードの探索(検索)

 24   フォームの編集対象表を多重化する
 24.1 [多重化]コマンド

 25   命名規則
 25.1 オブジェクト名の付け方
 25.2 変数名の付け方
 25.3 プロシージャ(手続き)名の付け方

 26   イベントプロシージャ(イベントハンドラ)を実行する

 27   プロシージャ(手続き)の引数
 27.1 引数はなぜ必要なのか?
 27.2 ひとつのプロシージャはひとつの機能を担当する
 27.3 引数の[値渡し]と[参照渡し]
 27.4 実引数と仮引数
 27.5 配列変数の[値渡し]と[参照渡し]

 28   配列変数の操作
 28.1 配列変数のソート
 28.2 指定した文字列を要素番号1にセットする
 28.3 指定した要素番号の文字列を削除する
 28.4 指定した文字列の要素番号を得る
 28.5 要素番号1に指定した文字列を挿入する

 29   半角コンマで区切った文字列を利用する

 30   論理と条件式
 30.1 [比較式]と[条件式]の違い
 30.2 桐の論理値
 30.3 条件式の書き方

 31   if と 条件式
 31.1 条件式の評価を変数に代入する
 31.2 if とプログラムのテスト

 32   繰り返し と 条件式

 33   スピンボタン

 34   リピート(マウスボタンを押している間実行し続ける)ボタン

 35   プログレスバー
 35.1 内部プログレスバーと外部プログレスバー
 35.2 プログレスバー実行中に作業を中断する
 35.3 プログレスバーの事例

 36   フォームとフォームの間での変数の受け渡し
 36.1 [主ウィンドウ]のウィンドウハンドル番号
 36.2 INF_Framework のHLDVAR機能

 37   メイン&サブフォーム
 37.1 [サブフォーム]オブジェクトの[グループ値リスト]属性
 37.2 メインフォームとサブフォームのイベントの発生順
 37.3 局所変数の上書きとその対策
 37.4 INF_Framework とメイン&サブフォーム
 37.5 リンクしないサブフォーム

 38   手続きの入れ子 手続きの[再帰呼び出し]
 38.1 手続きのネスト(入れ子)
 38.2 再帰呼び出し

 39   テキストボックスと局所変数

 40   [トレース出力]ウィンドウと[トレース出力]コマンド
 40.1 手続き実行開始,手続き実行終了
 40.2 [トレース出力]コマンド
 40.3 整形ユーティリティでトレース出力結果を整形する


21 レコードの絞り込み

21.1 桐の[検索条件]はQBE
 桐の[検索条件]は、[例示による問い合わせ( QBE、英: Query by Example)]そのものです。
QBEは、関係データベース (リレーショナルデータベース) 向けの問い合わせ言語の一つで、桐やMicrosoft Access・他でサポートされています。
 [検索条件]は、項目数×10行のマトリクス(表組み:テーブル)の空欄記入方式のユーザインターフェースです。
マトリクスの中に[データ]と[比較演算子]の組み合わせである[比較式]を記入することで、[比較式]を満たすレコードを絞り込めます。

【比較演算子】 ※比較演算子は、全角でも半角でもかまいません
 ・含む    … ワイルドカード( * ) ※ ×も使える
 ・前方一致  … ワイルドカード( * ) ※ ×も使える
 ・後方一致  … ワイルドカード( * ) ※ ×も使える
 ・等しい   … 等号 ( = )
 ・等しくない … 等号 ( <> ) ※ ≠も使える 注意:><も使えるが外部データベースでは不可
 ・より大きい … 不等号( > )
 ・以上    … 不等号( >= ) ※ =>, ≧も使える
 ・以下    … 不等号( <= ) ※ =<, ≦も使える
 ・より小さい … 不等号( < )

 【引用】例示による問い合わせ 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  例示による問い合わせ (れいじによるといあわせ、QBE、英: Query by Example) は、関係データベース (リレーショナルデータベース) 向けの問い合わせ言語の一つである。
  QBEは、1970年代半ばにアメリカ合衆国ニューヨーク州ヨークタウンのIBM研究センターで、別の問い合わせ言語SQLの開発と並行して、モシェ・ズルーフが考案した。
  QBEは、最初の視覚的な問い合わせ言語である。
  QBEでは関係の視覚的表現として表を使い、利用者は表に対して命令、例示、および条件を入力する。
  現在、データベース向けの多くの視覚的なフロントエンドは、QBEを源流とする創意工夫を採用している。
  QBEはもともとは、機能をデータ検索のみに限定していた。
  しかし後に挿入、削除、および更新、さらに一時表の生成など、検索以外のデータ操作もできるように拡張された。


 Fig.19 コマンドボタンの機能名:絞り込み_条件名

21.2 [絞り込み:検索条件]コマンドによるレコードの絞り込み
 [検索条件]の空欄記入方式のユーザインターフェースは、非定型処理を会話操作する場合には向いています。
しかし、定型処理(ルーチンワーク)を機械化(コンピュータ化)したアプリケーションには適していません。
従って、アプリケーションでは、[絞り込み:検索条件]コマンドを利用します。
[絞り込み:検索条件]コマンドでは、空欄記入方式のユーザインターフェースを表示することなくレコードを絞り込みます。

 ■[絞り込み:検索条件]コマンドを用いた絞り込み

 ―文字列型の場合
 項目[氏名]で"子"を含んでいるレコードを絞り込みたい場合には次のようにします。

 (例1)
 検索条件登録 "",{[氏名]{ *"子"* }}
 解除 *
 絞り込み 条件名 = ""       /* 標準の処理条件を指定 */

 注意:標準の条件名を使用する場合は「""」を指定します

 (例2)
 検索条件登録 "検索条件01",{[氏名]{ *"子"* }}
 解除 *
 絞り込み 条件名 = "検索条件01"  /* 処理条件名を指定 */

 注意:登録されていない条件名を指定するとエラーになります。
 (参考例)
 絞り込み 条件名 = #処理条件名( 3,#処理条件数( 3 ) ) /* 処理条件の登録数の値は、最後に登録した処理条件を示す */

 以下の関数で[検索条件]を指定するには、引数に3を指定する
 #処理条件名( 3, n )    … 登録されている処理条件名を取り出します
                 ※11:読み込み条件/12:書き出し条件では、#処理条件名( f1, f2, n )
 #処理条件数( 3 )     … 登録数を調べます
 #処理条件名検索( 3, str ) … str が何番目に登録されているかを調べます 存在しなければ未定義値を返します
                ※11:読み込み条件/12:書き出し条件では、#処理条件名( f1, f2, str )
                str 検索する処理条件名を指定します
                標準の処理条件があるかどうかを検索する場合は、未定義値として "" を指定します
                標準の処理条件が存在する場合は0、存在しなかった場合は未定義が返ります
                索引とグラフ、一覧表印刷には、標準の処理条件はありません

 ―数値の場合
 項目[体重]で50以上かつ60以下の値を含んでいるレコードを絞り込みたい場合には次のようにします。

 (例3)
 検索条件登録 "",{[体重]{ >= 50, <= 60 }}
 解除 *
 絞り込み 条件名 = ""        /* 標準の処理条件を指定 */

  または

 検索条件登録 "",{[体重]{ 50 <= [] <= 60 }}
 解除 *
 絞り込み 条件名 = ""        /* 標準の処理条件を指定 */

 (例4)
 検索条件登録 "検索条件02",{[体重]{ >= 50, <= 60 }}
 解除 *
 絞り込み 条件名 = "検索条件02"  /* 処理条件名を指定 */

  または

 検索条件登録 "検索条件02",{[体重]{ 50 <= [] <= 60 }}
 解除 *
 絞り込み 条件名 = "検索条件02"  /* 処理条件名を指定 */

21.3 [絞り込み(検索):比較式]は、ただ一つだけのマス目にしたQBE
 GUIの[検索条件]のマトリクスを、ただ一つだけのマス目にしたものがGUIの[絞り込み(検索):比較式]です。


 Fig.20 コマンドボタンの機能名:絞り込み_比較式

21.4 [絞り込み:比較式]コマンドによるレコードの絞り込み
 [絞り込み(検索):比較式]の空欄記入方式のユーザインターフェースは、非定型処理を会話操作する場合には向いています。
しかし、定型処理(ルーチンワーク)を機械化(コンピュータ化)したアプリケーションには適していません。
従って、アプリケーションでは、[絞り込み(検索):比較式]コマンドを利用します。
[絞り込み(検索):比較式]コマンドでは、空欄記入方式のユーザインターフェースを表示することなくレコードを絞り込みます。

 ■[絞り込み(検索):比較式]コマンドを用いた絞り込み

 ―文字列型の場合

 項目[氏名]で"子"を含んでいるレコードを絞り込みたい場合には次のようにします。

 (例5)
 解除 *
 絞り込み [氏名]{ *"子"* }, 文字比較方法 = 自動 /* 自動|文字符号|辞書順|拡張辞書順 */

 (例6)
 解除 *
 絞り込み [氏名]{ *"子"* }       /* 文字比較方法 = 自動 は省略可能 */

  または

 解除 *
 絞り込み [氏名]{ = *"子"* }      /* 文字比較方法 = 自動 は省略可能 */

  または

 解除 *
 絞り込み [氏名]{ [] = *"子"* }     /* [] は [氏名] として扱われる */

  または

 解除 *
 絞り込み [ほか]{ [氏名] = *"子"* }   /* [ほか] は任意の項目名 */

 ―数値の場合

 項目[体重]で50以上かつ60以下の値を含んでいるレコードを絞り込みたい場合には次のようにします。

 (例7)
 解除 *
 絞り込み [体重]{ >= 50, <= 60 }

  または

 解除 *
 絞り込み [体重]{ []>= 50, []<= 60 }   /* [] は [体重] として扱われる */

  または

 解除 *
 絞り込み [氏名]{ [体重] >= 50, [体重] <= 60 }

  または

 解除 *
 絞り込み [体重]{ 50 <= [] <= 60 }    /* [] は [体重] として扱われる */

  または

 解除 *
 絞り込み [ほか]{ 50 <= [体重] <= 60 }  /* [ほか] は任意の項目名 */

 ―未定義のものを絞り込む

 項目の値が空っぽ(未定義)のレコードを絞り込みたい場合には次のようにします。

 (例8)
 解除 *
 絞り込み [氏名]{ = #未定義 }

  または

 解除 *
 絞り込み [氏名]{ #未定義 }       /* = は省略可能 */

  または

 解除 *
 絞り込み [氏名]{ [] = #未定義 }    /* [] は [氏名] として扱われる */

  または

 解除 *
 絞り込み [ほか]{ [氏名] = #未定義 }  /* [ほか] は任意の項目名 */

 ―定義のものを絞り込む

 項目に値がある(定義)のレコードを絞り込みたい場合には次のようにします。

 (例9)
 解除 *
 絞り込み [氏名]{ = #定義 }

  または

 解除 *
 絞り込み [氏名]{ #定義 }       /* = は省略可能 */

  または

 解除 *
 絞り込み [氏名]{ [] = #定義 }    /* [] は [氏名] として扱われる */

  または

 解除 *
 絞り込み [ほか]{ [氏名] = #定義 }  /* [ほか] は任意の項目名 */

 <注意>
  【「桐のヘルプ」の「データと式」→「比較式」→「仕様(比較式)」より】
  ・ノート
  つぎの関数を使うときは、左辺か右辺の一方が項目名でなければいけません。
  #未定義
  #定義
  #削除

 ■道草
 おそらく多くの人が、[絞り込み:比較式]コマンドで波括弧({})を省略した記述を見た経験があると思います。
例えば、次のように試してみることが可能です。

 絞り込み [体重]{ = 60 }
  ↓
 絞り込み [体重] = 60 /* 波括弧({})を省略しちゃった! */
 これは、波括弧({})を省略しても、構文解釈が可能だからだと推測されます。
しかし、著者( ONnoji )は、波括弧({})を省略しない方が良いと考えます。

 ■[絞り込み:検索条件]コマンドと[絞り込み(検索):比較式]コマンドでは波括弧({})の使い方が異なる
 時々、[絞り込み:検索条件]コマンドと[絞り込み(検索):比較式]コマンドは、どちらも表記法が同じだろうと高を括ってコマンドをコピペして失敗する人がいます。
以下に同等の条件を示します。
単純にコピペしてはいけないことが判ると思います。

 【検索条件】
 検索条件(S):
 ┌───┬────┬───────┬────
 │   │ 性別 │  体重   │ ほか   【コマンド】
 ├───┼────┼───────┼────
 │条件1 │"女性" │ ≧ 25, ≦50 │      検索条件登録  "",{[性別]{"女性"}, [体重]{ ≧ 25, ≦50 }}
 │条件2 │    │       │      絞り込み 条件名 = ""
 │条件3 │    │       │
 : : :    :       :
 : : :    :       :      × 絞り込み [ほか]{[性別]{"女性"}, [体重]{ ≧ 25, ≦50 }}
 │条件10│    │       │
 └───┴────┴───────┴────  ○ 絞り込み [ほか]{[性別] = "女性", [体重]≧ 25,[体重]≦ 50 }
 【絞り込み:比較式】

 項目名(N): [ほか]               【コマンド】
 比較式(H):
 [性別] = "女性",[体重]≧ 25,[体重]≦ 50    絞り込み [ほか]{ [性別] = "女性",[体重]≧ 25,[体重]≦ 50 }


21.5 [絞り込み(検索):比較式]コマンドの高度な使い方

 ■[直接記述した値(リテラル)]の代わりに[変数]を利用してコマンドを実行する
 例えば、項目[氏名]で"子"を含んでいるレコードを絞り込みたい場合には次のようにしますが、

 解除 *
 絞り込み [氏名]{ *"子"* } /* 文字比較方法 = 自動 は省略可能 */

 "子"以外の文字を指定したくても、直接値(リテラル)を記述しているのですからこのままでは無理です。
 そこで、融通が利くように変数を利用します。
 "子"以外の文字を指定する場合には、↓以下のように文字列型の変数に文字を代入して
 ※例では"田"を代入しています

 (例10)
 解除 *
 &STR = "田"
 絞り込み [氏名]{ *&STR* }

 とします。
 これは、"子"といった値を直接指定(リテラル)するのではなく、値を変数に代入して指定した効果です。

 ■[比較式自身を変数に代入]してコマンドを実行する
 値自身を変数に代入しても、ワイルドカード( * )は直接指定(リテラル)のままです。
例えば、先頭一致・含む・末尾一致の3通りの動作をさせる場合にはどうしたらよいでしょうか?

 (例11)
 変数宣言 自動,文字列{ &string }

 解除 *
 &string = "田"
 ケース開始
  ケース ( 先頭一致条件 )
   絞り込み [氏名]{ &string* }

  ケース ( 含む条件 )
   絞り込み [氏名]{ *&string* }

  ケース ( 末尾一致条件 )
   絞り込み [氏名]{ *&string }

 ケース終了

 ↑上のように3通りの[絞り込み:比較式]コマンドを用意するのもアリです。
 しかし、↓下のように比較式自身を変数に代入して実行すれば、もっと柔軟に対応できます。

 (例12)
 変数宣言 自動,文字列{ &string }
 変数宣言 自動,文字列{ &expression }        /* 表現  */
 変数宣言 自動,文字列{ &WQ = #jis( #hex("22") ) } /* 二重引用符 */
 変数宣言 自動,整数 { &拡張辞書順 }

 :

 &拡張辞書順 = 1 /* 1:ON 0:OFF */
 &string   = "田"

 ケース開始
  ケース ( 先頭一致条件 )
   &expression = &WQ + &string + &WQ + "*" + #cond( &拡張辞書順, ":E" )

  ケース ( 含む条件 )
   &expression = "*" + &WQ + &string + &WQ + "*" + #cond( &拡張辞書順, ":E" )

  ケース ( 末尾一致条件 )
   &expression = "*" + &WQ + &string + &WQ + #cond( &拡張辞書順, ":E" )

 ケース終了

 解除 *
 絞り込み [氏名]_&expression

 さらに、↓以下のように項目名も変数で指定すれば、もっと柔軟に対応できます。

 (例13)
 変数宣言 自動,文字列{ &fieldName } /* 項目名 */

 :

 &fieldName = "氏名" /* 項目名に角カッコ([])は含めない */
 解除 *
 絞り込み &fieldName_&expression

 さらに、初級者には複雑に見えますがケース文なしでも可能です。

 (例14)
 変数宣言 自動,文字列{ &string }
 変数宣言 自動,文字列{ &expression }         /* 表現  */
 変数宣言 自動,文字列{ &WQ = #jis( #hex("22") ) }  /* 二重引用符 */
 変数宣言 自動,整数 { &拡張辞書順 }
 変数宣言 自動,整数 { &部分一致 }

 :

 &拡張辞書順 = 1   /* 1:ON 0:OFF */
 &部分一致  = 2    /* 1:先頭一致 2:部分一致 3:末尾一致 */
 &string   = "田"

 &expression = #cond( &部分一致 <> 1, "*" ) + &WQ + &string + &WQ + #cond( &部分一致 <> 3, "*" ) + #cond( &拡張辞書順, ":E" )
 &fieldName = "氏名"
 解除 *
 絞り込み &fieldName_&expression


 ■[比較式自身を変数に代入]して実行する際の注意点

 ―文字列の前後を二重引用符を囲む
 以下の例では、[絞り込み 比較式]コマンドの実行時に[KD1084:比較式の形式に誤りがあります]というエラーメッセージが表示されます。

 (例15)
 &string   = "101-0021"
 &expression = "*" + &string + "*"
 &fieldName = "郵便番号"
 解除 *
 絞り込み &fieldName_&expression ← [KD1084:比較式の形式に誤りがあります]

 こうなった理由は、&expression の中に二重引用符が含まれていなかったからです。
つまり、101-0021 を整数同士の減算と判定して、数値として処理したからです。

 このエラーは、数字の文字列中に算術演算子( +, -, *, /, ^, % )を含んでいる場合に起こります。
従って、↓以下のように文字列データの前後を二重引用符で囲むようにします。

 (例16)
 &WQ     = #jis( #hex("22") )  /* 二重引用符 */
 &string   = "101-0021"
 &expression = "*" + &WQ + &string + &WQ + "*"
 &fieldName = "郵便番号"
 解除 *
 絞り込み &fieldName_&expression

以下の例では、[絞り込み 比較式]コマンドの実行時に[KD1617:許されていない演算子とデータ型の組合わせがあります]というエラーメッセージが表示されます。

 (例17)
 &string   = "A-B"
 &expression = "*" + &string + "*"
 &fieldName = "郵便番号"
 解除 *
 絞り込み &fieldName_&expression ← [KD1617:許されていない演算子とデータ型の組合わせがあります]

 こうなった理由も、&expression の中に二重引用符が含まれていなかったからです。
文字列中に空白文字が含まれていたり、記号文字が含まれている場合が該当します。
 このようなエラーを起こさないように、[文字列では前後を二重引用符を囲む]ということ忘れないでください。
↓以下のようにすればエラーは発生しません。

 (例18)
 &WQ     = #jis( #hex("22") )  /* 二重引用符 */
 &string   = "A-B"
 &expression = "*" + &WQ + &string + &WQ + "*"
 &fieldName = "郵便番号"
 解除 *
 絞り込み &fieldName_&expression

以下の例では、[絞り込み 比較式]コマンドの実行時に[KD1641:文字列に誤りがあります]というエラーメッセージが表示されます。

 (例19)
 &string   = "account@hoge.ne.jp"
 &expression = "*" + &string + "*"
 &fieldName = "郵便番号"
 解除 *
 絞り込み &fieldName_&expression ← [KD1641:文字列に誤りがあります]

 これも、&expression の中に二重引用符が含まれていなかったからです。
文字列中に空白文字が含まれていたり、記号文字が含まれている場合が該当します。
このようなエラーを起こさないように、[文字列では前後を二重引用符を囲む]ということ忘れないでください。
↓以下のようにすればエラーは発生しません。

 (例20)
 &WQ      = #jis( #hex("22") )  /* 二重引用符 */
 &string   = "account@hoge.ne.jp"
 &expression = "*" + &WQ + &string + &WQ + "*"
 &fieldName = "郵便番号"
 解除 *
 絞り込み &fieldName_&expression

21.6 比較式の左辺と右辺の両方に計算式を指定する
 桐のヘルプに非常に重要なことが[ノート]として書かれているが、それに気が付いた人は非常に少ないと思います。
以下の引用します。

 【引用】「桐のヘルプ」の「データと式」→「比較式」→「仕様(比較式)」
  ノート
  ・ワイルドカード(*、×)を使うときは、左辺か右辺の一方が項目名でなければいけません。
  ・ワイルドカードを含む文字列を検索するときは、かならず検索する文字列を二重引用符でくくってください。たとえば文字列中の「×」を検索する場合は「"×"」としなければいけません。
  ・旧バージョンでは、左辺か右辺のいずれかが項目名でなければいけませんでしたが、本バージョンからは、左辺と右辺の両方に計算式を指定できます。
  ・つぎの関数を使うときは、左辺か右辺の一方が項目名でなければいけません。
   #未定義
   #定義
   #削除

 さて、この[ノート]で、最も重要なのは次の文言です。

  ・旧バージョンでは、左辺か右辺のいずれかが項目名でなければいけませんでしたが、本バージョンからは、左辺と右辺の両方に計算式を指定できます。

 実は、この文言の[旧バージョン]とはDOS桐のことです。そして[本バージョン]とはWin桐のことです。
つまり、「Win桐からは、比較式の左辺と右辺の両方に計算式を指定できます」という意味です。
といっても、多くの人にはチンプンカンプンだろうと思いますので、具体例を以下に示します。

 絞り込み [氏名]{ #条件選択( 条件式, [氏名], 1, [氏名] + "A" ) } ※条件式は任意

上↑は、DOS桐時代によく用いられた条件式を使った[絞り込み 比較式]コマンドです。
しかし、比較式の左辺が省略されているために、このままでは非常に分かりにくいので、
以下↓のように比較式の左辺を補います。

 絞り込み [氏名]{ [] = #条件選択( 条件式, [氏名], 1, [氏名] + "A" ) }   ※条件式は任意
  または、
 絞り込み [ほか]{ [氏名] = #条件選択( 条件式, [氏名], 1, [氏名] + "A" ) }  ※条件式は任意

 このように左辺には暗黙のうちに項目名があります。
このことを、「旧バージョンでは、左辺か右辺のいずれかが項目名でなければいけませんでした」と言っているのです。

この比較式は、実に巧妙に出来ていて、

 条件式が真ならば、絞り込み [ほか]{ [氏名] = [氏名] }        ← 必ず一致する
 条件式が偽ならば、絞り込み [ほか]{ [氏名] = [氏名] + "任意の文字" }← 必ず不一致する

という仕掛けになっています。
つまり、条件式が偽ならば、任意の文字を連結して不一致になるようにしています。

そして、数値の場合には、

 条件式が真ならば、絞り込み [ほか]{ [体重] = [体重] }                ← 必ず一致する
 条件式が偽ならば、絞り込み [ほか]{ [体重] = [体重] + ゼロ(0)以外の任意の数値 }← 必ず不一致する

という仕掛けで、
条件式が偽ならば、ゼロ(0)以外の任意の数値を加算して不一致になるようにしています。

分かりやすく、左辺を補うと以下↓のように、

 絞り込み [体重]{ [] = #条件選択( 条件式, [体重], 1, [体重] + 1 ) }   ※条件式は任意
  または、
 絞り込み [ほか]{ [体重] = #条件選択( 条件式, [体重], 1, [体重] + 1 ) } ※条件式は任意

そして、比較式の左辺を省略すると、

 絞り込み [体重]{ #条件選択( 条件式, [体重], 1, [体重] + 1 ) }     ※条件式は任意

となります。

 皆さんいかがでしょうか、[実に判りにくくてトリッキーな仕掛け]と言うべきだとは思いませんか?
しかし、DOS桐の場合には「左辺か右辺のいずれかが項目名でなければいけません」というのですから、これしか方法がなかったのです。

 ちなみに、著者( ONnoji )が[桐井戸端BBS]を見るようになったのは桐ver.8 sp4 の時からですが、
掲示板の回答は[実に判りにくくてトリッキーな仕掛け]のオンパレードでした。
その頃は、「Win桐からは、比較式の左辺と右辺の両方に計算式を指定できます」と気が付いた人は非常に少数だったと思います。

 さて、「比較式の左辺と右辺の両方に計算式を指定できます」というのですから、[レガシーな手法]と[Win桐の手法]の違いを以下に示します。※条件式は任意

 レガシー: 絞り込み [氏名]{ #条件選択( 条件式, [氏名], 1, [氏名] + "A" ) }※条件式は任意

 Win桐: 絞り込み [氏名]{ ( 条件式 ) = 1 }
        または、
       絞り込み [ほか]{ ( 条件式 ) = 1 }

 レガシー: 絞り込み [体重]{ #条件選択( 条件式, [体重], 1, [体重] + 1 ) } ※条件式は任意

 Win桐: 絞り込み [体重]{ ( 条件式 ) = 1 }
        または、
       絞り込み [ほか]{ ( 条件式 ) = 1 }

 ↑上を見て分かるように、[レガシーな手法]よりも[Win桐の手法]の方が圧倒的にシンプルです。
ちなみに、条件式をカッコで囲むと、条件が真の場合にイチ(1)、偽の場合にゼロ(0)になります。
[Win桐の手法]はこの性質を利用したものです。

 ちなみに、「桐のヘルプ」の「データと式」→「比較式」→「仕様(比較式)」には、以下の例があります。

 #文字数([住所])<=30
 #日時日付([])=#日時日付(#日数加算(#日時値,-3))
 ↑これらは「比較式の左辺と右辺の両方に計算式を指定できます」の例そのものです。

 なお、条件式にはワイルドカード( * )は使えませんので注意してください。
 また、条件式に範囲( 小 < [] < 大 )を使用した場合には希望通りの判定にはなりませんので使用しないでください。

 【引用】「桐のヘルプ」の「データと式」→「条件式」→「条件式の基礎知識」
  ・つぎの式は比較式でのみ有効です。条件式では希望どおりの判定にはなりせんので、書かないように心がけてください。
  (誤)20<=[年齢]<=30
  (正)20<=[年齢] .and [年齢]<=30

   条件式で使用できる演算子
   条件式では、算術演算子以外に=や≧などの比較演算子、.and や .or などの論理演算子が使用できます。条件式で使用できる演算子と、演算子の優先順序はつぎのとおりです。

  種類 演算子     優先順位
  算術演算子
   ( )        1
   ^         2
   ×、*      3
   ÷、/      3
   %        3
   +、−      4
  比較演算子
   >        5
   <        5
   ≦、<=、=<    5
   ≧、>=、=>    5
   ≠、<>、><    5
  論理演算子
   .not       6
   .and       7
   .or        8

  ・括弧を 30 重まで入れ子にして、評価の優先順位を変更できます。
  ・論理演算子の前後は、かならず1文字以上の空白を入れてください。

21.7 表の[未定義値項目処理]と比較式・計算式
 表の[未定義値項目処理]は、計算式から数値系の項目を扱うとき、項目値が未入力(空欄)の場合に項目値をゼロとして計算するか、未定義として計算するかを指定します。
なお、この指定は計算式から数値系の項目を扱う場合に適用されますが、絞り込み(検索)の比較式の場合には適用されません。

 絞り込み [数値系項目]{ #u }  /* 比較演算子を省略 */
 絞り込み [数値系項目]{ = #u } /* 比較演算子付   */
 絞り込み [数値系項目] = #u    /* 波括弧({})を省略 この省略は誤解の元になるので省略しない方がよいです */

上のように、値が未入力(空欄)のレコードを何の問題もなく絞り込めます(検索も同じです)。
しかし、計算式では影響がありますので注意してください。

 絞り込み [ほか]{ ( [数値系項目] = #u ) = 1 }

上の場合、表の[未定義値項目処理]は[ゼロ]の場合には、値が未入力(空欄)のレコードは絞り込まれません。
なぜならば、値が未入力(空欄)の項目値は[ゼロ]として扱われるので、[数値系項目] = #u の式は常に偽になるためです。
そこで、この場合には以下のようにする必要があります。

 絞り込み [ほか]{ ( #横合計( [数値系項目], [数値系項目] ) = #u ) = 1 }

このように表の[未定義値項目処理]の設定は、一方の比較式には影響せず、他方の計算式では影響を受けます。

 × 絞り込み [ほか]{ ( [数値系項目] = #u ) = 1 }
 〇 絞り込み [ほか]{ ( #横合計( [数値系項目], [数値系項目] ) = #u ) = 1 }

比較式と計算式の違いによって結果が異なるので、不思議の思う人が非常に多いですが、以上がその理由です。

【引用】ファイル属性([ファイル]メニュー)|桐 - ヘルプより
  [未定義項目値処理]
 計算式から項目を扱うとき、未定義の項目値をゼロとして計算するか、未定義として計算するかを指定します。
 未定義の項目を未定義として計算した場合、計算結果は未定義になります。
 集計関数では、この属性に関係なく、未定義値のデータを集計対象として扱いません。
 たとえば、#件数には含まれません。
 検索と絞り込み、グループ選択時は、未定義値をつねに未定義として扱います。

22 レコードの絞り込み結果の判定
 [絞り込み:比較式]コマンドなどでレコードを絞り込んだ時、
実行結果は、
 ・比較式を満たすレコードがある
 ・比較式を満たすレコードがない
のどちらかです。

22.1 絞り込み状態を解除する
 フォームの編集対象表、または任意の表のレコードを絞り込む時、全レコードを対象にする場合にはコマンド実行前に[絞り込み状態を解除]します。

 (例21)※これは例14と同じです

 変数宣言 自動,文字列{ &string }
 変数宣言 自動,文字列{ &expression }         /* 表現  */
 変数宣言 自動,文字列{ &WQ = #jis( #hex("22") ) }  /* 二重引用符 */
 変数宣言 自動,整数 { &拡張辞書順 }
 変数宣言 自動,整数 { &部分一致 }

 :

 &拡張辞書順 = 1   /* 1:ON 0:OFF */
 &部分一致  = 2   /* 1:先頭一致 2:部分一致 3:末尾一致 */
 &string   = "田"

 &expression = #cond( &部分一致 <> 1, "*" ) + &WQ + &string + &WQ + #cond( &部分一致 <> 3, "*" ) + #cond( &拡張辞書順, ":E" )
 &fieldName = "氏名"
 解除 *
 絞り込み &fieldName_&expression

 通常、全レコードを対象にすることが多いので、[解除 *]コマンドまたは[絞り込み解除 *]コマンドを実行するのが基本になります。

 ・[解除 *]コマンドは、[絞り込み状態]または[索引を使用した整列状態]を解除します
 ・[絞り込み解除 *]コマンドは、[絞り込み状態]だけを解除します

 もちろん、絞り込みのレベルをさらに深くする場合には解除する必要はありません。

22.2 #eof ・ #終端行 による判定
 [絞り込み:比較式]コマンドなどでレコードを絞り込んだ時、
実行結果は、
 ・比較式を満たすレコードがある
 ・比較式を満たすレコードがない
のどちらかです。
 この状態を判定するには #eof 関数を使用します。
#eof は #終端行 の別名です。本書では、プログラミング関係の用語として一般的な名称である #eof で統一します。
ちなみに、eof とは end of file(ファイルの終わり)の意味です。

 (例22)

 解除 *
 絞り込み &fieldName_&expression

 if ( .not #eof )

  ** 比較式を満たすレコードがある、つまり絞り込み成功

 else

  ** 比較式を満たすレコードがない、つまり絞り込み不成功

 end

 上の例の[絞り込み]コマンドを以下のように[検索]コマンドに置き換えてもそのまま使えます。

 解除 *
 検索 &fieldName_&expression

 if ( .not #eof )

  ** 比較式を満たすレコードがある、つまり探索成功

 else

  ** 比較式を満たすレコードがない、つまり探索不成功

 end

 このように、#eof による判定は[絞り込み]コマンドと[検索]コマンドのどちらにも使えて便利です。

 なお、[絞り込み]コマンドを実行すると、組み込み変数の &選択件数に絞り込まれた行数が代入されます。
 この性質を利用する場合には次のようになります。

 (例23)
 解除 *
 絞り込み &fieldName_&expression

 if ( &選択件数 <> 0 )

  ** 比較式を満たすレコードがある、つまり絞り込み成功

 else

  ** 比較式を満たすレコードがない、つまり絞り込み不成功

 end

 しかし、さらに別の[絞り込み]コマンドを実行すれば、 &選択件数の値は書き変わってしまいますので、

 変数宣言 自動,長整数{ &reccount }
 :

 解除 *
 絞り込み &fieldName_&expression
 &reccount = &選択件数

 if ( &reccount <> 0 )

  ** 比較式を満たすレコードがある、つまり絞り込み成功

 else

  ** 比較式を満たすレコードがない、つまり絞り込み不成功

 end

 とすることになるでしょう。
しかし、この方法は[検索]コマンドでは使えません。
なぜならば、組み込み変数の &選択件数の値は[検索]コマンドの実行結果を反映しないからです。
 従って、#eof を利用する方法と、&選択件数 を利用する方法を比べたならば、#eof を利用する方が優れています。
とはいえ、絞り込まれたレコードの数の情報も必要なことが多いので、一般的には次のようになります。

 (例24)
 変数宣言 自動,長整数{ &reccount }
 :

 解除 *
 絞り込み &fieldName_&expression
 &reccount = &選択件数      /* 絞り込みコマンドの直後に件数を取得する */

 if ( .not #eof )

  ** 比較式を満たすレコードがある、つまり絞り込み成功

 else

  ** 比較式を満たすレコードがない、つまり絞り込み不成功

 end


23 レコードの探索(検索)

 レコードの探索とは、フォームの編集対象表、または任意の表の比較式を満たすレコードをサーチ(探索)することです。
「探索」と「検索」の言葉は同じ意味で用いられることが多いのですが、「検索」は組織化されたデータ、すなわち索引(インデックス)をサーチことを指すという考え方もあります。
いずれにしても「探索」と「検索」の区別はほとんど意味をなさないと思われますが、本書では一般的な「探索」で統一します。

 [検索]コマンドの実行すると、比較式を満たすレコードへジャンプします。この時、比較式を満たすレコードが無ければ表の終端行へジャンプします。
なお、[検索]コマンドで [終了状態 = <変数名>]パラメータを追加した場合には、比較式を満たすレコードが無ければ処理対象行は移動しません。
このように、[終了状態 = <変数名>]パラメータ は、フォームの編集対象表の終端行へのジャンプを抑制するためのものです。

 さて、[絞り込み]コマンドと同様に[検索]コマンドの場合にも、[探索成功]と[探索不成功]の判定が必要です。
[検索]コマンドに[終了状態 = <変数名>]パラメータ を追加していない場合には、 #eof で[探索成功]と[探索不成功]の判定が出来ます。
[終了状態 = <変数名>] パラメータ を追加している場合には、 <変数名>の値を参照して[探索成功]と[探索不成功]の判定することになります。

 ■[終了状態 = <変数名>] パラメータの使用例

 (例25)
 変数宣言 自動,整数{ &status }
 :

 解除 *
 検索 &fieldName_&expression, 終了状態 = &status /* &status 1:探索成功 0:探索不成功 */

 if ( &status = 1 )

  ** 比較式を満たすレコードがある、つまり探索成功

 else

  ** 比較式を満たすレコードがない、つまり探索不成功

 end


 (例26)
 変数宣言 自動,整数{ &status }
 変数宣言 自動,整数{ &successful = 1 }
 :

 解除 *
 検索 &fieldName_&expression, 終了状態 = &status /* &status 1:探索成功 0:探索不成功 */

 if ( &status = &successful ) /* &successful = 1 */

  ** 比較式を満たすレコードがある、つまり探索成功

 else

  ** 比較式を満たすレコードがない、つまり探索不成功

 end

 ■道草
 探索不成功の場合には、一般的にはメッセージボックスを表示して、[比較式を満たすレコードがない]ことをユーザに伝えます。
その時のメッセージとしては以下の内容が適切です。
 ○ 該当するレコードが見つかりません ― 単に見つからないのであって、アプリケーションのバグも原因に含まれます
 × 該当するレコードがありません   ― 断定的ですが、ひょっとしてアプリケーションのバグが原因で探索不成功なのかもしれません

24 フォームの編集対象表を多重化する
 フォームの編集対象表を多重化した場合の利点は次の通りです。
 ・フォームの再描画を防いでレコードを操作できる
 ・レコードを扱ったプロシージャの処理時間を短縮できる

24.1 [多重化]コマンド
 フォームの編集対象表を多重化するには次のようにします。

 (例27) フォームの再描画を防いでレコードを操作する

 手続き定義開始 cmd5日分の平均を記入Click( )
  変数宣言 自動,日時{ &date }

  &date = [日付]  /* 現在行の日付を代入 */

  多重化
  ** ------ begin 多重化した表で作業 ---------**
  解除 *
  検索 [日付]{ #日付( [日付], 1 ) = #日付( &date, 1 ) }

  ジャンプ 行番号 = -4  /* 4行戻って  */
  絞り込み 行数  = 5  /* 5行絞り込む */

  手続き実行 prc平均を変数に代入する( )

  検索 [日付]{ #日付( [日付], 1 ) = #日付( &date, 1 ) }

  行訂正 [朝最高血圧平均] = &m朝最高血圧平均, [朝最低血圧平均] = &m朝最低血圧平均, [朝脈拍平均] = &m朝脈拍平均
  行訂正 [夜最高血圧平均] = &m夜最高血圧平均, [夜最低血圧平均] = &m夜最低血圧平均, [夜脈拍平均] = &m夜脈拍平均
  終了 表 編集対象表
  ** ------ end 多重化した表で作業 ---------**

  編集表 &hwindow /* 他の表を操作しないように編集表をフォームの編集対象表に設定します */

 手続き定義終了

 ■多重化によるパフォーマンス向上
 フォームの編集対象表を多重化していない一覧表形式(または伝票形式)のフォームの場合には、明細部のレコードを再描画するための時間が必要です。
そのために、[フォーム操作バー]の[ジャンプバー]を非表示にすると、若干改善しますが焼け石に水程度の改善しかしません。
ところが、フォームの編集対象表を多重化すると圧倒的にパフォーマンスが向上します。
 これは、カード形式のフォームでも同じです。
例えば、プログレスバーだけを表示しているカード形式のフォームだとしても、フォームの編集対象表を多重化してレコードを処理した方が圧倒的にパフォーマンスが向上します。
※拙作:utx_list3_reform:整形ユーティリティのプログレスバーフォームの場合には、処理時間が2/3に短縮しました。
 もしも、「このレコード処理は遅いな」と思ったら、フォームの編集対象表を多重化してレコードを処理してみてください。
圧倒的なパフォーマンスに腰を抜かすほど驚くはずです。

 <参考>

 プロシージャ:TBLprcTableMultiOpen は、指定した表番号の表を多重化する。
 すでに多重化されている場合には、多重化した表へ切り替える。
 必ず[編集表 &hwindow]で表を切り替えてから実行してください。

 手続き定義開始 cmdチェックした行を絞り込むClick( )
  変数宣言 自動,文字列{ &icon, &title = "cmdチェックした行を絞り込むClick( )", &msg }
  変数宣言 自動,整数 { &found }
  変数宣言 自動,整数 { &targetTblNum, &multiTblNum, &done }

  編集表 &hwindow /* 表を切り替えてから実行してください */
  &targetTblNum = &hwindow
  手続き実行 TBLprcTableMultiOpen( &targetTblNum, &multiTblNum, &done )
  if ( &multiTblNum )

   解除 *
   検索 [チェック]{ 1 }

   &found = 0
   if ( .not #eof )
    &found = 1
   end

   終了 表 &multiTblNum
  end

  if ( &found )

   編集表 &hwindow

   解除 *
   絞り込み [チェック]{ 1 }

  else

   &msg = "チェックした行が見つかません"
   &icon = "i"
   手続き実行 INFprcMsgPause( &icon, &title, &msg )

  end

 手続き定義終了


 手続き定義開始 TBLprcTableMultiOpen( 整数 &targetTblNum, 参照 整数 &tblNum, 参照 整数 &done )
  変数宣言 自動,文字列{ &icon, &title = "TBLprcTableMultiOpen( )", &msg }
  変数宣言 自動,文字列{ &targetTblName, &yen = #jis( #hex("5C") ) }
  変数宣言 自動,整数 { &primaryTblNum, &secondaryTblNum, &multiTblNum, &debug = 0 }

  &tblNum = #u
  &done  = 0

  &targetTblName = #表ファイル名( &targetTblNum )
  if ( &targetTblName <> #u )

   &primaryTblNum  = #表番号取得( &targetTblName, 1 )
   &secondaryTblNum = #表番号取得( &targetTblName, 2 )
   if ( &primaryTblNum .and &secondaryTblNum )

    if ( &primaryTblNum = &targetTblNum )

     &multiTblNum = &secondaryTblNum
    else

     &multiTblNum = &primaryTblNum
    end

   end

   if ( .not &multiTblNum )

    多重化
    &tblNum = #is表
   else

    編集表 &multiTblNum
    &tblNum = &multiTblNum
   end
   &done = 1

   &msg =      "フォルダ: " + #文字置換( #ファイル名( &targetTblName, 5 ), &yen, &yen + &yen )
   &msg = &msg + "\n\nファイル: " + #ファイル名( &targetTblName, 3 )
   &msg = &msg + "\n\n&primaryTblNum  = " + #str( &primaryTblNum )
   &msg = &msg + "\n\n&secondaryTblNum = " + #str( &secondaryTblNum )
   &msg = &msg + "\n\n&tblNum     = " + #str( &tblNum )
   条件 ( &debug ) 手続き実行 INFprcMsgPause( &icon, &title, &msg )
  else

   条件 ( &traceON ) トレース出力 &traceMsg + " 多重化に失敗しました( 編集対象表がありません )"
   &icon = "!"
   &msg =      "編集対象表がありません"
   &msg = &msg + "\n\n多重化できませんでした"
   手続き実行 INFprcMsgPause( &icon, &title, &msg )
  end

 手続き定義終了

25 命名規則
  名は体を表す(なはたいをあらわす)
25.1 オブジェクト名の付け方
 フォームに配置するオブジェクトの名前、つまりオブジェクト名は生成時に桐システムが自動的に付けてくれます。
オブジェクト名は重複してはいけない約束なので、下線( _ )以降にユニークな番号が付与されています。
しかし、このように自動生成されたオブジェクト名を見ても、そのオブジェクトの内容は直感的に理解できません。
従って自動生成されたオブジェクト名をそのまま使い回すのは止めた方がよいのです。

 ―わかり難いオブジェクト名の例

 ラベル_4 テキスト_3 コマンドボタン_5 …

 ―わかり易いオブジェクト名の例

 ラベル_氏名 テキスト_氏名 コマンドボタン_閉じる …

  または

 lbl氏名 txt氏名 cmd閉じる …

 上の例を見て判るように、わかり易いオブジェクト名を使用することが如何に重要であるかと気が付くことでしょう。

 ■オブジェクトの接頭辞を使用する
 オブジェクト名の命名は自由なので、{ ラベル_氏名 テキスト_氏名 コマンドボタン_閉じる … }式でもOKです。
しかし、オブジェクトの種類を表す接頭辞(英 prefix )を使う方法がわかり易いので以下に紹介します。
なお、この接頭辞一覧は web等を参考に ONnojiがリストアップしたものであり、絶対的なものではありません。

 lbl … ラベル
 txt … テキスト
 grp … グループ項目
 gbx … グループボックス
 cmd … コマンドボタン

 opt … オプションボタン
 chk … チェックボックス
 psh … プッシュボタン

 cbo … コンボボックス
 lst … リストボックス

 pic … ピクチャ
 lin … 直線
 ovl … 楕円
 sct … 扇形
 rnd … 角丸め矩形

 sub … サブフォーム
 gra … グラフ
 bar … バーコード

 fam … ファミリ

 txtオブジェクト名 + "入力支援ボタン" … 入力支援ボタン

 ■接頭辞に続くオブジェクト名
 接頭辞に続くオブジェクト名は、[標題]属性や[ソース]属性の値を用いることで、悩むことなく機械的に命名出来ます。

 lbl … lbl + 標題
 txt … txt + ソース
 grp … grp + ソース
 cmd … cmd + 標題

 ―オブジェクトの接頭辞の例

 フォーム
 ├ ファミリ
 ├ ワークスペース
 │ └ cmdStartup
 ├ フォーム操作バー
 ├ フォームヘッダ部
 │ ├ lbl空白
 │ ├ lbl日付
 │ ├ lbl朝最高血圧
 │ ├ lbl朝最低血圧
 │ ├ lbl朝脈拍
 │ ├ lbl夜最高血圧
 │ ├ lbl夜最低血圧
 │ ├ lbl夜脈拍
 │ ├ lbl朝最高血圧平均
 │ ├ lbl朝最低血圧平均
 │ ├ lbl朝脈拍平均
 │ ├ lbl夜最高血圧平均
 │ ├ lbl夜最低血圧平均
 │ ├ lbl夜脈拍平均
 │ ├ cmd今日の日付の行へジャンプ
 │ ├ cmd5日分の平均を記入
 │ ├ gra血圧
 │ │ └ lblグラフ血圧
 │ ├ optグラフ1
 │ │ └ lblグラフ1
 │ └ optグラフ2
 │   └ lblグラフ2
 └ フォーム明細部
   ├ 行セレクタ
   ├ txt日付
   ├ txt朝最高血圧
   ├ txt朝最低血圧
   ├ txt朝脈拍
   ├ txt夜最高血圧
   ├ txt夜最低血圧
   ├ txt夜脈拍
   ├ txt朝最高血圧平均
   ├ txt朝最低血圧平均
   ├ txt朝脈拍平均
   ├ txt夜最高血圧平均
   ├ txt夜最低血圧平均
   └ txt夜脈拍平均

25.2 変数名の付け方
 変数名の命名は自由なのですが、変数の種別(スコープ:有効範囲)を示す接頭辞を用いると便利です。

 自動 … なし   ※注意:[手続き定義開始]コマンドの[仮引数]も自動変数です。
 局所 … m   m はモジュールの意。
 固有 … g   g はグローバルの意
 共通 … p   p はパブリックの意

 なお、データ型を示す接頭辞は、批判が多い「システムハンガリアン記法」と呼ばれるものなので使用しません。

 ―変数の名前 2006/4/21(金) ― ブログ版 桐のイベント道場より
  プログラムの書き方は自由なので、桐のシンタックス(文法)に違反しなければ、
 変数名はどんな名前でも差し支えありません。
 しかし、少し工夫すると管理がとても楽になります。

  ・変数の接頭辞

  オブジェクト名の接頭辞と同じように変数名にも接頭辞を用いると、
 変数名を見ただけで変数の種別が判るので便利です。

  著者( ONnoji )の「変数名」に対する命名規則は次の通りです。

 種別  接頭辞
 自動 … なし  ※[手続き定義開始]の[仮引数]も自動変数です。
 局所 … m   ※ m はモジュールの意。
 固有 … g   ※ g はグローバルの意
 共通 … p   ※ p はパブリックの意

  接頭辞を用いることによって、
 スコープの異なる同名の変数を宣言することを避けられます。
 ※自動変数には接頭辞は付けません。

  <ご注意>
  繰り返しになりますが、プログラムの書き方は自由なので、
 以上の命名規則はあくまでも著者( ONnoji )の個人的なものです。
 なお、これは命名規則は批判が多い「ハンガリー記法」の模倣ではありません。
 著者( ONnoji )は「ハンガリー記法」の信奉者ではありませんので誤解の無いようにお願いします。

25.3 プロシージャ(手続き)名の付け方
 イベントプロシージャは自動的に命名されて作成されます。
しかし、一般プロシージャは自分自身で作らなくてはなりません。
この時、一般プロシージャを2種類に分けて考えると命名が簡単になります。 
すなわち、
 ・コマンドボタンが[機能名:手続き実行]で直接呼び出す一般プロシージャ
 ・それ以外のプロシージャ
です。

 ―コマンドボタンが[機能名:手続き実行]で直接呼び出す一般プロシージャ
 このプロシージャは、コマンドボタンのオブジェクト名 + "Click" とします。
このように決めておけば、コマンドボタンのオブジェクト名が決まれば、自動的に一般プロシージャ名も決まります。
こうすることで、悩まずに機械的に命名出来ます。※これは重要です。
 また、こうして命名した一般プロシージャ名を見れば、呼び出しているコマンドボタンのオブジェクト名が分かります。
つまり、コマンドボタンとそれに対応する一般プロシージャの関係がよく分かって便利なのです。

 ―それ以外のプロシージャ
 接頭辞として prc を用います。prc + "任意のプロシージャ名" です。 ※prc は procedure の意

このように一般プロシージャを命名すると、イベント処理ファイルのプロシージャは3種類に分類できるようになります。
すなわち、
 (1)イベントプロシージャ
 (2)コマンドボタンが[機能名:手続き実行]で直接呼び出す一般プロシージャ
 (3)それ以外のプロシージャ
です。
       フォーム( wfm/wfx )側  ←┬→ イベント処理( kev/kex )側
                     │
                     │
(1)イベントプロシージャ
 ┌─────────────────┐ │ ┌───────────────┐
 │                 │ │ │               │
 │オブジェクト  各種イベント発生 ├──┤
オブジェクト名::イベント名( ) ├──┐  (3)それ以外のプロシージャ
 │                 │ │ │               │  │  ┌─────────────┐
 └─────────────────┘ │ └───────────────┘  │  │             │
                     │                    ├──┤
prcプロシージャ名( )   │
 ┌─────────────────┐ │ ┌───────────────┐  │  │             │
 │                 │ │ │               │  │  └─────────────┘
 │コマンドボタン 機能名:手続き実行├──┤ c
mdオブジェクト名Click( )  ├──┘
 │                 │ │ │               │
 └─────────────────┘ │ └───────────────┘
                     │
(2)コマンドボタンが[機能名:手続き実行]で直接呼び出す一般プロシージャ
                     │ 
       フォーム( wfm/wfx )側  ←┴→ イベント処理( kev/kex )側

 ―プロシージャ一覧の例

 (1)イベントプロシージャ  ※[名札  メイン]も含める
    名札  メイン
    optグラフ1::ソース値更新
    optグラフ2::ソース値更新


 (2)コマンドボタンが[機能名:手続き実行]で直接呼び出す一般プロシージャ
    cmdStartupClick
    cmd今日の日付の行へジャンプClick

    cmd5日分の平均を記入Click

 (3)それ以外のプロシージャ
    prc平均を変数に代入する



 ―手続きの呼び出し関係の例

 (1)名札  メイン

 (1)optグラフ1::ソース値更新  
      注意:(1)から(3)や(2)を呼び出してもOK

 (1)optグラフ2::ソース値更新


 (2)cmdStartupClick
           注意:(2)から(2)を呼び出してもOK
 
(2)└ cmd今日の日付の行へジャンプClick

 (2)cmd今日の日付の行へジャンプClick

 (2)cmd5日分の平均を記入Click

 (3)└ prc平均を変数に代入する

 (3)prc平均を変数に代入する

26 イベントプロシージャ(イベントハンドラ)を実行する
 イベントプロシージャ(イベントハンドラ)は、イベントが発生して実行されます。
しかし、イベントが発生していなくてもイベントプロシージャを呼び出したい場合が稀にあります。

 当初からそういう事態が予想されていたならば、次のような構造にすればよい。
これは[呼び出すプロシージャ]と[呼び出されるプロシージャ]が適切に分離しているので望ましい構造です。

 ┌───────────────┐
 │(1)イベントプロシージャ  │
 │オブジェクト名::イベント名( ) ├──┐
 │               │  │
 └───────────────┘  │
 ┌───────────────┐  │  ┌───────────────┐
 │(2)機能名:手続き実行   │  │  │(3)それ以外のプロシージャ │
 │ cmdオブジェクト名Click( )  ├──┼──┤ prc手続き名( )        │
 │               │  │  │               │
 └───────────────┘  │  └───────────────┘
 ┌───────────────┐  │
 │(3)それ以外のプロシージャ │  │
 │ prc手続き名( )        ├──┘
 │               │
 └───────────────┘

 しかし、実際にはプログラム作成の手間を省くために、イベントが発生していなくてもイベントプロシージャを呼び出したい場合が稀にあります。
これは、仕方なくやむ得ず行うもので、決して積極的に行うべきではありません。
その場合には、次のような構造になります。

 ┌───────────────┐
 │(1)イベントプロシージャ  │
 │オブジェクト名::イベント名( ) ├──┐
 │               │  │
 └───────────────┘  │
 ┌───────────────┐  │  ┌───────────────┐
 │(2)機能名:手続き実行   │  │  │(1)イベントプロシージャ  │
 │ cmdオブジェクト名Click( )  ├──┼──┤オブジェクト名::イベント名( ) │
 │               │  │  │               │
 └───────────────┘  │  └───────────────┘
 ┌───────────────┐  │
 │(3)それ以外のプロシージャ │  │
 │ prc手続き名( )        ├──┘
 │               │
 └───────────────┘

 ―その1 拙作:MNU_Framework による例

(重要)
 以下の例では、実際にイベントが発生していないので、
 ・偽りの &thisとして、&MNUmThis を使用しています。
 ・偽りの実引数として、&MNUmマウス位置, &MNUm処理中止 を使用しています。


 フォーム::システムキーダウン
  │
  └ MNUprcEventSystemKeyDownRun
    │
    ├ … 省略 …
    │
    └ famMNU::マウス左ダウン
      │
    … 省略 …


【INF_15パズル.kev】 ※拙作:MNU_Framework を組み込んだもの

 名札  メイン
 :

 *---------- begin MNU_Framework 名札 メイン ---------------*
 :

 ライブラリ &MNUmLibraryName
 :

 変数宣言 局所,文字列{ &MNUmThis, … }
 :
 変数宣言 局所,長整数{ &MNUmマウス位置[ 2 ] = { 1, 1 }, &MNUm処理中止 }
 :
 *---------- end MNU_Framework 名札 メイン -----------------*
 :

 *

【MNU_Framework.cmd】

 **<from>
 手続き定義開始 MNUprcEventSystemKeyDownRun( 長整数 &vkNum,参照 長整数 &処理中止 )
  変数宣言 自動,文字列{ &objectName }
  :

  &MNUmThis = &objectName
  手続き実行 famMNU::マウス左ダウン( &MNUmマウス位置, 1, 1, &MNUm処理中止 ) /* &MNUmマウス位置 と &MNUm処理中止 は局所変数 */
  :

 手続き定義終了

 **<to>
 手続き定義開始 famMNU::マウス左ダウン(長整数 &マウス位置[2],長整数 &明細番号,長整数 &フラグ,参照 長整数 &処理中止)
  変数宣言 自動,文字列{ &objectName }
  :

  &objectName = &this    /* &this   はフォーム変数 */
  if ( &MNUmThis <> #u )  /* &MNUmThis は局所変数   */
   &objectName = &MNUmThis
   &MNUmThis  = #u    /* 代入後に内容をクリアする */
   :
  end

  :

 手続き定義終了


 ―その2 拙作:INF_電卓 による例  
注意:局所変数:&MNUmThis 等は、単純に拙作:MNU_Framework より流用したものです

【INF_電卓.kev】
 名札  メイン
 :

 変数宣言 局所,文字列{ &MNUmThis }
 変数宣言 局所,長整数{ &MNUmマウス位置[ 2 ] = { 1, 1 }, &MNUm処理中止 }
 :
 *

 手続き実行 VKprcKeySet( "*", 1, "0", "手続き実行 prcPseudoClickEventRun( ""cmdKey_乗算"") " )
 :

 **<from>
 手続き実行 prcPseudoClickEventRun( "cmdKey_乗算" )

  ↓

 **<to>
 手続き定義開始 prcPseudoClickEventRun( 文字列 &objectName )
  変数宣言 自動,文字列{ &icon, &title = "prcPseudoClickEventRun( )", &msg }

  &MNUmThis = &objectName /* &MNUmThis は局所変数 */

  if ( #対応番号( "cmdKey_1,cmdKey_2,cmdKey_3,cmdKey_4,cmdKey_5,cmdKey_6,cmdKey_7,cmdKey_8,cmdKey_9,cmdKey_0", &objectName ) <> 0 )
   手続き実行 famNumKey::マウス左クリック( &MNUmマウス位置,1,1,&MNUm処理中止 ) /* &MNUmマウス位置 と &MNUm処理中止 は局所変数 */
  end

  if ( #対応番号( "cmdKey_除算,cmdKey_乗算,cmdKey_減算,cmdKey_加算,cmdKey_等号", &objectName ) <> 0 )
   手続き実行 famOperatorKey::マウス左クリック( &MNUmマウス位置,1,1,&MNUm処理中止 ) /* &MNUmマウス位置 と &MNUm処理中止 は局所変数 */
  end

 手続き定義終了

27 プロシージャ(手続き)の引数
 引数(ひきすう)は、プロシージャ(手続き)において、その外部と値をやりとりするための特別な変数、あるいはその変数の値のことです。

  【引用】引数 出典: フリー百科事典『ウィキペディア(Wikipedia)』
   引数(ひきすう)は、数学における関数やコンピュータプログラムにおける手続きにおいて、その外部と値をやりとりするための特別な変数、あるいはその変数の値のことである。
   関数・サブルーチン・メソッド等を定義する時に、外部から値を渡される特別な変数として指定されるのが仮引数。
   関数(等)を呼出す式において、仮引数に対応する式(あるいはその値)が実引数である。
   実行時には、実引数の値を仮引数が受け取る。


27.1 引数はなぜ必要なのか?
 DOS桐には[手続きの引数]がなかったので、DOS桐の経験ユーザは「引数はなぜ必要なのか?」と不思議に思った人が非常に多いようです。
一方、コンピュータの高級言語(4GLを含む)の経験がある人の場合には、ようやく[手続きの引数]が使えるようになったと大いに喜んだと思います。

 これはバッチ処理と大差ないDOS桐からレベルアップして、Microsoft office のVBA言語と同じレベルへ到達した結果です。
従って、[手続きの引数]が理解できないという人は、MS officeのVBA言語のプロシージャの引数も同様に理解できません。

 なお、桐言語、またはMicrosoft office のVBA言語のプロシージャの引数がなんとなく理解出来たとしても、それだけでは本質的な理解になりません。
[手続きの引数]を単純に言語の仕様だと理解するのならば、それは[モジュール]という概念が欠落した表面的な理解です。
[モジュール]に関しては次の項をお読みください。

27.2 ひとつのプロシージャはひとつの機能を担当する
 プログラミングでは、[ひとつのプロシージャ(モジュール)は、ひとつの機能を担当する]のがベストです。
つまり、あれもこれも何でも出来るプロシージャ(モジュール)は駄目なんです。
しかし、これに関する内容は非常に専門的になるので、ここではでは詳しく紹介しません。
"モジュール" や "結合度" や "凝集度(または強度)" といった概念はプログラミングの常識です。
もしも、これらの概念に興味がある人は、フリー百科事典『ウィキペディア(Wikipedia)』などで "モジュール" や "結合度" や "凝集度" を検索してみてください。

 【引用】モジュール 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  モジュール(英: module)とは、工学などにおける設計上の概念で、システムを構成する要素となるもの。
  いくつかの部品的機能を集め、まとまりのある機能を持った部品のこと。
  モジュールに従っているものをモジュラー(英: modular)という。
  ―ソフトウェア
  プログラミングにおいて、一連の機能をひとまとまりになる複数の機能:モジュールに分割し、それぞれ別に開発する場合がある。
  こうすることで、全体として完成を早めることができる上、モジュール単位でテストしたりすることが可能になり、モジュールの入れ替えで機能を高めたり補修したりすることができるようになる。
  プログラムのモジュールは、できるだけ他のモジュールとの結合度を弱めて、独立性を高めることが望ましい。
  モジュールは、(一般に凝集した)サブルーチンとデータ構造の集合体としてのソフトウェアの実体である。
  モジュールはその部分だけでコンパイル可能な単位でもあり、再利用可能であると同時に、複数のプログラマが同時並行的にそれぞれ異なるモジュールの開発を行うことが可能となる。
  モジュールの特徴として「モジュール性」とカプセル化があり、それらによって複雑なプログラムを理解しやすくできる。


 【引用】結合度 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  結合度(けつごうど、カップリング、coupling)とは、コンピュータープログラミングで用いられる(機械よりは)人間寄りの尺度。
  ソフトウェア測定法の一種。
  利用者またはメンテナンスをする者にとって対象を利用、保守しやすいように対象の内容が整理、分割できているかどうかを、その状態によって段階に分けて表現する。


 【引用】凝集度 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  凝集度(ぎょうしゅうど、コヒージョン、cohesion)とは、情報工学においてモジュール内のソースコードが特定の機能を提供すべく如何に協調しているかを表す度合いである。
  IPAが実施する情報処理技術者試験では、強度(きょうど、ストレングス、strength)という言葉が使われる。
  凝集度は順序尺度の一種であり、「凝集度が高い」とか「凝集度が低い」といった言い方で使われる。
  凝集度の高いモジュールは、堅牢性、信頼性、再利用性、読みやすさなどの点で好ましく、凝集度の低いモジュールは保守/評価/再利用/読解が難しいため好ましくないとされる。


27.3 引数の[値渡し]と[参照渡し]
 [手続き定義開始]コマンドの[仮引数リスト]では、[値渡し]と[参照渡し]が選べます。

 ―値渡しの例

 **<from>
 手続き実行 prcProcedureName( "Hello, World!" ) /* 値渡しの場合には実引数にはリテラルな値を指定できる */

 または

 &STR = "Hello, World!"
 手続き実行 prcProcedureName( &STR ) /* 値渡しの場合には実引数には変数を指定できる */

 **<to>
 手続き定義開始 prcProcedureName( 文字列 &string )

  メッセージボックス "title", &string

 手続き定義終了


 ―参照渡しの例


 **<from>
 手続き実行 prcProcedureName( &STR ) /* 参照渡しの場合には実引数に必ず変数を指定する  */
 メッセージボックス "title", &STR   /* &STR には、"Yes" または "No" が代入されている  */


 **<to>
 手続き定義開始 prcProcedureName( 参照 文字列 &string )

  &string = #u /* 参照引数の初期化 */

  if ( 条件 )

   &string = "Yes"
  else

   &string = "No"
  end

 手続き定義終了

 【引用】桐10s ヘルプ ― 手続き定義開始
  ・手続き実行時に、引数を受け取る手続きにする場合は、受け取る変数のデータ型と名前を ( ) 内に指定します。
   この場所に指定した変数は、手続きを実行するときに自動変数として宣言され、手続きが終了した時点で削除されます。
  ・手続きが終了したときに、手続きの結果を返す場合は、値を渡す変数の<データ型>の前に「参照」をつけます。「参照」のうしろは、1文字以上の空白を入れてください。
   「参照」を指定した場合は、手続き実行時に指定する引数も変数でなければいけません。
   また、受け取る変数のデータ型は、値を渡す変数のデータ型と同じでなければいけません。


27.4 実引数と仮引数
 [手続き実行]コマンドの引数は[実引数]といい、[手続き定義開始]コマンドの引数は[仮引数]といいます。
どちらも単に[引数]と呼ぶことが多いのですが、これは使用するコマンドが異なるのでわざわざ言葉を選ぶ必要がないからです。

 (重要)
 引数に変数を使う場合には、実引数と仮引数の変数名が同一である必要はありません。
 仮引数は、プロシージャの内容に沿った変数名にするべきであって、実引数の変数名の影響を受ける必要はありません。
 むしろ、実引数と仮引数の変数名は異なっている方が普通です。


 ―実引数
 ・[手続き実行 <手続き名>]コマンドでカッコ"()"の中に指定します。
 ・実引数を使わない場合には、カッコ"()"の中は空にします。
 ・実引数には、リテラルな値(関数・計算式を含む)と変数が指定できます。
 ・複数の実引数を指定する場合には、コンマで区切ります。※実引数リスト
 ・[参照渡し]する場合には、必ず変数を指定して、実引数と仮引数のデータ型を同じにします。

 ―仮引数
 ・[手続定義開始]コマンドでカッコ"()"の中に指定します。
 ・仮引数を使わない場合には、カッコ"()"の中は空にします。
 ・仮引数には、変数名の前にデータ型を指定します。(例)文字列 &string
 ・複数の仮引数を指定する場合には、コンマで区切ります。※仮引数リスト
 ・[参照渡し]する場合には、参照を指定します。(例)参照 文字列 &string

 【引用】桐10s ヘルプ ― 手続き実行 <手続き名>
  ・引数を渡す手続きを実行する場合は、<式>に引数の値を指定します。値は、計算式で指定してもかまいません。
  ・引数を使用しない手続きを実行する場合は、式そのものを省略して()だけを指定します。
  ・手続き定義で「参照」を指定している引数の場合は、同じデータ型の変数名を指定しなければいけません。


 【引用】桐10s ヘルプ ― 手続き定義開始
  ・手続き実行時に、引数を受け取る手続きにする場合は、受け取る変数のデータ型と名前を ( ) 内に指定します。
   この場所に指定した変数は、手続きを実行するときに自動変数として宣言され、手続きが終了した時点で削除されます。
  ・手続きが終了したときに、手続きの結果を返す場合は、値を渡す変数の<データ型>の前に「参照」をつけます。「参照」のうしろは、1文字以上の空白を入れてください。
  ・「参照」を指定した場合は、手続き実行時に指定する引数も変数でなければいけません。また、受け取る変数のデータ型は、値を渡す変数のデータ型と同じでなければいけません。
   たとえば、2番目の引数として定義した自動変数の値を渡したい場合は、手続き実行時に指定する2番目の引数を変数名で指定します。
   2番目に定義した自動変数のデータ型が整数であれば、手続き実行時に指定する変数も整数型のものを指定します。
   長整数型、数値型、通貨型、実数型の変数を指定しても、エラーになりますので注意してください。


27.5 配列変数の[値渡し]と[参照渡し]
 配列変数を引数として使うには次のようにします。

 ―値渡しの例

 **<from>
 変数宣言 局所,文字列{
&mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }

 手続き実行 prcProcedureName( &mGroupOfSevenDim ) /* すべての配列要素を渡す場合には角カッコ([])と要素数を省く */

 **<to>
 手続き定義開始 prcProcedureName(
文字列 &stringDim[12] ) /* 実引数の配列変数の要素数に関わらず、仮引数の配列変数の要素数は固定 */
  変数宣言 自動,整数{ &i, &loop, &step = 1 }

  &loop = #配列要素数( "stringDim" )
  繰り返し &i = 1, &loop, &step

   メッセージボックス "title", &stringDim[ &i ]

  繰り返し終了

 手続き定義終了


 ―参照渡しの例

 参照渡しの場合には、実引数の配列変数の要素数に応じて、仮引数の配列変数の要素数が変化します。

 **<from>
 変数宣言 局所,文字列{ &
mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }

 手続き実行 prcProcedureName(
&mGroupOfSevenDim ) /* すべての配列要素を渡す場合には角カッコ([])と要素数を省く */

 **<to>
 手続き定義開始 prcProcedureName(
参照 文字列 &stringDim[] ) /* 実引数の配列変数の要素数に応じて、仮引数の配列変数の要素数が変化する */
  変数宣言 自動,整数{ &i, &loop, &step = 1 }

  &loop = #配列要素数( "stringDim" )
  繰り返し &i = 1, &loop, &step

   メッセージボックス "title", &stringDim[ &i ]

  繰り返し終了

 手続き定義終了

  【桐10ヘルプ】 ― 手続き実行 <手続き名>
  ・配列変数の引数を持つ手続きを実行します( &番号リストは配列変数 )。
   手続き実行 指定行絞り込み( &番号リスト )


 【桐10ヘルプ】 ― 手続き定義開始
  ・引数を、配列変数でまとめて受け取る手続きを定義します。この手続きを実行するときは「手続き実行 指定行絞り込み( &番号リスト )」などとして、配列変数で引数を渡します( &ID は配列変数 )。
   手続き定義開始 指定行絞り込み( 長整数 &ID[32] )
    … (コマンド) …
   手続き定義終了

  ・手続き実行時に渡される配列変数の要素数に応じて、手続き定義内で使用する変数の要素数を決めることができます(ただし、データ型が一致しない場合、または配列変数でないものは指定できません。
   この場合、つぎの例のように、要素数を空にしておきます。
    手続き定義開始 対象項目抽出( 参照 文字列 &処理項目[] )


 ― 引数を使ったプログラミングが未だ苦手という人へ。 ― かっこうBBS(三代目) 2019年12月04日より
  引数はアプリケーションをモジュラー設計しているか否かによって理解度が異なります。
 処理内容によってはモジュールは、それほど独立したものではなくなります。
 例えば、コマンドボタンを実行すると、あとは一本道で進んで完了するような処理の場合には引数は必要ありません。
 このようなモジュールでは、多くの変数を参照するので、引数リストが膨大になってしまいます。
 だから、引数リストが多くなるようなモジュールでは、引数を使わない方がベターです。
 こういうモジュールは強度が弱いということになりますが、一本道で進んで完了するバッチ的な処理はそれでOKなのです。
 こういう事情があるので、「引数を使わないプログラムは悪い」と考えるのは誤りです。
  ちなみに、著者( ONnoji )が引数を使うことが多いのは、
 一度作ったモジュール(プロシージャ:手続き)を他のアプリケーション(イベント処理:kev/kex)で再利用することを念頭にしているからです。

28 配列変数の操作

28.1 配列変数のソート
 配列変数をソート(並べ替え)したいことがあります。
ここで紹介する方法は、単純交換法( straight exchange sort )というもので、バブルソート( bubble sort )ともいいます。
なお、バブルソートは遅いという先入観をお持ちの人もいると思いますが、配列変数をソートするのならばバブルソートで十分なのです。

 ―文字列型の配列変数のソート

 **<from>
 変数宣言 局所,文字列{ &mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }

 &order = "A" /* 引数:&order は、"A" または "a" で昇順ソート( ASCENDING )、"D" または "d" で降順ソート( DECENDING )です */
 手続き実行 prcStringDimSort( &order, &mGroupOfSevenDim )


 **<to>
 手続き定義開始 prcStringDimSort( 文字列 &order, 参照 文字列 &stringDim[] )
  変数宣言 自動,文字列{ &stringA, &stringB }
  変数宣言 自動,数値 { &s, &fin, &n, &i }

  ** 引数:&order は、"A" または "a" で昇順ソート( ASCENDING )、"D" または "d" で降順ソート( DECENDING )です

  &order = #lc2( #半角( #sstr( &order, 1, 1 ) ) )

  &n = #配列要素数( "stringDim" )
  &s = 2

  繰り返し

   &fin = &s
   &s  = &n
   繰り返し &i = &n, &fin, -1

    &stringA = &stringDim[ &i ]
    &stringB = &stringDim[ &i - 1 ]

    if ( ( &order = "a" .and &stringA < &stringB ) .or ( &order = "d" .and &stringA > &stringB ) )

     &stringDim[ &i - 1 ] = &stringA
     &stringDim[ &i ]   = &stringB
     &s = &i
    end

   繰り返し終了

   if ( &s = &n )
    繰り返し中止
   end
  繰り返し終了

 手続き定義終了


 ■配列変数をソートする方法 ― 桐のイベント道場 かっこうログ 2002年06月03日より

 配列変数をソートする方法をご紹介いたします。
 例は 文字列型の配列変数 &test[ ] をソートするものです。
 なお、以下の例は一括処理(.cmd)ですが、イベント(.kev)でも利用可能です。

 <参考書籍>
 現代データ構造とプログラム技法 萩原宏・西原清一 著 オーム社刊 ISBN4-274-12831-8
 *---------------------------------------------------*
 変数宣言 固有,文字列{ &test[6], &string }

 &test = {"b","f","a","e","c","d"}
 手続き実行 prcSort( &test )
 &string = &test[1]+&test[2]+&test[3]+&test[4]+&test[5]+&test[6]
 確認 &string
 終了

 手続き定義開始 prcSort( 参照 文字列 &dim[] )

  変数宣言 自動,数値{ &s, &fin, &n, &i, &numA, &numB }
  変数宣言 自動,文字列{ &strA, &strB}
  &n = #配列要素数( "dim" )

  &s = 2
  繰り返し

   &fin = &s, &s = &n
   繰り返し &i = &n, &fin, -1
    &strA = &dim[ &i ]    /* 数値の場合は &numA */
    &strB = &dim[ &i - 1 ]  /* 数値の場合は &numB */
    if ( &strA < &strB )   /* 数値の場合は &numA < &numB */
     &dim[ &i - 1 ] = &strA /* 数値の場合は &numA */
     &dim[ &i ]   = &strB /* 数値の場合は &numB */
     &s = &i
    end
   繰り返し終了

   if ( &s = &n )
    繰り返し中止
   end
  繰り返し終了
 手続き定義終了
 *---------------------------------------------------*

28.2 指定した文字列を要素番号1にセットする
 指定した文字列を要素番号1にセットする。この時、別の要素番号に同じ文字列があれば削除する。

 実行前      実行後
 1 フランス ┌→ 日本   ← 要素番号1に"日本"を挿入
 2 アメリカ │  フランス ┐
 3 イギリス │  アメリカ │
 4 ドイツ  │  イギリス ├ 要素番号を繰り下げる
 5 日本  →┘  ドイツ  │
 6 イタリア    イタリア │
 7 カナダ     カナダ  ┘

 **<from>
 変数宣言 局所,文字列{ &mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }
 :
 *

 変数宣言 自動,文字列{ &string }

 &string = "日本"
 手続き実行 prcHistoryDimSet( &string, &mGroupOfSevenDim )

 **<to>
 手続き定義開始 prcHistoryDimSet( 文字列 &string, 参照 文字列 &stringDim[] )
  変数宣言 自動,文字列{ &icon, &title = "prcHistoryDimSet( )", &msg }
  変数宣言 自動,整数 { &top = 1, &bottom = #配列要素数( "stringDim" ), &i, &next = 1, &before = -1, &found }

  if ( &stringDim[ &top ] <> &string .and &top <> &bottom )

   繰り返し &i = &top + 1, &bottom, &next

    &found = &i

    if ( &stringDim[ &i ] = &string )
     繰り返し中止
    end
   繰り返し終了

   繰り返し &i = &found, &top + 1, &before
    &stringDim[ &i ] = &stringDim[ &i - 1 ]
   繰り返し終了

  end

  &stringDim[ &top ] = &string

 手続き定義終了

28.3 指定した要素番号の文字列を削除する
 指定した要素番号の文字列を削除して、削除した要素番号以降を繰り上げる。

 実行前      実行後
 1 フランス    フランス
 2 アメリカ    アメリカ
 3 イギリス    イギリス
 4 ドイツ     ドイツ
 5 日本  ←削除 イタリア
 6 イタリア    カナダ
 7 カナダ         ← 繰り上げたので 7 は未定義値になる

 **<from>
 変数宣言 局所,文字列{ &mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }
 :
 *

 変数宣言 自動,整数{ &dimNum }

 &dimNum = 5
 手続き実行 prcHistoryDimErase( &dimNum, &mGroupOfSevenDim )

 **<to>
 手続き定義開始 prcHistoryDimErase( 整数 &dimNum, 参照 文字列 &stringDim[] )
  変数宣言 自動,文字列{ &icon, &title = "prcHistoryDimErase( )", &msg }
  変数宣言 自動,整数 { &bottom = #配列要素数( "stringDim" ), &i, &next = 1 }

  if ( &dimNum < &bottom )

   繰り返し &i = &dimNum, &bottom -1, &next
    &stringDim[ &i ] = &stringDim[ &i + 1 ]
   繰り返し終了

  end

  &stringDim[ &bottom ] = #u

 手続き定義終了


28.4 指定した文字列の要素番号を得る
 指定した文字列を探索して要素番号を得る。要素番号は1から始まる。探索不成功の場合にはゼロ( 0 )が返される。

 1 フランス
 2 アメリカ
 3 イギリス
 4 ドイツ
 5 日本   ← &foundNum = 5 &string = "日本"
 6 イタリア
 7 カナダ


 **<from>
 変数宣言 局所,文字列{ &mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }
 :
 *

 変数宣言 自動,文字列{ &string }
 変数宣言 自動,整数 { &foundNum }

 &string = "日本"
 手続き実行 prcStringDimSeek( &string, &mGroupOfSevenDim, &foundNum )

 メッセージボックス "title", "&foundNum = " + #str( &foundNum )


 **<to>
 手続き定義開始 prcStringDimSeek( 文字列 &string, 参照 文字列 &stringDim[], 参照 整数 &foundNum )
  変数宣言 自動,文字列{ &icon, &title = "prcStringDimSeek( )", &msg }
  変数宣言 自動,整数 { &found }
  変数宣言 自動,整数 { &i, &loop, &step = 1 }

  &foundNum = 0
  &found  = 0

  &loop = #配列要素数( "stringDim" )
  繰り返し &i = 1, &loop, &step

   if ( &stringDim[ &i ] = &string )

    &foundNum = &i
    &found  = 1
    繰り返し中止
   end

  繰り返し終了

 手続き定義終了

28.5 要素番号1に指定した文字列を挿入する
 要素番号1に指定した文字列を挿入する。挿入した要素番号以降を繰り下げる。

 実行前     実行後
 1 フランス   日本   ← 要素番号1に"日本"を挿入
 2 アメリカ   フランス ┐
 3 イギリス   アメリカ │
 4 ドイツ    イギリス ├ 繰り下がる
 5 日本     ドイツ  │
 6 イタリア   日本   │
 7 カナダ    イタリア ┘

 **<from>
 変数宣言 局所,文字列{ &mGroupOfSevenDim[7] }
 &mGroupOfSevenDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }
 :
 *

 変数宣言 自動,文字列{ &string }

 &string = "日本"
 手続き実行 prcStringDimFIFO( &string, &mGroupOfSevenDim )


 **<to>
 手続き定義開始 prcStringDimFIFO( 文字列 &string, 参照 文字列 &stringDim[] )
  変数宣言 自動,文字列{ &icon, &title = "prcStringDimFIFO( )", &msg }
  変数宣言 自動,整数 { &i, &loop, &dimMax = #配列要素数( "stringDim" ), &step = -1 }

  &loop = 2
  繰り返し &i = &dimMax, &loop, &step

   &stringDim[ &i ] = &stringDim[ &i - 1 ]

  繰り返し終了

  &stringDim[ 1 ] = &string

 手続き定義終了


29 半角コンマで区切った文字列を利用する
 桐では半角コンマで区切った文字列を利用して判定や文字列の照合が出来ます。

 ―存在するか否かの判定

 変数宣言 自動,文字列{ &元号 }
 :

 &元号 = "元禄"
 if ( #対応番号( "明治,大正,昭和,平成,令和", &元号 ) <> 0 )
  :
 end

 または

 変数宣言 自動,文字列{ &元号, &元号List }
 &元号List = "明治,大正,昭和,平成,令和"
 :

 &元号 = "元禄"
 if ( #対応番号( &元号List, &元号 ) <> 0 )
  :
 end

 ―文字列の照合

 変数宣言 自動,文字列{ &month,    &monthListList }
 変数宣言 自動,文字列{ &monthOfJapan, &monthOfJapanList }
 変数宣言 自動,整数 { &at }
 :

 &monthListList  = "January,February,March,April,May ,June ,July,August,September,October,November,December"
 &monthOfJapanList = "睦月  ,如月  ,弥生 ,卯月 ,皐月,水無月,文月,葉月 ,長月   ,神無月 ,霜月  ,師走"

 &monthList    = #trim( &monthList, 4 )    /* 空白除去 */
 &monthOfJapanList = #trim( &monthOfJapanList, 4 ) /* 空白除去 */

 &month = "September"
 &at   = #対応番号( &monthListList, &month ) /* "September" は &at = 9 */

 &monthOfJapan = #対応文字列( &monthOfJapanList, &at ) /* &at = 9 → "長月" */


 ― #対応番号と#対応文字列を利用する ― 桐のイベント道場 かっこうBBS(三代目)2011年10月30日より
  二つの文字列、仮に &Aストリング ・ &Bストリング を用意して、
 &Aストリング の中の文字出現位置を、仮に &at として、
 &Bストリング の文字位置 &at の文字列を取り出す。
 この方法はdBASE言語の時からよく利用しました。
 ちなみに、桐の場合には、半角コンマで区切った文字列に対して、
 #対応番号 で &Aストリング の &at が求められますので、
 逆関数の、#対応文字列 で &Bストリング の文字列を取り出します。
 これは著者( ONnoji )が非常によく使う手法ですよ。
 ※著者( ONnoji )のライブラリの中にはた〜くさんありますよ。変数名に List という文字を使っています。

  配列変数を用意して、要素番号1から順番に調べるよりも簡単でしょう。
 以下に具体例を示しますので、参考にしてください。

 フォームアプリケーション入門§2
 テキストボックスの入力前・入力後・ソース値更新イベント より
 ↓
 手続き定義開始 txtToriCode::ソース値更新( )

  &mToriName = "********"
  条件 (&mToriCode="11") &mToriName = "注文仕入"
  条件 (&mToriCode="12") &mToriName = "注文返品"
  条件 (&mToriCode="21") &mToriName = "委託仕入"
  条件 (&mToriCode="22") &mToriName = "委託返品"
  条件 (&mToriCode="91") &mToriName = "その他仕入"
  条件 (&mToriCode="92") &mToriName = "その他返品"

 手続き定義終了

 ↓

 手続き定義開始 txtToriCode::ソース値更新( )
  変数宣言 自動,文字列{ &codeList, &nameList }
  変数宣言 自動,整数 { &at }

  &codeList = "11   ,12   ,21   ,22   ,91    ,92"
  &nameList = "注文仕入,注文返品,委託仕入,委託返品,その他仕入,その他返品"
  &codeList = #trim( &codeList, 4 ) /* 空白文字除去 */

  &at = #対応番号( &codeList, &mToriCode )
  if ( &at )
   &mToriName = #対応文字列( &nameList, &at )
  else
   &mToriName = "********"
  end

 手続き定義終了

30 論理と条件式
 初級者には[比較式]と[条件式]の区別が難しいようです。

30.1 [比較式]と[条件式]の違い

             比較式 条件式
 ・ワイルドカード( * )  ○   ×
 ・範囲( 小 < [] < 大 ) ○   ×  条件式に範囲( 小 < [] < 大 )を使用した場合には希望通りの判定にはなりません
 ・範囲( 小>[], []<大 ) ○   ×

 ・比較演算子      ○   ○
 ・論理演算子      ×   ○
 ・グループ分けのカッコ ×   ○

 初級者が[条件式]で失敗するのは、[条件式]でワイルドカード( * )や範囲( 小 < [] < 大 )を誤って使う場合です。
[条件式]にワイルドカード( * )を使った場合にはエラーが表示されますが、
[条件式]に範囲( 小 < [] < 大 )を使用した場合にはエラーが表示されずに、希望通りの判定にはなりませんので注意してください。

 [比較式]は、[例示による問い合わせ( QBE、英: Query by Example)]の場合に限るとしっかり理解することが重要です。
こうすれば、[比較式]と[条件式]を区別するのは簡単です。

 すなわち、
  ・[例示による問い合わせ( QBE、英: Query by Example)]の場合には[比較式]を使う
  ・それ以外は[条件式]
 です。

30.2 桐の論理値
 桐にはデータ型に[論理型(ブーリアン)]が用意されていませんが、論理値に相当する値があります。

 それは、
  ・[条件式]において未定義値、または数値のゼロ( 0 )は、偽( False )と扱う
  ・それ以外は真( True )と扱う
 です。

 <偽の例>

 ―その値自身が偽

 ゼロ( 0 )
 #u または #未定義値 または ""

 ―比較結果が偽

 ( "男性" = "女性" )
 ( 1 < 0 )

 ―計算結果が偽

 ( #文字置換( "男性", "" ) )
 ( 1 * 0 )

 <真の例>

 ―その値自身が真

 ゼロ以外の数値 例えばイチ( 1 )、例えば 12、例えば -1、… この例は無限でキリがない
 空でない文字列 例えば、"日曜日" … この例も無限でキリがない

 ―比較結果が真

 ( "男性" <> "女性" )
 ( 1 <> 0 )

 ―計算結果が真

 ( #文字置換( "男性", "女性" ) )
 ( 1 * 1 )

 【引用】「桐のヘルプ」の「データと式」→「条件式」→「条件式の基礎知識」
  条件に応じた処理を行なう場面では、条件式を使用します。条件式を使用すると「A のときは B にして、C のときは D にする」などの処理ができます。
  計算式は計算した値を返しますが、条件式を使用する場所では、演算結果が真か偽かのどちらかで判断されます。
  判定 値
  真  計算結果または比較結果がゼロでも未定義でもない。
  偽  計算結果または比較結果がゼロまたは未定義。

 【引用】ブーリアン型 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  ブーリアン型(ブーリアンがた、英: Boolean datatype)は、真理値の「真 = true」と「偽 = false」という2値をとるデータ型である。
  ブーリアン、ブール型、論理型(logical datatype)などともいう。
  2種類の値を持つ列挙型とも、2進で1ケタすなわち1ビットの整数型とも、見ることもできる。
  また、各種ブール演算を行うことができ、論理積 (AND, &, *)、論理和 (OR, |, +)、排他的論理和 (XOR, NEQV, ^)、同値 (EQV, =, ==)、非同値 (NEQV, <>, !=)、否定 (NOT, ~, !) などの操作が可能である。
  これらの演算はブール代数の演算に対応している。


30.3 条件式の書き方

 ―否定演算子 .not
 とにかく値自身や比較結果や計算結果が、{ ゼロ( 0 ) #u( #未定義値 ) または "" }ならば偽なのですから、
否定演算子( .not )を用いれば簡単に真になります。

 以下は、レコードの先頭から終端行へ進む繰り返し構造です。
#eof 関数は、終端行であれば真(1)、そうでなければ偽(0)を返します。
なので、否定演算子( .not ) を用いて論理を反転させた条件式( .not #eof )を使用しているのです。

 ジャンプ 行番号 = 先頭
 繰り返し ( .not #eof )
  :

  ジャンプ 行番号 = 次行
 繰り返し終了

 なお、以下のように否定演算子( .not ) を用いないで条件式を書くこともできます。

 ジャンプ 行番号 = 先頭
 繰り返し ( #eof = 0 )
  :

  ジャンプ 行番号 = 次行
 繰り返し終了

 もちろん、条件式( #eof = 0 )も正しい条件式ですが、普通は条件式( .not #eof )を使用します。
なぜならば、#eof 関数が真(1)または偽(0)のどちらかの値を返すからです。
このように関数が真偽を返す場合には、その関数自身が論理値なのですから、そのまま使うか、否定演算子( .not )を併用するのが一般的なスタイルです。
もちろん、条件式( #eof = 0 )や条件式( #eof <> 1 )は、決して誤りではありませんが一般的なスタイルではありません。

 【桐10ヘルプ】 ― #終端行
  処理対象行が終端行かどうかを調べます。
  終端行であれば真(1)、そうでなければ偽(0)を返します。
  ノート
  ・#終端行 は #EOF と書いてもかまいません。


 ―論理積演算子 .and と論理和演算子 .or

 さて、突然ですが

 1足す2掛ける3の答えは?

 すなわち、1+2*3 である。答えは7である。
もしも、答えを9だと思った人は、四則演算の優先順位を忘れています。

 実は、論理演算子にも優先順位があります。

 1+2*3 のそれぞれの数字(項)を条件式に例えてみると次のようになります

 条件式1+条件式2*条件式3

 当然、まず、条件式2*条件式3を評価して、その結果と条件式1+を評価します。

 これを論理演算子で書き直すと次のようになります。

 条件式1 .or 条件式2 .and 条件式3

 論理演算子の名前自身に[積]と[和]という文字が使われているのでとても覚えやすいハズです。
 すなわち
  論理積 … .and
  論理和 … .or
 です。

 ちなみに、 .AND でも .OR でも半角でも全角でもOKですが、本書では半角英小文字で統一します。

 ―グループ分けのカッコ" ( ) "

 なお、論理積演算子よりも優先されるものがあります。
それは、グループ分けのカッコ" ( ) "です。
これも四則演算と同様ですから覚えやすいハズです。

 例えば ( 条件式1 .or 条件式2 ) .and 条件式3


 【引用】「桐のヘルプ」の「データと式」→「条件式」→「条件式の基礎知識」
  ・つぎの式は比較式でのみ有効です。条件式では希望どおりの判定にはなりせんので、書かないように心がけてください。
  (誤)20<=[年齢]<=30
  (正)20<=[年齢] .and [年齢]<=30

  条件式で使用できる演算子
  条件式では、算術演算子以外に=や≧などの比較演算子、.and や .or などの論理演算子が使用できます。条件式で使用できる演算子と、演算子の優先順序はつぎのとおりです。

  種類 演算子     優先順位
  算術演算子
  ( )        1
  ^         2
  ×、*      3
  ÷、/      3
  %        3
  +、−      4
  比較演算子
  >        5
  <        5
  ≦、<=、=<    5
  ≧、>=、=>    5
  ≠、<>、><    5
  論理演算子
  .not       6
  .and       7
  .or        8

  ・括弧を 30 重まで入れ子にして、評価の優先順位を変更できます。
  ・論理演算子の前後は、かならず1文字以上の空白を入れてください。

 ― コラム3 論理値のこと ― 桐のイベント道場 2001-08-28 より

  <論理と論理値>
   論理という言葉に抵抗を感じる人があるかと思います。
  例えば「不毛な論理」などいうように日常生活では悪いイメージに使う場面が多いようですが、
  このコラムで扱う論理は日常生活における論理とは異なります。
  実は私たちがコンピュータのプログラムを作るときには、必ずといって良いほど論理のお世話になっています。
  身近な例では桐の#条件選択( )関数や、
  IF <条件> ELSE END、繰り返し <条件> 繰り返し終了 といった構文で使用する条件式も論理です。
  このように桐で条件式と呼んでいるものはすべて論理になります。

  論理には「それは正しい」と「それは間違っている」の二つしかありません。
  注意:日常生活における「それは判らない」というのは含まれません。
  「それは正しい」を真(True)といいます。
  「それは間違っている」を偽(False)といいます。
  もしも、真や偽という言葉が難しいと感じる人は、「はい・いいえ」や「Yes・No」と考えるとよいと思います。
  この真と偽のニ値を論理値といいます。

  論理でおもしろいことのひとつに論理値を正反対にする操作があります。
  「それは正しい」の反対 → 「それは正しくない」 → 「それは間違っている」
  「それは間違っている」の反対 → 「それは間違っていない」 →「それは正しい」
  正反対にすることを「否定」といいます。コンピュータではNOT演算子が否定に相当します。
  NOT演算子は便利なのでよく使います。次の例はNOT演算子を利用したものです。
  注意:桐のNOT演算子は NOTの前にドット(.)を付けます。

  繰り返し (.not #終端行) /*終端行で無い間 繰り返します*/
   :
   ジャンプ 行番号=次行
  繰り返し終了

  <桐の論理値>
  桐には項目のデータ型として論理型(Yes/No型)はありません。
  項目のデータ型に論理型が無いのですから変数のデータ型にも論理型がありません。
  しかし、論理値に相当する値はあるのです。結論から先にいうと次のようになります。

  (1)条件式において、未定義値は偽とみなされる。
  (2)条件式において、数値型等の0(ゼロ)は偽とみなされる。
  (3)それ以外は条件式において真とみなされる。

  それでは身近な#条件選択( )関数を例にして論理値を考えてみましょう。

  (例)#条件選択([性別]="1","男性",1,"女性")

  上の例は文字列型項目[性別]の値が"1"の時に"男性"という文字列を返し、そうでない時には"女性"という文字列を返します。
  ところで最初の条件式の[性別]="1"は直感的に理解できますが、
  最後の条件式の数値の1(イチ)に対しては不思議に思った経験のある人が多いだろうと思います。作者もその一人です。
  それにしても最後の条件式の数値の1(イチ)とはどういう意味なのでしょうか?
  そこでもう一度、論理値のルールを確かめてみることにしましょう。

  (1)条件式において、未定義値は偽とみなされる。
  (2)条件式において、数値の0(ゼロ)は偽とみなされる。
  (3)それ以外は条件式において真とみなされる。

  上のルールに照らし合わせると数値の1(イチ)はルールの3番めに該当しますね。
  なるほどこれで分かりました。つまり、数値の1(イチ)は常に真と評価される条件式になっていたわけです。
  ところで、#条件選択( )関数には多くの「<条件式>,<値>」の組を作ることが出来ますが、
  一般的に最後の条件には常に真と評価される条件式が必要になります。
  これはすべての条件式に当てはまらない場合に未定義値が返されることを防ぐためです。
  常に真と評価される条件式は恒真式と呼びます。
  しかし、どうして恒真式を数値の1(イチ)で表現するのでしょうか。
  恒真式になりさえすれば別の値でもかまわないはずですね。
  試しに次の実験1のように書いてみても正しく動作します。

  ■実験1

  #条件選択([性別]="1","男性",8,"女性")
  #条件選択([性別]="1","男性",−8,"女性")
  #条件選択([性別]="1","男性","そうでなければ","女性")

  作者の考えではルールの2番めで数値の0(ゼロ)が偽であることから、
  真の代表を数値の1(イチ)とするのが桐におけるの恒真式の一般的な書き方だろうと思います。

  <条件式の評価結果を変数に代入する>
  さて、真を数値の1(イチ)にすることには一応の根拠があります。
  それは次の実験2を行うとよく分かります。

  ■実験2

  変数宣言 固有,数値{&gLogical}
  代入 &gLogical = ("あ"="い") /*("あ"="い")は条件式      */
  確認 #str(&gLogical)     /* &gLogicalの値は0(ゼロ)です */
  代入 &gLogical = ("あ"<"い") /*("あ"<"い")は条件式      */
  確認 #str(&gLogical)     /* &gLogicalの値は1(イチ)です */
  条件式の評価結果を変数に代入することは普通しませんので、
  実験2を見て変な代入コマンドの使い方だと思われた人も多いと思いますが、
  実験2から分かるように桐の場合では条件式の評価結果は数値の0(ゼロ)か1(イチ)になります。
  つまり、条件式の評価結果を変数に代入すると真は1、偽は0となるのです。

 <真理値表(Truth table)>
   桐の論理演算子の種類は3つあります。
  優先順位は高いほうから、.not、.and、.orの順です。
  カッコ"( )"を用いてグルーピングすることによってカッコ内を優先できます。
  桐の論理演算子は 演算子の前にドット(.)を付けます。
  p と q はそれぞれ条件式または論理値を表します。

.not 否定
p .not p
真(1) 偽(0)
偽(0) 真(1)
参考:NOTは、否定(反転)の意味

(a) 数値の0と1だけを返す関数
(b) 未定義値と未定義値以外だけを返す関数
 にも利用可能です。

(例) .not #終端行
 これは #終端行<>1 や #終端行=0 と同等です。


.and 論理積
p q p .and q
真(1) 真(1) 真(1)
真(1) 偽(0) 偽(0)
偽(0) 真(1) 偽(0)
偽(0) 偽(0) 偽(0)
参考:ANDは、「なおかつ」の意味

 p と q の両方とも真の時にだけ真になります。

論理積は以下と同等です。
 1×1=1
 1×0=0
 0×1=0
 0×0=0


.or 論理和
p q p .or q
真(1) 真(1) 真(1)
真(1) 偽(0) 真(1)
偽(0) 真(1) 真(1)
偽(0) 偽(0) 偽(0)
参考:ORは、「または」の意味

 p と q のどちらか一方(両方を含む)が真の時に真になります。

論理和は以下と同等です。
 1+1=1 注意:論理なので1になる
 1+0=1
 0+1=1
 0+0=0

   カッコ"( )"を用いてグルーピングすることによってカッコ内を優先できます。
  p .or q .and r  の場合ではand演算子が優先するので q .and r を先に評価します。
  これを代数的に表現すると p + q × r のようになります。
   ( p .or q ) .and r の場合では ( p .or q ) を先に評価します。
  これを代数的に表現すると (p + q) × r のようになります。
  今回のコラム3はこれで終わりです。最後までお読みいただいてありがとうございます。
  では次回をお楽しみに。

31 if と 条件式
 if ( 条件式 ) ... else ... end は[実行制御]のコマンド(文)です。
DOS桐にはif文がなかったので、DOS桐の経験ユーザではif文を珍しく思った人が多いようです。
一方、コンピュータの高級言語(4GLを含む)の経験がある人の場合には、ようやくif文が使えるようになったと大いに喜んだと思います。

31.1 条件式の評価を変数に代入する
 条件式の評価は整数型の変数に代入できます。

 変数宣言 自動,整数{ &logical }
 &logical = ( "男性" = "女性" )  /* &logical にはゼロ( 0 )が代入される */
 &logical = ( "男性" <> "女性" ) /* &logical にはイチ( 1 )が代入される */

 つまり、条件式の評価が偽( false )であればゼロ( 0 )、真( true )であればイチ( 1 )です。

 ―複雑な条件式は変数に代入する

 例えば、

┌if ( 条件式1 .and 条件式2 .and ( 条件式3 .or 条件式4 .or 条件式5 ) )

└end

 というif文は、

 変数宣言 自動,整数{ &logical }

 &logical = ( 条件式3 .or 条件式4 .or 条件式5 )

┌if ( 条件式1 .and 条件式2 .and &logical )

└end

 とすることが出来ます。

 さらに、

 変数宣言 自動,整数{ &logical }

 &logical = ( 条件式1 .and 条件式2 .and ( 条件式3 .or 条件式4 .or 条件式5 ) )

┌if ( &logical )

└end

 とすることも出来ます。

 このようにif文の条件式が長くなる時には、条件式の評価を整数型の変数に代入すると便利です。

31.2 if とプログラムのテスト

 ―プログラムのテスト

 プログラムをテストする際に、次のようにメッセージボックスを表示する方法があります。

┌if ( 条件式 )

│ メッセージボックス "title", "if"  /* 確認 "if"  */

├else

│ メッセージボックス "title", "else" /* 確認 "else" */

└end

 これは次のようにすることでより簡単で分かりやすくなります。

 変数宣言 自動,整数{ &logical }

 &logical = ( 条件式 )
 メッセージボックス "title", "if 条件式 … " + #str( &logical )
┌if ( 条件式 )
│ :
├else
│ :
└end

 または、

 メッセージボックス "title", "if 条件式 … " + #str( ( 条件式 ) )
┌if ( 条件式 )
│ :
├else
│ :
└end

 メッセージボックスの代わりに[トレース出力]コマンドを利用するのも効果的です。

 トレース出力 "if 条件式 … " + #str( ( 条件式 ) )
┌if ( 条件式 )
│ :
├else
│ :
└end


 ―条件式に[恒真式]を利用した確実な実行テスト

 if文は、条件の評価が真( 1 )にならなければ実行されません。
わざわざ真になるようにセッティングするのが面倒だったり、または困難な場合もあります。
その時には、条件式に[恒真式]を利用すると効果的です。

 **if ( 条件式1 .and 条件式2 ) ← 一時的にコメントアウトする
┌if ( 1 )

└end

 ↑上の場合には、[恒真式]のイチ( 1 )を使ったので必ず実行されます。

 また、else以降を実行する場合には、[恒偽式]のゼロ( 0 )を指定します。

 **if ( 条件式1 .and 条件式2 ) ← 一時的にコメントアウトする
┌if ( 0 )
│ :  ← 絶対に実行されません
├else
│ :  ← 必ず実行されます
└end


 ―条件式に[恒偽式]を利用したコメント化

 プログラムの複数行の範囲を一時的にコメントアウトしたいことがあります。
この時にコメントアウトする行数が多いと手間が大変ですし、また元に戻すのも大変です。
その場合には、if ( 0 ) ... end で囲むと便利です。

┌if ( 0 ) /* この行と対応する end をコメントアウトすれば元に戻ります */
│ :
│ :
└end

 【引用】恒真式 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  恒真式(こうしんしき、トートロジー、英: tautology、ギリシャ語のταυτο「同じ」に由来)とは論理学の用語で、
  「aならば aである(a → a)」「aである、または、aでない(a ∨ ¬a)」のように、
  そこに含まれる命題変数の真理値、あるいは解釈に関わらず常に真となる論理式である。

■道草
 DOS桐には if ... end 文がありませんでした。
しかし、繰り返し ( 条件 ) ... 繰り返し終了 文を使って if ... end 文と同じことが可能でした。※ただし、else節は出来ません。
著者( ONnoji )はDOS桐で非常によく利用していましたっけ。

┌繰り返し ( 条件式 )



←─繰り返し中止 /* 無条件に繰り返しを中止する */
└繰り返し終了

 ↑上は下↓と等価です。

┌if ( 条件式 )



└end

32 繰り返し と 条件式
 桐の[繰り返し]コマンド(文)には次の3通りがあります。

 (a) 繰り返し ( <条件式> ) … 繰り返し終了
 (b) 繰り返し … 繰り返し終了
 (c) 繰り返し 回数 … 繰り返し終了

 ■[前判断型の繰り返し( while )]と[後判断型の繰り返し( until )]

 (a) 繰り返し ( <条件式> ) … 繰り返し終了
 (b) 繰り返し … 繰り返し終了

 ↑上の(a) と(b) は実質的に同じものです。

 (a)
 ┌繰り返し ( 条件式 )
 │
 │
 │
 └繰り返し終了

 (b)
 ┌繰り返し
 │
 │
 │┌if ( 条件式 )
 ←┼─繰り返し中止 /* ← 忘れると無限ループになってしまいます */
 │└end
 └繰り返し終了

 何故ならば、(b) は、次の( b′)のように条件式が[恒真式]であると見なせるからです。

 ( b′)
 ┌繰り返し ( 1 )  /* ← 条件式が[恒真式]になっている */
 │
 │
 │┌if ( 条件式 )
 ←┼─繰り返し中止 /* ← 忘れると無限ループになってしまいます */
 │└end
 └繰り返し終了

 (a)は、if文と同じように最初に条件式を評価します。
従って最初に条件式の評価が偽であった場合には、[繰り返し ( <条件式> ) … 繰り返し終了]の範囲を実行しません。
これを、[前判断型の繰り返し( while )]といいます。※初級シスアドでは[While-do型]と呼んでいる

 一方、(b)および( b′)は、まず実行してから、[繰り返し終了]の直前で再び繰り返すのか否かを判断します。
従ってこれは、[後判断型の繰り返し( until )]といいます。※初級シスアドでは[Do-while型]と呼んでいる

 もしも、以上の説明でイメージが掴めない人は、次のように想像してみるとよいと思います。
すなわち、
 ・[前判断型の繰り返し( while )] → 石橋を叩いてから、橋を渡る ※安全そうに見えた橋が実は壊れていて渡れないかもしれない
 ・[後判断型の繰り返し( until )] → まず、飲む牛乳 ※ひょっとして牛乳が腐っていてお腹を壊すかもしれないが全く気にしない
です。


 ― 繰り返しは、[繰り返し ( <条件式> ) … 繰り返し終了]が基本で、これさえマスターすればよい 2018/3/29 ― ブログ版 桐のイベント道場より
   while条件の繰り返しは、if ... end と似ているのです。
  同じところは、最初に条件を満たすか否か判断するところです。
  違いは、[繰り返す]か[繰り返さない]かです。
  以下の繰り返しは、

  ┌繰り返し ( .not #eof )
  │
  │
  │
  │ ジャンプ 行番号 = 次行
  └繰り返し終了

  ↓次のように if ... end を繰り返すのと等価です。

  ┌if ( .not #eof )      ┌if ( .not #eof )      ┌if ( .not #eof )
  │              │              │
  │            → │            → │
  │              │              │
  │ ジャンプ 行番号 = 次行  │ ジャンプ 行番号 = 次行  │ ジャンプ 行番号 = 次行
  └end             └end             └end


 ■[For Next 型の繰り返し]
 配列変数を操作する場合などでは、[For Next 型の繰り返し]が便利です。
これは、カウントアップ、またはカウントダウンして、目標のカウントに達するまで繰り返すというものです。
ちょうど、数を数えるときに指を折って数えるように、親に言われて小さな子供がお風呂で100まで数えるように、それと同じです。

 変数宣言 自動,文字列{ &stringDim[7] }
 &stringDim = { "フランス","アメリカ","イギリス","ドイツ","日本","イタリア","カナダ" }

 変数宣言 自動,整数{ &i, &loop, &step = 1 }

 &loop = #配列要素数( "stringDim" )
┌繰り返し &i = 1, &loop, &step



└繰り返し終了

 ↑上の例では、1( &i )からカウントを始めて、1( &step )ずつ加算して、7( &loop )になるまで繰り返します。

 なお、加算値( &step )を省略する人が多いですが、大した手間ではないので省略しないことをおススメします。
ちなみに、加算値( &step )を省略した場合には、加算値は1または−1になります。
つまり、<開始値>≦<終了値>なら 1ですが、<開始値>><終了値>なら −1 になります。
うっかりすると、1ずつ加算しているつもりで、実は−1づつ加算(つまり減算)していることがありますのでご注意ください。
これを防ぐ方法は、必ず加算値( &step )を記述して省略しないことです。


 【桐10ヘルプ】 ― 繰り返し 回数 … 繰り返し終了
 <加算値>
 繰り返すたびに加算する数値を指定します(計算式)。
 マイナスの値を指定すると、減算になります。
 この値を省略すると、<開始値>≦<終了値>なら 1、<開始値>><終了値>なら -1 を加えます。



 ― 前判断型( do while 型 )は、構造化プログラミングの基本です ― 2018/3/5 ブログ版 桐のイベント道場より
  For Nex 型の繰り返しは、基本的な前判断型( while )で記述できる。

  −例示1− 表定義順の先頭項目から最終項目へブンブン回す

   &step   = 1
   &fieldMax = #項目数

   &loop = &fieldMax
  ┌繰り返し &i = 1, &loop, &step
  │
  │ :
  │
  └繰り返し終了


  ↑の For Next 型を ↓の前判断型( while )に書き換える。

   &fieldMax = #項目数

   &loop = &fieldMax
   &i  = 1
   &step = 1

  ┌繰り返し ( &i <= &loop )
  │
  │ :
  │
  │ &i = &i + &step /* &step の値が1なので &i = &i + 1 と同じ */
  └繰り返し終了

  ↑で現れる、
  &i = &i + &step というのはインクリメント(増分)命令です。
  この例では、&step の値が1なので、
   &i = &i + 1
  と記述してもOK。
  ところで、
   &i = &i + 1
  というのは、初級者には数学の等式に見えて不思議でしょ。
  これは数学の等式ではなく、代入文なので
   &i ← &i + 1 という意味なのです。
  なお、桐では &i = &i + 1 と書くしかありませんが、
  C言語やJava言語では、
   i = i + 1 を i++ と書くのが普通ですよ。

33 スピンボタン
 スピンボタンは、マウスボタンを押している間、テキストボックスの数値を加算し続ける、または数値を減算し続けるボタンです。
Win桐では[スピンボタン]はサポートされていませんが、

 [マウス左ダウン] → [タイマー]イベントで繰り返し実行する → [マウス左アップ] → [マウス左クリック]

というイベントの流れで[スピンボタン]を自作できます。
これは[ドラッグ&ドロップ]と似通ったロジックで、大雑把に言うと[マウス移動]イベントの代わりに、[タイマー]イベントで繰り返し実行するという違いです。

 参照:※フォームアプリケーション教書 第1部 10  [イベント]属性の静的/動的セット
 参照:※フォームアプリケーション教書 第1部 16.5 マウス左ダウン/マウス移動/マウス左アップで[ドラッグ&ドロップ]

 なお、拙作:INF Framework Rev.227以降 または INF Framework Rev.238以降 にてスピンボタン機能をサポートしています。
具体例は、以下のwebページを参照してください。
  ↓
 あこめの桐のプログラミング入門 桐10s by AKome
 スピンボタン
 http://akome409102.html.xdomain.jp/

 【引用】スピンボタン 出典: フリー百科事典『ウィキペディア(Wikipedia)』
  スピンボタン(spin button)はGUIパーツ(ウィジェット)の一種。主としてテキストフィールドの横に配置され、数値の入力などを補助するためのコントロールである。
  TVリモコンでいえばチャンネル送りボタンに相当する。
  スピンボタンのついたテキストボックスのことはスピンボックスと呼ばれる。
  テキストフィールドには不定値の入力が可能だが、それゆえ操作の自由度が高く、「1だけ増やした数」などはかえって入力が面倒になる傾向がある。
  例えば19に1を足せば20であり、二桁の書き換えが必要である。
  またアルファベットを誤入力する可能性も考えられる。
  これらの問題に対し、操作を増加/減少のみに絞った補助機構がスピンボタンである。
  一般に、わずかな量の増減を行なう場合はスピンボタンを操作する方が高速である。
  最大・最小値でループするケースもあり、入力範囲の限定にも有効であることが分かる。


 Fig.21 スピンボタンの例

 参考:スピンボタンのトレース出力

 ―ワンクリックの場合

┌when 手続き"famSpinButton::マウス左ダウン({3990,360},1,1,0)"を実行開始しました

│┌when 手続き"SPNprcTxtSourceEval("&mIndentTopNum","&mIndentTopNum",,)"を実行開始しました
│└end

│┌when 手続き"SPNprcDummyButtonLevel("txtSpinDownFor_txtIndentTopNum",1)"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryON("&SPNmOnSpinButton",50)"を実行開始しました
│└end

│┌when 手続き"SPNprcEventKeyDownON( )"を実行開始しました
│└end

│┌when 手続き"SPNprcEventSystemKeyDownON( )"を実行開始しました
│└end

└end

┌when 手続き"famSpinButton::マウス左アップ({3990,345},1,0)"を実行開始しました

│┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcDummyButtonLevel("txtSpinDownFor_txtIndentTopNum",0)"を実行開始しました
│└end

└end

┌when 手続き"famSpinButton::マウス左クリック({3990,345},1,0,0)"を実行開始しました

│┌when 手続き"SPNprcSpinButtonRepeat("txtSpinDownFor_txtIndentTopNum,txtIndentTopNum,mIndentTopNum,variable,,,down,1,1,,,,0,0",0)"を実行開始しました
││
││┌when 手続き"SPNprcSpinButtonTxtSourceRestore("txtIndentTopNum",10,,0,)"を実行開始しました
││└end
││
│└end

└end


 ―ボタンを押し続けた場合

┌when 手続き"famSpinButton::マウス左ダウン({3960,165},1,1,0)"を実行開始しました

│┌when 手続き"SPNprcTxtSourceEval("&mIndentTopNum","&mIndentTopNum",,)"を実行開始しました
│└end

│┌when 手続き"SPNprcDummyButtonLevel("txtSpinUpFor_txtIndentTopNum",1)"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryON("&SPNmOnSpinButton",50)"を実行開始しました
│└end

│┌when 手続き"SPNprcEventKeyDownON( )"を実行開始しました
│└end

│┌when 手続き"SPNprcEventSystemKeyDownON( )"を実行開始しました
│└end

└end

┌when 手続き"フォーム::タイマー2( )"を実行開始しました

│┌when 手続き"SPNprcEventTimerSecondaryRun( )"を実行開始しました
││
││┌when 手続き"SPNprcTimerSecondaryOFF( )"を実行開始しました
││└end
││
││┌when 手続き"SPNprcTimerPrimaryON("&SPNmOnSpinButton",10)"を実行開始しました
││└end
││
│└end

│┌when 手続き"INFprcEventTimerSecondaryRun( )"を実行開始しました
│└end

└end

┌when 手続き"フォーム::タイマー1( )"を実行開始しました

│┌when 手続き"SPNprcEventTimerPrimaryRun( )"を実行開始しました
││
││┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
││└end
││
││┌when 手続き"SPNprcSpinButtonRepeat("txtSpinUpFor_txtIndentTopNum,txtIndentTopNum,mIndentTopNum,variable,,,up,1,,12,,,0,0",1)"を実行開始しました
│││
│││┌when 手続き"SPNprcSpinButtonTxtSourceRestore("txtIndentTopNum",3,,1,)"を実行開始しました
│││└end
│││
│││┌when 手続き"SPNprcTimerPrimaryON("&SPNmOnSpinButton",10)"を実行開始しました
│││└end
│││
││└end
││
│└end

└end

  :

 マウスボタンが押されている間 手続き"フォーム::タイマー1( )"を繰り返す

  :

┌when 手続き"フォーム::タイマー1( )"を実行開始しました

│┌when 手続き"SPNprcEventTimerPrimaryRun( )"を実行開始しました
││
││┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
││└end
││
││┌when 手続き"SPNprcSpinButtonRepeat("txtSpinUpFor_txtIndentTopNum,txtIndentTopNum,mIndentTopNum,variable,,,up,1,,12,,,0,0",1)"を実行開始しました
│││
│││┌when 手続き"SPNprcSpinButtonTxtSourceRestore("txtIndentTopNum",10,,1,)"を実行開始しました
│││└end
│││
│││┌when 手続き"SPNprcTimerPrimaryON("&SPNmOnSpinButton",10)"を実行開始しました
│││└end
│││
││└end
││
│└end

└end

┌when 手続き"famSpinButton::マウス左アップ({3960,165},1,0)"を実行開始しました

│┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcDummyButtonLevel("txtSpinUpFor_txtIndentTopNum",0)"を実行開始しました
│└end

└end

┌when 手続き"famSpinButton::マウス左クリック({3960,165},1,0,0)"を実行開始しました

│┌when 手続き"SPNprcSpinButtonRepeat("txtSpinUpFor_txtIndentTopNum,txtIndentTopNum,mIndentTopNum,variable,,,up,1,,12,,,0,0",0)"を実行開始しました
││
││┌when 手続き"SPNprcSpinButtonTxtSourceRestore("txtIndentTopNum",11,,0,)"を実行開始しました
││└end
││
│└end

└end

34 リピート(マウスボタンを押している間実行し続ける)ボタン
 スピンボタンと同じロジックでリピート(マウスボタンを押している間実行し続ける)ボタンが自作できます。

 なお、拙作:INF Framework Rev.227以降 または INF Framework Rev.238以降 にてリピート機能をサポートしています。
具体例は、以下のwebページを参照してください。
  ↓
 あこめの桐のプログラミング入門 桐10s by AKome
 オートリピート
 http://akome409102.html.xdomain.jp/


 Fig.22 リピートボタンの例

 参考:リピートボタンのトレース出力

 ―ワンクリックの場合

┌when 手続き"famRecordUpDown::マウス左ダウン({4830,330},1,1,0)"を実行開始しました

│┌when 手続き"SPNprcDummyButtonLevel("cmdDown_cmdDown",1)"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryON("&SPNmOnRecordUpDown",50)"を実行開始しました
│└end

│┌when 手続き"SPNprcEventKeyDownON( )"を実行開始しました
│└end

│┌when 手続き"SPNprcEventSystemKeyDownON( )"を実行開始しました
│└end

└end

┌when 手続き"famRecordUpDown::マウス左アップ({4830,330},1,0)"を実行開始しました

│┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcDummyButtonLevel("cmdDown_cmdDown",0)"を実行開始しました
│└end

└end

┌when 手続き"famRecordUpDown::マウス左クリック({4830,330},1,0,0)"を実行開始しました

│┌when 手続き"SPNprcRecordUpDownRepeat("cmdDown_cmdDown,cmdDown,0,0",0)"を実行開始しました
││
││┌when 手続き"フォーム::レコード移動(2,25,2)"を実行開始しました
│││
│││┌when 手続き"EZWprcEventRecMoveRun(2)"を実行開始しました
│││└end
│││
││└end
││
│└end

└end


 ―ボタンを押し続けた場合

┌when 手続き"famRecordUpDown::マウス左ダウン({4950,255},2,1,0)"を実行開始しました

│┌when 手続き"SPNprcDummyButtonLevel("cmdDown_cmdDown",1)"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryON("&SPNmOnRecordUpDown",50)"を実行開始しました
│└end

│┌when 手続き"SPNprcEventKeyDownON( )"を実行開始しました
│└end

│┌when 手続き"SPNprcEventSystemKeyDownON( )"を実行開始しました
│└end

└end

┌when 手続き"フォーム::タイマー2( )"を実行開始しました

│┌when 手続き"SPNprcEventTimerSecondaryRun( )"を実行開始しました
││
││┌when 手続き"SPNprcTimerSecondaryOFF( )"を実行開始しました
││└end
││
││┌when 手続き"SPNprcTimerPrimaryON("&SPNmOnRecordUpDown",10)"を実行開始しました
││└end
││
│└end

│┌when 手続き"INFprcEventTimerSecondaryRun( )"を実行開始しました
│└end

└end

┌when 手続き"フォーム::タイマー1( )"を実行開始しました

│┌when 手続き"SPNprcEventTimerPrimaryRun( )"を実行開始しました
││
││┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
││└end
││
││┌when 手続き"SPNprcRecordUpDownRepeat("cmdDown_cmdDown,cmdDown,0,0",1)"を実行開始しました
│││
│││┌when 手続き"フォーム::レコード移動(3,25,3)"を実行開始しました
││││
││││┌when 手続き"EZWprcEventRecMoveRun(3)"を実行開始しました
││││└end
││││
│││└end
│││
│││┌when 手続き"SPNprcTimerPrimaryON("&SPNmOnRecordUpDown",10)"を実行開始しました
│││└end
│││
││└end
││
│└end

└end

  :

 マウスボタンが押されている間 手続き"フォーム::タイマー1( )"を繰り返す

  :

┌when 手続き"フォーム::タイマー1( )"を実行開始しました

│┌when 手続き"SPNprcEventTimerPrimaryRun( )"を実行開始しました
││
││┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
││└end
││
││┌when 手続き"SPNprcRecordUpDownRepeat("cmdDown_cmdDown,cmdDown,0,0",1)"を実行開始しました
│││
│││┌when 手続き"フォーム::レコード移動(4,25,4)"を実行開始しました
││││
││││┌when 手続き"EZWprcEventRecMoveRun(4)"を実行開始しました
││││└end
││││
│││└end
│││
│││┌when 手続き"SPNprcTimerPrimaryON("&SPNmOnRecordUpDown",10)"を実行開始しました
│││└end
│││
││└end
││
│└end

└end

┌when 手続き"famRecordUpDown::マウス左アップ({4950,255},2,0)"を実行開始しました

│┌when 手続き"SPNprcTimerPrimaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcTimerSecondaryOFF( )"を実行開始しました
│└end

│┌when 手続き"SPNprcDummyButtonLevel("cmdDown_cmdDown",0)"を実行開始しました
│└end

└end

35 プログレスバー
 プログレスバーは、時間がかかる処理の進捗状況を水平方向のバー示し、進捗率を示すものです。

 【引用】プログレスバー 出典: フリー百科事典『ウィキペディア(Wikipedia)』
   プログレスバー(英: Progress Bar)とは、長時間かかるタスクの進捗状況がどの程度完了したのかを視覚的・直感的に表示するもので、
  グラフィカルユーザインタフェースの要素(ウィジェット)の一つである。
  しばしば、ダウンロードやファイル転送のようにパーセント形式で表示される際に使われる。
  プログレスメーター (英: Progress Meters)とも呼ばれる。
  プログレスバーの外観形態としては、左から右へ満たされていく水平方向のバーで進捗率を表すものがよく使われている。
   タスク完了までの処理量や時間が予測できないなど、タスクの進行の割合を表すことができない状況で使用される場合、
  一定幅のカラーバーが全体のバー内を繰り返し移動するアニメーションといったような、「未定プログレスバー」(英: Indeterminate)として表示される。
  このバーは進行の総量(サイズ)がいっぱいになるのを示すのではなく、現在進行中であることを示す動きとしてインジケーターの役割を兼ねた働きをしている。
  Microsoft Windowsでは、この表示状態をマーキースタイル(英: Marquee Style)と呼ぶこともある。


35.1 内部プログレスバーと外部プログレスバー
 Win桐ではプログレスバーはサポートされていませんが、
  [タイマー] → [タイマー]イベントで繰り返し実行する
 というイベントの流れで[プログレスバー]を自作できます。

 プログレスバーを自分自身のフォームに組み込んだものを[内部プログレスバー]と呼ぶことにします。
一方、プログレスバーを自分自身のフォームとは別のモーダルフォームに組み込んだものを[外部プログレスバー]と呼ぶことにします。

 プログレスバーを自作する場合には、[内部プログレスバー]の方が[外部プログレスバー]と比べて難易度が低くなります。
これは[外部プログレスバー]が自分自身のフォームとは別のモーダルフォームであるという理由からです。
従って、最初は[内部プログレスバー]をテストして、もしも必要ならば[外部プログレスバー]に仕上げるというアプローチがよいです。


 Fig.23 内部プログレスバーの例


 Fig.24 外部プログレスバーの例


 Fig.25 外部未定プログレスバーの例

35.2 プログレスバー実行中に作業を中断する
 プログレスバー実行中に作業を中断できると便利です。
[タイマー]イベントを利用するのは、中断を可能にするために他なりません。
もしも、[タイマー]イベントを使用せずに[プログレスバー]を作ったならば、処理が終わるまで中断することができません。

 [プログレスバー]を実行する際には、事前に[タイマー]イベントを実行する回数を決定して、1回あたりに処理する単位を求めて[タイマー]イベントを複数回実行します。
[タイマー]イベントで1回あたりに処理する単位は、レコード数でも他の単位でもOKです。

 ※「未定プログレスバー」の場合には、[タイマー]イベントを実行する回数は事前に決定できません。

35.3 プログレスバーの事例

 プログレスバーと言っても色々あります。

 ・フォームが[応答なし]と表示されないように、または作業の進捗状態をユーザに見せるために、
  負荷が掛かる一本道の作業を、[複数の手続きに分けて]または[同じ手続きを複数回に分けて]タイマーで実行する。

 ・シェル実行の実行成果(テキスト)とタイミングを合わせるためにタイマーを実行して待機する。

 ・未定プログレスバー:つまり、いつ終わるか予測不能な作業をタイマーで分割実行する。

 なお、[外部プログレスバー]と[内部プログレスバー]の違いは、外部のフォームでプログレスバーを実行するか否かの違いで、あまり重要ではありません。

 プログレスバーを使う理由は次の通り

 ・処理の経過を可視化する
 ・処理を中断できるようにする ※処理内容によっては中断しない方がよい場合もあります
 ・処理を分割して実行することによって、PCがビジー(応答なし)状態になることをなるべく抑える

 以下は、拙作:God_Excel_Reader 第1.0版 の God_Excel_Reader_ProgressBar.kev の内容です。
以下にご紹介する事例は外部プログレスバーなので、プログレスバーはGod_Excel_Reader_ProgressBar.wfm/kev になります。
なお、ソースの保守変更が容易になるように、[ミッション]は &PRGmSendMissionCommand を[コマンド]コマンドで実行しています。
ちなみに、[トレース出力]コマンドを多用している理由は、プログレスバーの動作を掌握するためです。
[トレース出力]コマンドの出力結果は、拙作:整形ユーティリティで見易く整形できます。
[トレース出力]コマンドを利用しない場合でも、プログレスバーの動作を掌握する必要があって、それはとても面倒です。
なので、著者( ONnoji )はプログレスバーを[フレームワーク化]して改良を重ねてきました。

■フェーズ1(スタートアップ) ダイアグラム

 ┌────────────────┐
 │                │
 │ [開始時実行コマンド]ボタン │
 │                │
 │ cmdStartupClick         │
 │                │
 └────┬───────────┘
      │
      │
 ┌────┴───────────┐
 │                │
 │ プログレスバー・スタートアップ│
 │                │
 │ PRGprcProgressBarStartup    │
 │                │
 └────┬───────────┘
      │
      │
 ┌────┴─────────────┐
 │                  │   ┌─────────────┐
 │ プログレスバー・初期化      ├───┤ プログレスバー幅取得  │
 │                  │   │ PRGprcProgressBarWidthGet│
 │ PRGprcProgressBarInitializeAndRun │   └─────────────┘
 │                  │   ┌─────────────┐
 │                  ├───┤ プログレスバー表示更新 │
 │                  │   │ PRGprcProgressbarAppear │
 │                  │   └─────────────┘
 │                  │   ┌─────────────┐
 │                  ├───┤ タイマーセット     │
 │                  │   │ INFprcTimerPrimaryON   │
 │                  │   └─────────────┘
 │                  │   ┌─────────────┐
 │                  ├───┤ 割り込みキーセット   │
 │                  │   │ VKprcEventKeyDownON・他 │
 │                  │   └─────────────┘
 └────┬─────────────┘
      │
      ↓
   タイマーループ


■フェーズ2(タイマーループ) ダイアグラム

 ┌─────────────┐   ┌─────────────┐
 │             │   │             │   ┌────────────────┐これはスタブ(代用・ダミー)で仮テスト用です
 │ タイマー実行      │   │             ├───┤ ミッション          │ ↓
 │             ├───┤ 処理をユニット単位で実行│   │ prcPowershellReplaceTxtFileLoad│PRGprcStubMissionCommand
 │ フォーム::タイマー1       │   │             │   └────────────────┘
 │             │   │ PRGprcProgressBarCall  │   ┌─────────────┐
 └─────────────┘   │             ├───┤ プログレスバー表示更新 │
                   │             │   │ PRGprcProgressbarAppear │
                   │             │   └─────────────┘
                   │             │   ┌─────────────┐
                   │             ├───┤ 続行/停止の判定    │   ┌─────────────┐
                   │             │   │ PRGprcProgressBarCallEval├───┤ タイマーリセット    │
                   │             │   │             │   │ INFprcTimerPrimaryOFF  │
                   │             │   │             │   └─────────────┘
                   │             │   │             │   ┌─────────────┐
                   │             │   │             ├───┤ 割り込みキーリセット  │
                   │             │   │             │   │ VKprcEventKeyDownOFF・他 │
                   │             │   │             │   └─────────────┘
                   │             │   └─────────────┘
                   │             │   ┌─────────────┐
                   │             ├───┤ リターン        │
                   │             │   │ HDLVARcmdButtonClick   │
                   │             │   └─────┬───────┘
                   └─────────────┘         │
                                           │
                                           ↓
                                      呼び出し元のフォームへ復帰

cmdStartupClick              [開始時実行コマンド]ボタン

├ PRGprcProgressBarStartup        プログレスバー・スタートアップ
│ │
│ └ PRGprcProgressBarInitializeAndRun プログレスバー・初期化
│   │
│   ├ PRGprcProgressBarWidthGet   プログレスバー幅取得
│   │
│   ├ PRGprcProgressBarAppear    プログレスバー表示更新
│   │
│   ├ INFprcTimerPrimaryON      タイマーセット
│   │
│   ├ VKprcEventKeyDownON      割り込みキーセット
│   │
│   ├ VKprcKeyON
│   │
│   └ VKprcKeySet

└ ( UIprcFormObjectSeekOnHdl )

フォーム::タイマー1

├ ( MNUprcEventTimerPrimaryRun )

├ ( SPNprcEventTimerPrimaryRun )

├ ( INFprcEventTimerPrimaryRun )

└ PRGprcProgressBarCall      処理をユニット単位で実行
  │
  ├ PRGprcStubMissionCommand  ミッション ※ PRGprcStubMissionCommand は、スタブ(代用・ダミー)で仮テスト用です
  │
  ├ PRGprcProgressBarAppear   プログレスバー表示更新
  │
  ├ PRGprcProgressBarCallEval  続行/停止の判定
  │ │
  │ ├ INFprcTimerPrimaryOFF  タイマーリセット
  │ │
  │ ├ VKprcEventKeyDownOFF  割り込みキーリセット
  │ │
  │ ├ VKprcKeyOFF
  │ │
  │ └ VKprcKeyClear
  │
  └ HDLVARcmdButtonClick    リターン

 **---------- <begin プログレスバー ProgressBar Framework 第3.2版 名札 メイン> ---------------**
 変数宣言 局所,整数 { &HDLVARmOkOnly = 1 } /* OKのみのダイアログボックスとして動作、[×][Esc][閉じる]等が[OK]と同等になる。但し exit の値は -1 */
 変数宣言 局所,文字列{ &PRGmProgressMsg }
 変数宣言 局所,文字列{ &PRGmProgressAddMsg }
 変数宣言 局所,数値 { &PRGmProgressbarWidth }
 変数宣言 局所,整数 { &PRGmContinue }
 変数宣言 局所,整数 { &PRGmOnProcessRun } /* &PRGmOnProcessContinue → &PRGmOnProcessRun 第 3.0 版 */
 変数宣言 局所,長整数{ &PRGmProcessUnit }  /* &PRGmRecordUnit        → &PRGmProcessUnit  第 3.0 版 */
 変数宣言 局所,長整数{ &PRGmProcessCount }
 変数宣言 局所,長整数{ &PRGmProcessMaxCount }
 変数宣言 局所,整数 { &PRGmProcessLap }
 変数宣言 局所,整数 { &PRGmEscKeyUse }
 変数宣言 局所,整数 { &PRGmBreakByEscKey }
 ** 2021.10.07 不要:変数宣言 局所,文字列{ &PRGmPurocedureName }
 変数宣言 局所,整数 { &PRGmOdometerType }                         /* 2020.10.26 New! */
 ** 2021.10.14 不要:変数宣言 局所,日時 { &PRGmProcessBeginDate } /* 2021.10.06 New! */
 ** 2021.10.14 不要:変数宣言 局所,日時 { &PRGmProcessEndDate }   /* 2021.10.06 New! */

 ** 変数宣言 局所,整数 { &PRGmSendTryCountMax }         /* 2021.10.07 &HDLVARmStoreParameter で宣言する */
 ** 変数宣言 局所,整数 { &PRGmSendPrimaryTimerInterval }/* 2021.10.07 &HDLVARmStoreParameter で宣言する */
 ** 変数宣言 局所,整数 { &PRGmSendMissionCommand }      /* 2021.10.11 &HDLVARmStoreParameter で宣言する */
 ** 変数宣言 局所,整数 { &PRGmSendAddMsg }              /* 2021.10.07 &HDLVARmStoreParameter で宣言する */

 ** ProgressBar Framework 第 3.0 版 2020.10.11 utx_list3_argsvar_All.wfm/.kev これは内部プログレスバーです
 ** ProgressBar Framework 第 3.1 版 2020.11.08 NDL_ISBN_search_ProgressBar.wfm/.kev ※ eval_01_ISBNでゲットだぜ.wfm → 蔵書物品エントリー.wfm
 ** ProgressBar Framework 第 3.2 版 2021.10.07 God_Excel_Reader_ProgressBar.wfm/.kev
 **---------- <end プログレスバー ProgressBar Framework 第3.2版 名札 メイン> ---------------**


手続き定義開始 cmdStartupClick( )
 変数宣言 自動,文字列{ &icon, &title = "cmdStartupClick( )", &msg }

 変数宣言 自動,文字列{ &traceMsg = #cond( #変数( "INFmTraceFormPathAdd" ), &INFmMyWfmPath ) + &INFmMyWfmName + " hdl=" + #last( " " + #str( &hwindow ), 2 ) + ">" + &title }
 変数宣言 自動,整数 { &traceON = #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "ALL" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "PRG" ) }

 **&traceON = 1
 条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"
 条件 ( &traceON ) トレース出力 "**********************************"
 条件 ( &traceON ) トレース出力 "** [開始時実行コマンド]ボタン **"
 条件 ( &traceON ) トレース出力 "**********************************"

 条件 ( &traceON ) トレース出力 "if ( #ウィンドウハンドル( &HDLVARmReferWfmHdl ) ) … " + #str( ( #ウィンドウハンドル( &HDLVARmReferWfmHdl ) ) )
 if ( #ウィンドウハンドル( &HDLVARmReferWfmHdl ) ) /* 呼び出し元フォームのウィンドウが存在すれば… */

  *  &msg = #文字置換( &mTempTblName, "\", "\\" )
  *  &msg = &msg + "\n\n" + #文字置換( &mTempFileName, "\", "\\" )
  &icon = "i"
  **手続き実行 INFprcMsgPause( &icon, &title, &msg )

  条件 ( &traceON ) トレース出力 " 手続き実行 PRGprcProgressBarStartup( )"
  手続き実行 PRGprcProgressBarStartup( )

  *----------- begin 桐sfor SmartLicense 対応 ----------*
  if ( #変数( "UImConvertLive" ) )
   if ( #局所変数( &HDLVARmReferWfmHdl, "UImModernUse" ) .and .not &UImModernUse )
    &UImModernUse = #局所変数( &HDLVARmReferWfmHdl, "UImModernUse" )
    手続き実行 UIprcFormObjectSeekOnHdl( &UImModernUse ) /* 2022.01.22 */
   end
  end
  *----------- end 桐sfor SmartLicense 対応 ----------*
 end

 条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
手続き定義終了

手続き定義開始 PRGprcProgressBarStartup( )
 ** modify 手続き定義開始 PRG標準cmdProgressBarStartClick( )
 変数宣言 自動,文字列{ &icon, &title = "PRGprcProgressBarStartup( )", &msg }
 変数宣言 自動,文字列{ &addMsg } /* , &purocedureName */
 変数宣言 自動,長整数{ &recordCount, &processUnit }
 変数宣言 自動,長整数{ &countMax, &processUnit }
 変数宣言 自動,整数 { &pass, &escKeyUse }
 変数宣言 自動,整数 { &timerInterval }
 変数宣言 自動,整数 { &odometerType }

 変数宣言 自動,文字列{ &traceMsg = #cond( #変数( "INFmTraceFormPathAdd" ), &INFmMyWfmPath ) + &INFmMyWfmName + " hdl=" + #last( " " + #str( &hwindow ), 2 ) + ">" + &title }
 変数宣言 自動,整数 { &traceON = #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "ALL" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "PRG" ) }

 **&traceON = 1
 条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"
 条件 ( &traceON ) トレース出力 "************************************"
 条件 ( &traceON ) トレース出力 "** プログレスバー・スタートアップ **"
 条件 ( &traceON ) トレース出力 "************************************"

 if ( 0 )
  &recordCount = 1000

  &pass = 2
  ケース開始
    **ケース ( &recordCount < 50 )
    ** &pass = 2
   ケース ( &recordCount < 100 )
    &pass = 2
   ケース ( &recordCount < 200 )
    &pass = 4
   ケース ( &recordCount < 500 )
    &pass = 10
   ケース その他 /* 500行以上は 20パス(5%)刻み */
    &pass = 20
  ケース終了
  &processUnit = #切り上げ( &recordCount / &pass, 0 )
 end

 &pass          = 100 /* &PRGmProcessMaxCount = &pass       最大処理回数            */
 &processUnit   = 1   /* &PRGmProcessUnit     = &processUnit 1回あたりの処理単位数 */
 &timerInterval = 100 /* タイマー1のインターバル 単位は 1/100秒                    */

 ** &HDLVARmStoreParameter 整数 { &PRGmSendTryCountMax, &PRGmSendPrimaryTimerInterval }
 条件 ( &traceON ) トレース出力 " if ( #配列要素数( ""PRGmSendTryCountMax"" ) = 0 ) … " + #str( ( #配列要素数( "PRGmSendTryCountMax" ) = 0 ) )
 if ( #配列要素数( "PRGmSendTryCountMax" ) = 0 )

  &pass = 1
  if ( #変数( "PRGmSendTryCountMax" ) >= 1 )
   &pass = #変数( "PRGmSendTryCountMax" ) /* &PRGmProcessMaxCount = &pass 最大処理回数 */
  end
 end

 条件 ( &traceON ) トレース出力 " if ( #配列要素数( "PRGmSendPrimaryTimerInterval" ) = 0 ) … " + #str( ( #配列要素数( "PRGmSendPrimaryTimerInterval" ) = 0 ) )
 if ( #配列要素数( "PRGmSendPrimaryTimerInterval" ) = 0 )

  &timerInterval = 10
  if ( #変数( "PRGmSendPrimaryTimerInterval" ) > 10 )
   &timerInterval = #変数( "PRGmSendPrimaryTimerInterval" ) /* タイマー1のインターバル 単位は 1/100秒 */
  end
 end

 条件 ( &traceON ) トレース出力 " &pass          = " + #str( &pass )          + " 最大処理回数"
 条件 ( &traceON ) トレース出力 " &processUnit   = " + #str( &processUnit )   + " 1回あたりの処理単位数"
 条件 ( &traceON ) トレース出力 " &timerInterval = " + #str( &timerInterval ) + " タイマー1のインターバル 単位は 1/100秒"

 &escKeyUse    = 1
 &odometerType = 2 /* オドメータ 1: % 2: 回数 */
 &addMsg       = " XMLファイル取得中..."
 条件 ( &traceON ) トレース出力 " if ( #trim( #変数( ""PRGmSendAddMsg"" ), 4 ) <> #u ) … " + #str( ( #trim( #変数( "PRGmSendAddMsg" ), 4 ) <> #u ) )
 if ( #trim( #変数( "PRGmSendAddMsg" ), 4 ) <> #u )
  &addMsg = #変数( "PRGmSendAddMsg" ) /* 2021.10.07 */
 end

 手続き実行 PRGprcProgressBarInitializeAndRun( &timerInterval, &pass, &processUnit, &escKeyUse, &odometerType, &addMsg ) /* , &purocedureName */

 条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
手続き定義終了

手続き定義開始 PRGprcProgressBarInitializeAndRun( 整数 &timerInterval, 長整数 &pass, 長整数 &processUnit, 整数 &escKeyUse, 整数 &odometerType, 文字列 &addMsg ) /* 不要:, 文字列 &purocedureName */
 変数宣言 自動,文字列{ &icon, &title = "PRGprcProgressBarInitializeAndRun( )", &msg }
 変数宣言 自動,文字列{ &objectName }
 変数宣言 自動,整数 { &isObject }

 変数宣言 自動,文字列{ &traceMsg = #cond( #変数( "INFmTraceFormPathAdd" ), &INFmMyWfmPath ) + &INFmMyWfmName + " hdl=" + #last( " " + #str( &hwindow ), 2 ) + ">" + &title }
 変数宣言 自動,整数 { &traceON = #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "ALL" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "PRG" ) }

 **&traceON = 1
 条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"
 条件 ( &traceON ) トレース出力 "****************************"
 条件 ( &traceON ) トレース出力 "** プログレスバー・初期化 **"
 条件 ( &traceON ) トレース出力 "****************************"

 &objectName = "PRGlblProgressBar" /* 規定値 */
 手続き実行 PRGprcProgressBarWidthGet( &objectName, &isObject, &PRGmProgressbarWidth )
 条件 ( &traceON ) トレース出力 "**************************"
 条件 ( &traceON ) トレース出力 "** プログレスバー幅取得 **"
 条件 ( &traceON ) トレース出力 "**************************"
 条件 ( &traceON ) トレース出力 " 手続き実行 PRGprcProgressBarWidthGet( &objectName, &isObject, &PRGmProgressbarWidth )"

 条件 ( &traceON ) トレース出力 " if ( &isObject ) … " + #str( ( &isObject ) )
 if ( &isObject )
  *----- begin 初期化 ----------*
  &PRGmProcessMaxCount = &pass         /* 最大処理回数                */
  &PRGmProcessCount    = 0            /* 回数カウンタ 初期化         */
  &PRGmProcessUnit     = &processUnit  /* 処理単位数                  */
  &PRGmOnProcessRun    = 1            /* タイマーフラグ 初期化       */
  &PRGmContinue        = 1             /* 続行フラグ 初期化           */
  &PRGmProcessLap      = 0             /* 周回数 初期化               */
  &PRGmEscKeyUse       = &escKeyUse    /* Escキーを使うか否か         */
  &PRGmBreakByEscKey   = 0             /* Escキー中断フラグ           */
  &PRGmOdometerType    = &odometerType /* オドメータ 1: % 2: 回数     */
  &PRGmProgressAddMsg  = &addMsg       /* "処理中... ( Escキーで中止 )" */
  ** 2021.10.07 不要:&PRGmPurocedureName = &purocedureName /* タイマーから呼び出す手続き名 */

  手続き実行 PRGprcProgressBarAppear( 0, &PRGmProgressAddMsg ) /* プログレスバーの表示をリセット */
  条件 ( &traceON ) トレース出力 "****************************"
  条件 ( &traceON ) トレース出力 "** プログレスバー表示更新 **"
  条件 ( &traceON ) トレース出力 "****************************"
  条件 ( &traceON ) トレース出力 " 手続き実行 PRGprcProgressBarAppear( 0, &PRGmProgressAddMsg )"

  手続き実行 INFprcTimerPrimaryON( "&PRGmOnProcessRun", &timerInterval ) /* タイマーフラグ をオン */
  条件 ( &traceON ) トレース出力 "********************"
  条件 ( &traceON ) トレース出力 "** タイマーセット **"
  条件 ( &traceON ) トレース出力 "********************"
  条件 ( &traceON ) トレース出力 " 手続き実行 INFprcTimerPrimaryON( ""&PRGmOnProcessRun"", &timerInterval )"
  *----- end 初期化 ----------*

  条件 ( &traceON ) トレース出力 ""
  条件 ( &traceON ) トレース出力 " *----- begin 初期化 ----------*"
  条件 ( &traceON ) トレース出力 " &timerInterval       = " + #str( &timerInterval )       + " タイマー1のインターバル 引数:&timerInterval 単位は 1/100秒"
  条件 ( &traceON ) トレース出力 " &PRGmOnProcessRun    = " + #str( &PRGmOnProcessRun )    + " タイマー1のフラグ"
  条件 ( &traceON ) トレース出力 " &PRGmProcessMaxCount = " + #str( &PRGmProcessMaxCount ) + " 最大処理回数 引数:&pass"
  条件 ( &traceON ) トレース出力 " &PRGmProcessCount    = " + #str( &PRGmProcessCount )    + " 回数カウンタ"
  条件 ( &traceON ) トレース出力 " &PRGmProcessUnit     = " + #str( &PRGmProcessUnit )     + " 処理単位数 引数:&processUnit"
  条件 ( &traceON ) トレース出力 " &PRGmContinue        = " + #str( &PRGmContinue )        + " 続行フラグ"
  条件 ( &traceON ) トレース出力 " &PRGmProcessLap      = " + #str( &PRGmProcessLap )      + " 周回数"
  条件 ( &traceON ) トレース出力 " &PRGmEscKeyUse       = " + #str( &PRGmEscKeyUse )       + " Escキーを使うか否か 引数:&escKeyUse"
  条件 ( &traceON ) トレース出力 " &PRGmBreakByEscKey   = " + #str( &PRGmBreakByEscKey )   + " Escキー中断フラグ"
  条件 ( &traceON ) トレース出力 " &PRGmOdometerType    = " + #str( &PRGmOdometerType )    + " ""オドメータ 1: % 2: 回数 引数:&odometerType"""
  条件 ( &traceON ) トレース出力 " &PRGmProgressAddMsg  = " + #str( &PRGmProgressAddMsg )  + " 処理中メッセージ 引数;addMsg"
  条件 ( &traceON ) トレース出力 " &PRGmSendMissionCommand = " + &PRGmSendMissionCommand   + " "
  条件 ( &traceON ) トレース出力 " *----- end 初期化 ----------*"
  条件 ( &traceON ) トレース出力 ""

  条件 ( &traceON ) トレース出力 " if ( &PRGmEscKeyUse ) … " + #str( ( &PRGmEscKeyUse ) )
  if ( &PRGmEscKeyUse )
   手続き実行 VKprcEventKeyDownON( )
   手続き実行 VKprcKeyON( )
   手続き実行 VKprcKeySet( "Esc", 1, "0", "手続き実行 PRGprcProgressBarOnKeyEsc( &VKmRepeat )" )
   条件 ( &traceON ) トレース出力 "************************"
   条件 ( &traceON ) トレース出力 "** 割り込みキーセット **"
   条件 ( &traceON ) トレース出力 "************************"
   条件 ( &traceON ) トレース出力 " 手続き実行 VKprcEventKeyDownON( )"
   条件 ( &traceON ) トレース出力 " 手続き実行 VKprcKeyON( )"
   条件 ( &traceON ) トレース出力 " 手続き実行 VKprcKeySet( ""Esc"", 1, ""0"", ""手続き実行 PRGprcProgressBarOnKeyEsc( &VKmRepeat )"" )"
  end

 else
  条件 ( &traceON ) トレース出力 " プログレスバーを表示するためのオブジェクトが見つかりません"
  条件 ( &traceON ) トレース出力 " &objectName = " + &objectName

  &msg = "プログレスバーを表示するためのオブジェクトが見つかりません"
  &msg = &msg + "\n\n&objectName = " + &objectName
  &msg = &msg + "\n\n&isObject   = " + #str( &isObject )
  &icon = "e"
  手続き実行 INFprcMsgPause( &icon, &title, &msg )
 end

 条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
手続き定義終了

手続き定義開始 フォーム::タイマー1()
 変数宣言 自動,文字列{ &icon, &title = "フォーム::タイマー1( )", &msg }

 変数宣言 自動,文字列{ &traceMsg = #cond( #変数( "INFmTraceFormPathAdd" ), &INFmMyWfmPath ) + &INFmMyWfmName + " hdl=" + #last( " " + #str( &hwindow ), 2 ) + ">" + &title }
 変数宣言 自動,整数 { &traceON = #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "ALL" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "INF" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "TIMER" ) }

 **&traceON = 1
 条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

 *---------- begin MNU Tools フォーム::タイマー1 ---------------*
 **if ( #変数( "MNUmLive" ) )
 条件 ( #変数( "MNUmLive" ) ) 手続き実行 MNUprcEventTimerPrimaryRun( )
 **end
 *---------- end MNU Tools フォーム::タイマー1 -----------------*

 *---------- begin SpinButton_library フォーム::タイマー1 --------------------*
 **if ( #変数( "SPNmOnSpinButton" ) .or #変数( "SPNmOnRecordUpDown" ) )
 条件 ( #変数( "SPNmOnSpinButton" ) .or #変数( "SPNmOnRecordUpDown" ) ) 手続き実行 SPNprcEventTimerPrimaryRun( )
 **end
 *---------- end SpinButton_library フォーム::タイマー1 --------------------*

 *---------- begin INF Framework フォーム::タイマー1 ---------------*
 **if ( #変数( "INFmLive" ) .and #変数( "HDLSELmOnHdlSet" ) )
 **条件 ( #変数( "INFmLive" ) .and ( #変数( "HDLSELmOnHdlSet" ) .or #変数( "INFmOnErrorInfoRead" ) ) ) 手続き実行 INFprcEventTimerPrimaryRun( )
 ** Rev.101 2010.02.22 フォーム::タイマー1() を変更
 条件 ( #変数( "INFmLive" ) .and ( #変数( "HDLSELmOnHdlSet" ) .or #変数( "INFmOnErrorInfoRead" ) .or #変数( "ONEmOnEraseTempTbl" ) ) ) 手続き実行 INFprcEventTimerPrimaryRun( )
 **end
 *---------- end INF Framework フォーム::タイマー1 -----------------*

 *---------- begin プログレスバー ---------------*
 条件 ( &traceON ) トレース出力 " if ( #変数( ""PRGmOnProcessRun"" ) ) … " + #str( #変数( "PRGmOnProcessRun" ) )
 if ( #変数( "PRGmOnProcessRun" ) )

  ** NDL_ISBN_search_ProgressBar.kev では、コマンド &macro としていたが、トレース出力の結果が分かりにくいので、手続き名を PRGprcProgressBarCall( ) に固定した
  条件 ( &traceON ) トレース出力 "手続き実行 PRGprcProgressBarCall( )"
  手続き実行 PRGprcProgressBarCall( ) /* 2021.10.06 */

 end
 *---------- end プログレスバー ---------------*

 条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
手続き定義終了

手続き定義開始 PRGprcProgressBarCall( )
 変数宣言 自動,文字列{ &icon, &title = "PRGprcProgressBarCall( )", &msg }
 変数宣言 自動,整数 { &cnt }
 変数宣言 自動,整数 { &percent }
 変数宣言 自動,整数 { &missionComplete }

 変数宣言 自動,文字列{ &traceMsg = #cond( #変数( "INFmTraceFormPathAdd" ), &INFmMyWfmPath ) + &INFmMyWfmName + " hdl=" + #last( " " + #str( &hwindow ), 2 ) + ">" + &title }
 変数宣言 自動,整数 { &traceON = #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "ALL" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "PRG" ) }

 **&traceON = 1
 条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"
 条件 ( &traceON ) トレース出力 "******************************"
 条件 ( &traceON ) トレース出力 "** 処理をユニット単位で実行 **"
 条件 ( &traceON ) トレース出力 "******************************"

 &PRGmProcessLap = &PRGmProcessLap + 1
 条件 ( &traceON ) トレース出力 " &PRGmProcessLap = " + #str( &PRGmProcessLap )

 &cnt = 0
 繰り返し ( &PRGmContinue )
  条件 ( &traceON ) トレース出力 " 繰り返し ( &PRGmContinue )"

  &PRGmProcessCount = &PRGmProcessCount + 1
  &cnt = &cnt + 1
  条件 ( &traceON ) トレース出力 " &PRGmProcessCount = " + #str( &PRGmProcessCount )
  条件 ( &traceON ) トレース出力 " &cnt = " + #str( &cnt )

  *----------- begin このプログレスバーのミッション -----------*
  条件 ( &traceON ) トレース出力 ""
  条件 ( &traceON ) トレース出力 " *----- begin このプログレスバーのミッション ----------*"

  &missionComplete = 0

  条件 ( &traceON ) トレース出力 "if ( #変数( ""PRGmSendMissionCommand"" ) <> #u ) … " + #str( ( #変数( "PRGmSendMissionCommand" ) <> #u ) )
  if ( #変数( "PRGmSendMissionCommand" ) <> #u )

   条件 ( &traceON ) トレース出力 "#変数( ""PRGmSendMissionCommand"" ) = " + #変数( "PRGmSendMissionCommand" )
   **手続き実行 prcPowershellReplaceTxtFileLoad( &mTempTblName, &mTempFileName, &missionComplete )
   コマンド #変数( "PRGmSendMissionCommand" )
  else

   手続き実行 PRGprcStubMissionCommand( &missionComplete )
  end

  条件 ( &traceON ) トレース出力 " if ( &missionComplete ) … " + #str( &missionComplete )
  if ( &missionComplete )
   条件 ( &traceON ) トレース出力 " *----- begin 目的作業の完了判定 ----------*"

   ** 引数:&missionComplete が真になったら、目的作業が完了しているので、&PRGmProcessCount = &PRGmProcessMaxCount にセットする
   &PRGmProcessCount = &PRGmProcessMaxCount
   条件 ( &traceON ) トレース出力 " &PRGmProcessCount = &PRGmProcessMaxCount"

   条件 ( &traceON ) トレース出力 " *----- end 目的作業の完了判定 ----------*"
  end
  条件 ( &traceON ) トレース出力 " *----- end このプログレスバーのミッション ----------*"
  条件 ( &traceON ) トレース出力 ""
  *----------- end このプログレスバーのミッション -----------*

  条件 ( &traceON ) トレース出力 " if ( &cnt >= &PRGmProcessUnit .or &PRGmProcessCount >= &PRGmProcessMaxCount ) … " + #str( ( &cnt >= &PRGmProcessUnit .or &PRGmProcessCount >= &PRGmProcessMaxCount ) )
  if ( &cnt >= &PRGmProcessUnit .or &PRGmProcessCount >= &PRGmProcessMaxCount )

   条件 ( &traceON ) トレース出力 " 繰り返し中止"
   繰り返し中止
  end
 繰り返し終了

 &percent = #切捨て( &PRGmProcessCount / &PRGmProcessMaxCount * 100, 0 )
 条件 ( &traceON ) トレース出力 " &percent = " + #str( &percent )

 条件 ( &traceON ) トレース出力 " if ( &percent >= 100 ) … " + #str( ( &percent >= 100 ) )
 if ( &percent >= 100 )
  &percent = 100
 end
 手続き実行 PRGprcProgressBarAppear( &percent, &PRGmProgressAddMsg )

 条件 ( &traceON ) トレース出力 " 手続き実行 PRGprcProgressBarCallEval( )"
 手続き実行 PRGprcProgressBarCallEval( )

 条件 ( &traceON ) トレース出力 " if ( .not &PRGmContinue ) … " + #str( ( .not &PRGmContinue ) )
 if ( .not &PRGmContinue )
  条件 ( &traceON ) トレース出力 "*********************"
  条件 ( &traceON ) トレース出力 "** HDLVAR 終了処理 **"
  条件 ( &traceON ) トレース出力 "*********************"

  ** 2021.10.14 不要:&PRGmProcessEndDate = #日時値

  &msg = "&PRGmContinue = " + #str( &PRGmContinue )
  &msg = &msg + "\n\n&missionComplete = " + #str( &missionComplete )
  &icon = "i"
  **手続き実行 INFprcMsgPause( &icon, &title, &msg )

  条件 ( &traceON ) トレース出力 " if ( &missionComplete ) … " + #str( ( &missionComplete ) )
  if ( &missionComplete )

   条件 ( &traceON ) トレース出力 " 手続き実行 HDLVARcmdButtonClick( 1 )"
   手続き実行 HDLVARcmdButtonClick( 1 )
  else

   ** 2020.11.02 手続き実行 HDLVARcmdButtonClick( 0 )
   ** 2020.11.02 変数宣言 局所,整数 { &HDLVARmOkOnly = 1 }
   条件 ( &traceON ) トレース出力 " メソッド呼び出し @cmd閉じる.実行( )"
   メソッド呼び出し @cmd閉じる.実行( ) /* [中止][×][Esc]で -1 が返るように変更 */
  end

 end

 条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
手続き定義終了

手続き定義開始 PRGprcStubMissionCommand( 参照 整数 &done )
 変数宣言 自動,文字列{ &icon, &title = "PRGprcStubMissionCommand( )", &msg }

 変数宣言 自動,文字列{ &traceMsg = #cond( #変数( "INFmTraceFormPathAdd" ), &INFmMyWfmPath ) + &INFmMyWfmName + " hdl=" + #last( " " + #str( &hwindow ), 2 ) + ">" + &title }
 変数宣言 自動,整数 { &traceON = #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "ALL" ) .or #対応番号( #uc2( #変数( "INFmTraceModuleNameList" ) ), "PRG" ) }

 **&traceON = 1
 条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"
 条件 ( &traceON ) トレース出力 "**************************************"
 条件 ( &traceON ) トレース出力 "** この手続きはスタブ(代用品)です **"
 条件 ( &traceON ) トレース出力 "**************************************"

 条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
手続き定義終了

36 フォームとフォームの間での変数の受け渡し
 小規模なアプリケーションでは、たったひとつのフォームウィンドウを用意するだけで済む場合があります。
しかし、多くの場合には複数のフォームウィンドウと連携するアプリケーションになります。
 [主ウィンドウ]に対応する[副ウィンドウ]、つまり[ダイアログボックス]と[補助ウィンドウ]の場合には、
  ・[主ウィンドウ]→[副ウィンドウ]
  ・[副ウィンドウ]→[主ウィンドウ]
 の双方向に局所変数の値を受け渡せると便利です。
これはプロシージャの引数の受け渡しを、[フォーム]ウィンドウで行うのと同じです。

 ■[主ウィンドウ]に対応する[副ウィンドウ]

 ―ダイアログボックス

 [主ウィンドウ/ダイアログボックス(モーダル・ポップアップ)]型

 主ウィンドウ                      ダイアログボックス
 Aフォーム                       Bフォーム
 ┌───────────────────────┐   ┌──────────────────┐
 │コマンドボタンの標題             │   │コマンドボタンの標題        │
 │ダイアログボックスを開く           │   │OK                │
 │                       │   │                  │
 │機能名       機能パラメータリスト   │   │機能名  機能パラメータリスト   │
 │1 なし       #代入( &実行リターン, 0 ) ┝━━━┥1 なし  #代入( &実行リターン, 1 ) │
 │2 モーダルフォーム Bフォーム        ┝━━━┥2 閉じる              │
 │3 なし                    │   │3 なし               │
 │4 なし                    │   │4 なし               │
 └───────────────────────┘   └──────────────────┘
 【参考】[キャンセル]ボタンの例 1 なし  #代入( &実行リターン, 0 )

 ―補助ウィンドウ

 [主ウィンドウ/補助ウィンドウ(モードレス・ポップアップ)]型

 主ウィンドウ              ポップアップ形式の補助ウィンドウ
 Aフォーム               Bフォーム
 ┌───────────────┐   ┌───────────────┐
 │コマンドボタンの標題     │   │コマンドボタンの標題     │
 │Bフォームを開く       │   │Bフォームを閉じる      │
 │               │   │               │
 │機能名  機能パラメータリスト│   │機能名  機能パラメータリスト│
 │1 開く  Bフォーム     ├→→→┤1 閉じる           │
 │2 なし            │   │2 なし            │
 │3 なし            │   │3 なし            │
 │4 なし            │   │4 なし            │
 └───────────────┘   └───────────────┘

36.1 [主ウィンドウ]のウィンドウハンドル番号
 [主ウィンドウ]から[副ウィンドウ]が開かれた時、※モーダルでもモードレスでもOK
[副ウィンドウ]側で[主ウィンドウ]のウィンドウハンドル番号が判明すれば、[副ウィンドウ]側で[主ウィンドウ]の局所変数を参照できます。

 ■[主ウィンドウ]→[副ウィンドウ]

 [主ウィンドウ]のウィンドウハンドル番号は、[主ウィンドウ]のシステムが用意した局所変数の &hwindow です。
そこで、任意の数値型の組み込み変数に局所変数の &hwindow の値を代入して、[副ウィンドウ]側で組み込み変数を参照すれば、
[副ウィンドウ]側で関数:#局所変数 を用いて[主ウィンドウ]の局所変数の値を取得することが可能になります。

 以下の例は組み込み変数:&標準偏差 に局所変数の &hwindow の値(ウィンドウハンドル番号)を代入しています。

 ―[副ウィンドウ]のBフォームをモーダルで開く場合

 主ウィンドウ  Aフォーム
 ┌────────────────────────┐
 │コマンドボタンの標題              │
 │ダイアログボックスを開く            │
 │                        │
 │機能名       機能パラメータリスト    │
 │1 なし       #代入( &実行リターン, 0 )  │
 │2 なし       #代入( &標準偏差, &hwindow )│
 │3 モーダルフォーム Bフォーム         │
 │4 なし                     │
 └────────────────────────┘

 ―[副ウィンドウ]のBフォームをモードレスで開く場合

 主ウィンドウ  Aフォーム
 ┌────────────────────┐
 │コマンドボタンの標題          │
 │Bフォームを開く            │
 │                    │
 │機能名  機能パラメータリスト     │
 │1 なし  #代入( &標準偏差, &hwindow ) │
 │2 開く  Bフォーム          │
 │3 なし                 │
 │4 なし                 │
 └────────────────────┘

 ■[副ウィンドウ]→[主ウィンドウ]

 すでに[主ウィンドウ]のウィンドウハンドル番号が既知になっているので、
[局所変数代入]コマンド、または[ #局所変数代入]関数を用いて[主ウィンドウ]の局所変数に対して値を代入できます。

 ― 局所変数代入 &hdl, &mVariableName = 式 … command

 (例) 局所変数代入 &hdl, &mVariableName = #u /* コマンドなので関数と異なり戻り値がありません */

 ※Syntax:局所変数代入 <ハンドル>,<変数名> = <計算式>|<配列変数名>[ <要素番号> ] = <計算式>|<配列変数名> = { <計算式>,… }

 ― #局所変数代入( &hdl, &mVariableName, 式 ) … function
 ※この関数は#代入 のハンドル付きバージョンです

 <注意>
 [副ウィンドウ]のBフォームをモードレスで開いた場合、[主ウィンドウ]がすでに閉じられている場合があります。
 [ #ウィンドウハンドル]関数で、ウィンドウが開かれてるかチェックする必要があります。

 (例)
 ┌if ( #ウィンドウハンドル( &hdl ) ) /* ウィンドウが開かれていれば真(1) 開かれていなければ偽(0)*/
 │
 └end

 また、[主ウィンドウ]がすでに閉じられてから別のウィンドウが同じウィンドウハンドル番号で開いているかもしれません。
 このように[副ウィンドウ]のBフォームをモードレスで開いた場合には、十分注意してください。

36.2 INF_Framework のHLDVAR機能
 拙作:INF_Framework では、[フォームとフォームの間での変数の受け渡し]をHLDVAR機能と呼んで以前から対応しています。
拙作は単に値の受け渡しだけではなく、[副ウィンドウ]側で[主ウィンドウ]の局所変数と同名の変数を宣言して値を代入する機能も含んでいます。
また、[副ウィンドウ]側の応答ボタンの判別も可能です。
詳しくは標準フレームワークに同梱されている HDLVAR仕様メモ.txt をご覧ください。


 Fig.26 INF_Framework HDLVAR機能の標準応答ボタン

37 メイン&サブフォーム

 メイン&サブフォームは、メインに相当するフォームに[サブフォーム]オブジェクトを作成して、
[サブフォーム]オブジェクトの[サブフォーム名]属性に任意のフォーム名を設定したものです。

37.1 [サブフォーム]オブジェクトの[グループ値リスト]属性

 桐10sのサンプルでは、
・メインフォーム … カード形式( メインサブフォーム.wfx )
          明細部に[サブフォーム]オブジェクト
                ↑
                └──[グループ値リスト]に [伝票No], [納品日] を設定
                                 ↑    ↑
・サブフォーム  … 伝票形式( サブフォーム.wfx )        ↓    ↓
          フォームヘッダ部に2つの[グループ項目]([伝票No]と[納品日])を配置して[画面表示]を"しない"に設定

という具合になっています。

 これはメインフォームとサブフォームを[共通のグループ値でリンク]するために考案したサンプルであろうとかと思われます。
しかし、実際にこのようなデザインがベターなのか否か甚だ疑問であり、おそらくは説明のためのサンプルであろうと著者( ONnoji )は推測しています。
ちなみに、このサンプルのように敢えて[表ファイルを2つに分割してメイン&サブフォームで表示]しなくても、
[1つの表ファイルを[グループ項目]を設定したフォームで表示]すればシンプルになるのですが…※これはDOS桐から存在する画面伝票です

 【引用】「桐のヘルプ」 ― [グループ値リスト]
  ・サブフォームのグループ項目値とリンクする際に使用するデータを指定します。項目名、変数名、定数、計算式が指定できます。
  ・サブフォームに複数の[グループ項目]オブジェクトを配置している場合は、[グループ項目]オブジェクトの定義順でデータを指定します。各データはコンマ(,)で区切ります。
   (例) [学年],[組],[出席番号]


37.2 メインフォームとサブフォームのイベントの発生順
 メインフォームとサブフォームの両方にイベント処理が設定してある場合には、
メインフォームのイベントとサブフォームのイベントが交互に発生するので注意が必要です。

(例)

メインサブフォーム.kex

名札 メイン
 変数宣言 局所, 整数{ &hMain, &hSub }, 局所, 文字列{ &SysT = "メインサブフォーム" }


手続き定義開始 フォーム::フォーム開始(長整数 &表番号)
 &hMain = &表番号
手続き定義終了


サブフォーム.kex

名札 メイン
 変数宣言 局所,整数{ &hSub }, 局所,通貨{ &税抜合計, &消費税合計 }


手続き定義開始 フォーム::フォーム開始(長整数 &表番号)
 &hSub = &表番号
手続き定義終了


 ■トレース出力の結果

┌when メイン処理を実行開始しました メインサブフォーム.kex
└end

 DB( 2):"d:\path\売上ヘッダ.tbx"をモード=専有更新で開きました

┌when メイン処理を実行開始しました サブフォーム.kex
└end

 DB( 3):"d:\path\売上.tbx"をモード=専有更新で開きました

┌when 手続き"フォーム::フォーム開始(2)"を実行開始しました メインサブフォーム.kex
└end

┌when 手続き"フォーム::フォーム開始(3)"を実行開始しました サブフォーム.kex
└end

37.3 局所変数の上書きとその対策
 メインフォームとサブフォームのそれぞれの[名札 メイン]で同名の局所変数を宣言していたならば、後から宣言した同名の局所変数で上書きされます。
しかし、データ型が異なる場合と、データ型が同じでも配列要素数が異なる場合には、
サブフォーム側の[名札 メイン]実行中に次のエラーが表示されて、サブフォーム側の[名札 メイン]の実行が中断されます。

 KU1151:変数名はすでに定義されています

 【引用】「桐のヘルプ」 ― [局所変数を有効にする]
  ・サブフォーム側で定義した局所変数も宣言する場合はON、宣言しない場合はOFFにします。
  ・この属性をOFFにしても、サブフォームのイベント処理ファイルに定義した局所変数は宣言されます。
  ・メインフォームとサブフォームで同名の局所変数を定義する場合は、サブフォーム側で定義する局所変数のデータ型が、
   メインフォーム側で定義した局所変数のデータ型と同じでなければいけません。


 このようにメイン&サブフォームでは、[名札 メイン]で宣言した局所変数の上書きが発生するために、
メイン側とサブフォーム側での変数名の衝突が起きていないか十分注意する必要があります。
 しかし、いくら注意しても同名の変数を宣言する可能性があります。
それを積極的に解決する方法は、サブフォーム側の[名札 メイン]で宣言する局所変数名に任意の接頭辞を付けることです。

 (例) 変数宣言 局所,文字列{ &mString } → 変数宣言 局所,文字列{ &SUBmString }

37.4 INF_Framework とメイン&サブフォーム
 拙作:INF_Framework は、当初はメイン&サブフォームでも動作するようになっていました。
しかし、メイン&サブフォームでは局所変数が上書きされるために、メイン側とサブフォーム側のフォーカスが切り替わるたびに、
テキストデータを外部へ値を出力して、保存してあったテキストデータを読み込んでというスワップ動作をしていました。
 しかし、手間が掛かる割には、メイン&サブフォームを利用することが非常に少ないので第3版から完全にスワップ動作を中止しました。
これによって第3版では、メインフォームだけにしか拙作:INF_Framework を導入出来なくなりました。
※サブフォーム側に拙作:INF_Framework を導入しようとしても、自動的に検知して導入をキャンセルするようになっています。

 ― メイン&サブフォームのサポート終了 2008/6/6 ― ブログ版 桐のイベント道場より
  ■メイン&サブフォームの場合の互換性
   メインフォームとサブフォームの両方にINF_Tools_library を適用している場合は極めて少ないと思いますが、
  ※ここでは、INF_Tools_library を両方に適用している場合を、メイン&サブフォームと呼びます。
   INF Tools Framework Rev.72 は上位互換性がありますので、INF_Tools_library を利用した既存のメイン&サブフォームでも問題なく動作するはずです。
  ※ここでは、INF_Tools_library を両方に適用している場合を、メイン&サブフォームと呼びます。
  ※INF_Tools_library をメイン側だけに適用の場合は、何も問題ありません。
  ※INF_Tools_library をサブフォーム側だけに適用することは不可能です。
   しかし、都合によりメイン&サブフォームのサポートを終了させていただくことになりました。
  詳しくは以下をお読みください。
  ■メイン&サブフォームのサポート終了
   掲示板などで明言しているのでご存知の人もあるかもしれませんが、
  著者( ONnoji )は、桐のアプリケーション開発でメイン&サブフォームというアプローチを放棄しました。
  そのため、従来からある機能については、旧:INF_Tools_library との互換性は保持しましたが、
   INF Tools Framework Rev.72 で新しく追加された機能は、サブフォーム側でテストしていません。
  ※メイン&サブフォームを使わないので、今後もテストを行いません。
   新い機能のために追加された局所変数は、メイン・サブ間で変数値のスワップを行いません。
  ※メイン&サブフォームでは局所変数は共通なので、フォーカスの移動に伴って変数値のスワップが必要になります。
   そのために動作が不安定(デタラメ)になります。
  従いまして、新しく追加された機能はメイン&サブフォームで利用しないでください。
  ※ここでは、INF_Tools_library を両方に適用している場合を、メイン&サブフォームと呼びます。
  ※INF_Tools_library をメイン側だけに適用の場合は、何も問題ありません。
  ※INF_Tools_library をサブフォーム側だけに適用することは不可能です。

37.5 リンクしないサブフォーム
 メイン&サブフォームと聞くと、[グループ値リスト]でリンクしていると思う人が多いことでしょう。
Win桐に付属しているサンプルを見せられると、リンクしているのが当たり前で、それが常識だと思う人が大多数かもしれません。
しかし、リンクしないメイン&サブフォームだってOKなのです。

 以下に[50音]のボタンを配置した NULLフォーム をフォームヘッダ部に設定した例を示します。 ― 「グラスの底に顔があっても良いじゃないか」岡本太郎

 <サブフォーム側のプロシージャ>

手続き定義開始 cmdButtonClick( 文字列 &objectName, 文字列 &caption )

┌if ( &mSubFormMode .and &caption <> #u )

│ &mKeypadCaption = &caption
│ 
メソッド呼び出し ハンドル = &hwindow, @cmdサブフォームから実行.実行( )
└end                      ↓
                        ↓
手続き定義終了                 ↓
                        ↓
 <
メインフォーム側のコマンドボタン:cmdサブフォームから実行

 ┌───────────────────────┐
 │コマンドボタンの標題             │
 │
cmdサブフォームから実行            │
 │                       │
 │機能名      機能パラメータリスト    │
 │1 実行条件                  │
 │2 表示                    │
 │3 手続き実行   cmdサブフォームから実行Click│
 │4 なし                    │
 └───────────────────────┘


 Fig.27 リンクしないサブフォーム( NULLフォーム )


 Fig.28 [50音]のボタンを配置した NULLフォーム

38 手続きの入れ子 手続きの[再帰呼び出し]

38.1 手続きのネスト(入れ子)
 桐の仕様では、
  ・手続きの入れ子 100重
 となっています。
しかし、実際に試してみると桐ver.8 の時から桐10sの現在でも、110重までネスト(入れ子)出来ます。

 さすがに110重まで手続きをネストすることは無いと思いますが、
しかし、うっかり[再帰呼び出し]をするとアッという間にネスト(入れ子)が深くなってしまいますので注意してください。

 ― 再帰呼び出しによるネスト(入れ子)のテスト

 **<from>
 手続き実行 prcTest( 0 )

 **<to>
 手続き定義開始 prcTest( 整数 &i )

  &i = &i + 1
  トレース出力 _&i

  手続き実行 prcTest( &i )

 手続き定義終了


 ■トレース出力結果

 :&i : 1
 :&i : 2
 :&i : 3
 :&i : 4
 :&i : 5
 :&i : 6
 :&i : 7
 :&i : 8
 :&i : 9
 :&i : 10
 :&i : 11

  :
  :

 :&i : 92
 :&i : 93
 :&i : 94
 :&i : 95
 :&i : 96
 :&i : 97
 :&i : 98
 :&i : 99
 :&i : 100
 :&i : 101
 :&i : 102
 :&i : 103
 :&i : 104
 :&i : 105
 :&i : 106
 :&i : 107
 :&i : 108
 :&i : 109
 :&i : 110
 エラー :KU1239:手続き実行のネストが深すぎます

38.2 再帰呼び出し
 Win桐では、手続きの[再帰呼び出し]が可能になりました。
一般的に、
 ・再帰によるプログラムは、PCに負荷をかけるプログラムであり、時によっては膨大な負荷をかけることもある。※ハノイの塔、フィボナッチ数 etc.
 ・だから、簡単に非再帰プログラムとして書けるものならば、再帰プログラムを使わないようにします。
↑上のように、再帰は出来るだけ避けるべきものです。
しかし、非再帰プログラムでは複雑なプログラムになってしまうものが、再帰プログラムでは簡単に書けることがあります。

 再帰プログラムの方が非再帰プログラムよりも簡単な例として非常に有名なものは[ハノイの塔]と呼ばれるものです。

 【引用】ハノイの塔 出典: フリー百科事典『ウィキペディア(Wikipedia)』
   ハノイの塔(ハノイのとう、Tower of Hanoi)はパズルの一種。 バラモンの塔または ルーカスタワー(Lucas' Tower)とも呼ばれる。
  ■ルール
  以下のルールに従ってすべての円盤を右端の杭に移動させられれば完成。
   ・3本の杭と、中央に穴の開いた大きさの異なる複数の円盤から構成される。
   ・最初はすべての円盤が左端の杭に小さいものが上になるように順に積み重ねられている。
   ・円盤を一回に一枚ずつどれかの杭に移動させることができるが、小さな円盤の上に大きな円盤を乗せることはできない。
  n枚の円盤すべてを移動させるには最低 2^n - 1 回の手数がかかる。
  解法に再帰的アルゴリズムが有効な問題として有名であり、プログラミングにおける再帰的呼出しの例題としてもよく用いられる。
  ただし支配数がメルセンヌ数なので、同じく再帰の例題として多用されるフィボナッチ数同様、再帰をストレートに実装するととんでもない事態を生む例でもある。
  ■由来
   :
  64枚の円盤を移動させるには、最低でも
  (264^64 - 1)回 = 18,446,744,073,709,551,615 回 = 1844京6744兆737億955万1615回
  かかり、1枚移動させるのに1秒かかったとすると、最低でも約5845億年かかる(なお、ビッグバンは今から約137億年前に発生したとされている)。


 ―Win桐による[ハノイの塔]の再帰プログラム

 さまざまなwebページにC言語・その他で[ハノイの塔]の再帰プログラムの例が紹介されています。
そこで、桐言語でコーディングした例を以下に示します。

 **Win桐による[ハノイの塔]の再帰プログラム

 ** &n  … 整数 :移動させる円盤の枚数
 ** &from … 文字列:移動元の棒の名前
 ** &work … 文字列:作業用に使う棒の名前
 ** &dest … 文字列:移動先の棒の名前

 **<from>
 &n = 3   /* 3枚の場合 */
 手続き実行 prcHanoi( &n, "A", "B", "C" )


 **<to>
 手続き定義開始 prcHanoi( 整数 &n, 文字列 &from, 文字列 &work, 文字列 &dest )

  if ( &n >= 2 )
   手続き実行 prcHanoi( &n -1, &from, &dest, &work ) /* 再帰呼び出し:自分自身を call すること */
  end

  トレース出力 #str( &n ) + " を " + &from + " から " + &dest + " へ"

  if ( &n >= 2 )
   手続き実行 prcHanoi( &n -1, &work, &from, &dest ) /* 再帰呼び出し:自分自身を call すること */
  end

 手続き定義終了

 ■トレース出力結果

┌when :prcHanoi( )を実行開始しました

│┌when :prcHanoi( )を実行開始しました
││
││┌when :prcHanoi( )を実行開始しました
│││
│││ :1 を A から C へ
│││
││└end
││
││ :2 を A から B へ
││
││┌when :prcHanoi( )を実行開始しました
│││
│││ :1 を C から B へ
│││
││└end
││
│└end

│ :3 を A から C へ

│┌when :prcHanoi( )を実行開始しました
││
││┌when :prcHanoi( )を実行開始しました
│││
│││ :1 を B から A へ
│││
││└end
││
││ :2 を B から C へ
││
││┌when :prcHanoi( )を実行開始しました
│││
│││ :1 を A から C へ
│││
││└end
││
│└end

└end



 Fig.29 ハノイの塔

 【引用】再帰 出典: フリー百科事典『ウィキペディア(Wikipedia)』
   再帰(さいき)は、あるものについて記述する際に、記述しているものそれ自身への参照が、その記述中にあらわれることをいう。
  定義において、再帰があらわれているものを再帰的定義という。
  自己相似の記事も参照のこと。
  主に英語のrecursionとその派生語の訳にあてられる。
  他にrecurrenceの訳(回帰#物理学及び再帰性を参照のこと)や、reflexiveの訳[1]として「再帰」が使われることがある。
  数学的帰納法との原理的な共通性から、recursionの訳として数学では「帰納」を使うことがある。
  ―再帰呼出し
   再帰呼出し(さいきよびだし、英: recursive call)は、プログラミング技法の一つである。
  手続きや関数といった概念をもつプログラミング言語では、ある手続き中で再びその手続き自身を呼び出すことを認める場合が多い。
  これを再帰呼出しといい、階乗計算やフィボナッチ数列のように、本来再帰的な構造をもつアルゴリズム(再帰的アルゴリズム)を記述するのに適している。
  再帰呼出しが許されない言語もある(戻りアドレスを固定の場所に記録しているなど。FORTRANなどではそういう実装もあった)。
  また、引数やローカル変数が無いため効果的に再帰呼出しを利用できない言語(クラシックなBASIC等)では、配列を利用してスタックを実装し、それを使って再帰的な処理を実現する。
  複数の手続き/関数が互いに相手を呼ぶ場合も、広い意味での再帰呼出し(相互再帰)である。

39 テキストボックスと局所変数
 フォーム定義状態で、テキストボックスの[ソース]属性に局所変数を設定した場合、
設定した局所変数が[フォーム定義の変数管理]で宣言されていない場合には、[整合性チェック]でエラー表示されます。
これは、すでに[名札 メイン]で当該の局所変数を宣言している場合でも同じです。

 テキストボックスのエディタを使って値を編集するのであれば、[フォーム定義の変数管理]で変数を宣言することが望ましいです。
しかし、編集をしない単なる表示だけのテキストボックスの場合には省略しても差し支えありません。

 このような場合には、テキストボックスの[ソース]属性を次のように設定します。
 
 変更前 ソース(S): &変数名       例:&mString
 
 変更後 ソース(S): #変数( "変数名" )  例:#変数( "mString" )
 
#変数()関数の中には、アンパサンド(&)記号を付けない変数名を二重引用符(" )で囲んだものを記述します。(注)

 このように#変数()関数を使うと、[整合性チェック]でエラー表示されなくなります。
なぜならば、#変数()関数の引数に指定した変数名が存在しない場合には、未定義値が返るからです。
このように、未定義値を返すので決してエラーにはならないという仕掛けです。

(注)リテラルな文字列の代わりに、文字列型の局所変数を用いることも出来ますが、
   その場合でも変数値の内容にはアンパサンド(&)記号を付けない変数名を代入します。
   当然ですが、変数値の内容に二重引用符(" )も含めません。


 Fig.30 整合性チェック


 fig31 ソース属性に#変数関数を使用する

40 [トレース出力]ウィンドウと[トレース出力]コマンド
 [トレース出力]ウィンドウは、桐の初期値で使わない設定になっているので使った経験がない人が多いでしょう。
しかも、[トレース出力]ウィンドウに出力された内容が読み難くいために、利用するのを諦めた人も多いかもしれません。

 【引用】桐10s ヘルプ  トレース出力ウィンドウ([表示]メニュー)
  ・この機能は、環境設定の[トレース出力ウィンドウを使用する]をONにしている場合のみ使用できます。
   [トレース出力ウィンドウを使用する]をONにするには、[ツール]メニューの[環境設定]を選び、[一括]タブの[高度な設定]ボタンをクリックします。
   この設定を有効にするには、桐を再起動する必要があります。
  ・[トレース出力]ウィンドウに表示する項目は、[表示]メニューの[トレース出力ウィンドウの設定]で設定できます。
  ・[トレース出力]ウィンドウは、桐ウィンドウの枠にドッキングしたり、桐ウィンドウの枠から切り離し、フローティング表示することができます。
  ・[トレース出力]ウィンドウをフローティング表示するには、[トレース出力]ウィンドウの枠をドラッグし、桐ウィンドウの枠の外側または内側にドロップします。
   [トレース出力]ウィンドウの枠をダブルクリックすると、ドッキングする前の場所にフローティング表示されます。
  ・[トレース出力]ウィンドウを桐ウィンドウの枠にドッキングするには、[トレース出力]ウィンドウのタイトルバーまたは枠をドラッグし、桐ウィンドウの上下左右いずれかの枠にドロップします。
   [トレース出力]ウィンドウのタイトルバーをダブルクリックすると、フローティング表示する前の位置にドッキングされます。
  ・ドッキングしている[トレース出力]ウィンドウのドッキング位置を変更する場合は、[トレース出力]ウィンドウの枠をドラッグし、桐ウィンドウの上下左右のいずれかの枠にドロップします。
  ・[トレース出力]ウィンドウに表示されているテキストを選択して、クリップボードに複写することができます。
   [トレース出力]ウィンドウで右メニューを表示して、[すべて選択]を選んだ後、右メニューで[コピー]を選んでください。


 しかし、[トレース出力]ウィンドウこそが、[フォーム+イベント処理]でアプリケーションを作る場合の最強ツールなんです。
メニューバーの[表示]メニュー→[トレースウィンドウの設定]を選ぶと、[トレース出力内容の選択]ダイアログボックスが現れます。

 初めてこのダイアログを見た人は、非常に多くのチェックボックスがあるので驚いたことでしょう。
しかし、たったの2つ、または1つのチェックボックスだけが重要で、他のチェックボックスはあまり役に立ちません。

 それは、[コマンド実行状況をトレースする]の次の2つのチェックボックスです。
  □ 手続き実行開始,手続き実行終了
  □ トレース出力コマンド

 しかし、最も重要なのは次のチェックボックスです。
  □ トレース出力コマンド

 トレース出力内容の選択
  │
  ├□ 表・結合表・外部DBのアクセス状況をトレースする
  │  │
  │  └ 省略
  │
  ├■ コマンド実行状況をトレースする
  │  │
  │  ├□ 一括処理,イベント処理のオープン,クローズ
  │  │
  │  ├□ ブレークポイント行実行
  │  │
  │  ├■
手続き実行開始,手続き実行終了
  │  │
  │  ├□ コマンドボタンからの手続き実行
  │  │
  │  └■
トレース出力コマンド
  │
  └□ イベント発生状況をトレース出力する
     │
     └ 省略


 fig32 [トレース出力]ウィンドウの設定


40.1 手続き実行開始,手続き実行終了
 [手続き実行開始,手続き実行終了]チェックボックスがオンの場合には、
 ・イベントプロシージャ(イベントハンドラ)
 ・一般プロシージャ(一般手続き)
の開始と終了が[トレース出力]ウィンドウに出力されます。

 なお、一般プロシージャには、コマンドボタンから実行した一般プロシージャも含まれますので、
[コマンドボタンからの手続き実行]チェックボックスをオンにする必要はありません。

 以下の例は桐10sのメイン&サブフォームのサンプル(メインサブフォーム.wfx+サブフォーム.wfx)のトレース出力結果です。

 ■出力結果の例

 一括実行:メイン処理を実行開始しました
 一括実行:メイン処理を実行終了しました
 一括実行:メイン処理を実行開始しました
 一括実行:メイン処理を実行終了しました
 一括実行:手続き"フォーム::フォーム開始(1)"を実行開始しました
 一括実行:手続きを実行終了しました
 一括実行:手続き"フォーム::フォーム開始(2)"を実行開始しました
 一括実行:手続きを実行終了しました

 ↑上を見るとメインフォームの[名札 メイン]とサブフォームの[名札 メイン]が交互に実行されていることが分かります。
ただし、メイン&サブフォームのように複数のフォームを開く場合には、どのフォームのプロシージャであるか判別し難い欠点があります。

40.2 [トレース出力]コマンド
 [トレース出力]コマンドの書き方は次の通りです。

 (記述例)
 トレース出力 _&変数名                 ※変数名の前に下線( _ )を付けると、変数名も一緒に表示します。
 トレース出力 _&変数名1, " ", _&変数名2

 トレース出力 "&変数名 = " + &変数名
 トレース出力 "&変数名 = " + #str( &変数名 )      ※文字列と連結する場合には、#str で文字列に変換する

 トレース出力 "if ( 1 > 0 ) … " + #str( ( 1 > 0 ) )  ※ "if ( 条件式 ) … " + #str( ( 条件式 ) ) の形式

 トレース出力 &traceMsg + "を実行開始しました"
 トレース出力 &traceMsg + "を実行終了しました"

 【引用】桐10s ヘルプ ― トレース出力
  ・トレース出力ウィンドウに<計算式>の結果を文字列に変換して出力します。
  ・このコマンドは、イベントハンドラのデバッグ用として使用します。
  ・トレースウィンドウを使用するには、あらかじめ環境設定の[一括]タブを選択し、[高度な設定]ダイアログの[トレース出力ウィンドウを使用する(再起動時に有効)]のチェックをONにしておかなければいけません。
  ・トレース出力ウィンドウを表示していない場合または[トレース出力]を ON にしていない場合は、なにもしません。


 ―[手続き実行開始]と[手続き実行終了]をトレースする

 [トレース出力]コマンドをプロシージャ([名札 メイン]を含む)に記述すると、
[トレース出力]コマンドだけで[手続き実行開始]と[手続き実行終了]をトレースすることが可能になります。

 (例)

  **メインサブフォーム.kex
  名札 メイン
   変数宣言 局所,文字列{ &traceMsg }
   変数宣言 局所,整数 { &traceON }
   &traceMsg = "名札 メイン  メインサブフォーム.kex"
   &traceON = 1
   条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

   :

   条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
  *

  手続き定義開始 フォーム::フォーム開始(長整数 &表番号)
   変数宣言 自動,文字列{ &traceMsg }
   変数宣言 自動,整数 { &traceON }
   &traceMsg = "フォーム::フォーム開始  メインサブフォーム.kex"
   &traceON = 1
   条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

   :

   条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
  手続き定義終了


  **サブフォーム.kex
  名札 メイン
   変数宣言 局所,文字列{ &traceMsg }
   変数宣言 局所,整数 { &traceON }
   &traceMsg = "名札 メイン  サブフォーム.kex"
   &traceON = 1
   条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

   :

   条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
  *

  手続き定義開始 フォーム::フォーム開始(長整数 &表番号)
   変数宣言 自動,文字列{ &traceMsg }
   変数宣言 自動,整数 { &traceON }
   &traceMsg = "フォーム::フォーム開始  サブフォーム.kex"
   &traceON = 1
   条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

   :

   条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
  手続き定義終了

 ■トレース出力結果の例

    :名札 メイン  メインサブフォーム.kexを実行開始しました
    :名札 メイン  メインサブフォーム.kexを実行終了しました
    :名札 メイン  サブフォーム.kexを実行開始しました
    :名札 メイン  サブフォーム.kexを実行終了しました
    :フォーム::フォーム開始  メインサブフォーム.kexを実行開始しました
    :フォーム::フォーム開始  メインサブフォーム.kexを実行終了しました
    :フォーム::フォーム開始  サブフォーム.kexを実行開始しました
    :フォーム::フォーム開始  サブフォーム.kexを実行終了しました

 ―変数の値をトレースする
  **メインサブフォーム.kex
  手続き定義開始 フォーム::フォーム開始(長整数 &表番号)
   変数宣言 自動,文字列{ &traceMsg }
   変数宣言 自動,整数 { &traceON }
   &traceMsg = "フォーム::フォーム開始 ― メインサブフォーム.kex"
   &traceON = 1
   条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

   &hMain = &表番号

   トレース出力 _&hMain

   トレース出力 "&hMain = " + #str( &hMain)


   条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
  手続き定義終了

 ■トレース出力結果の例

    :フォーム::フォーム開始 ― メインサブフォーム.kexを実行開始しました
    :&hMain : 2
    :&hMain = 2
    :フォーム::フォーム開始 ― メインサブフォーム.kexを実行終了しました

 ―条件式をトレースする
  **メインサブフォーム.kex
  手続き定義開始 フォーム::行削除開始(長整数 &削除モード,参照 長整数 &処理継続)
   変数宣言 自動,文字列{ &traceMsg }
   変数宣言 自動,整数 { &traceON }
   &traceMsg = "フォーム::行削除開始 ― メインサブフォーム.kex"
   &traceON = 1
   条件 ( &traceON ) トレース出力 &traceMsg + "を実行開始しました"

   変数宣言 整数{ &OK }

   メッセージボックス &SysT, "この伝票を削除してよろしいですか?  ", \
    アイコン = ?, ボタン指定 = 5, &OK

   条件 ( &traceON ) トレース出力 " If ( &OK = 6 ) … " + #str( ( &OK = 6 ) )
   If ( &OK = 6 )
    :
   Else
    :
   End

   条件 ( &traceON ) トレース出力 &traceMsg + "を実行終了しました"
  手続き定義終了

 ■トレース出力結果の例

    :フォーム::行削除開始 ― メインサブフォーム.kexを実行開始しました
    : If ( &OK = 6 ) … 0
    :フォーム::行削除開始 ― メインサブフォーム.kexを実行終了しました

40.3 整形ユーティリティでトレース出力結果を整形する
 拙作:整形ユーティリティを利用するとトレース出力結果を非常に読み易く整形できます。
整形結果は、テキストファイルに出力したり、印字したりできます。

 ■整形前

    :名札 メイン ― メインサブフォーム.kexを実行開始しました
    :名札 メイン ― メインサブフォーム.kexを実行終了しました
    :名札 メイン ― サブフォーム.kexを実行開始しました
    :名札 メイン ― サブフォーム.kexを実行終了しました
    :フォーム::フォーム開始 ― メインサブフォーム.kexを実行開始しました
    :&hMain : 2
    :&hMain = 2
    :フォーム::フォーム開始 ― メインサブフォーム.kexを実行終了しました
    :フォーム::フォーム開始 ― サブフォーム.kexを実行開始しました
    :フォーム::フォーム開始 ― サブフォーム.kexを実行終了しました
    :フォーム::行削除開始 ― メインサブフォーム.kexを実行開始しました
    : If ( &OK = 6 ) … 0
    :フォーム::行削除開始 ― メインサブフォーム.kexを実行終了しました

 ■整形後

 ┌when :名札 メイン ― メインサブフォーム.kexを実行開始しました
 └end

 ┌when :名札 メイン ― サブフォーム.kexを実行開始しました
 └end

 ┌when :フォーム::フォーム開始 ― メインサブフォーム.kexを実行開始しました
 │
 │ :&hMain : 2
 │ :&hMain = 2
 │
 └end

 ┌when :フォーム::フォーム開始 ― サブフォーム.kexを実行開始しました
 └end

 ┌when :フォーム::行削除開始 ― メインサブフォーム.kexを実行開始しました
 │
 │ : If ( &OK = 6 ) … 0
 │
 └end

 拙作:整形ユーティリティ(無料ソフト)は、次のwebページからダウンロード出来ます。
  ・【多遊】さんのHPのダウンロードコーナー
  ・拙作HP 桐の釣魚大全のトップ > ワークショップ > ダウンロード

 【引用】― ヘルプ_utx_list3.txt より
  4.「トレース出力整形」で整形する
  次の手順で桐の[トレース出力ウィンドウ]に出力された内容を整形できます。
  <手順>
  1)桐の[トレース出力ウィンドウ]でトレースします。
  2)[トレース出力ウィンドウ]を右クリックで[すべて選択]を選びます。
  3)[トレース出力ウィンドウ]を右クリックで[コピー]を選びます。
  4)「トレース出力整形」の[メモ帳を開く]ボタンを実行します。
  5)メモ帳が開いたら、クリップボードの内容を貼り付けます。
  6)メモ帳を保存終了してください。
   ※拡張子( .txt )の関連付けによってはWindowsの[メモ帳]以外のアプリケーションが起動することがあります。
  7)最後に、「トレース出力整形」の[トレース整形]ボタンを実行してください。これで出来あがりです。
   ※メモ帳の内容をクリアした場合には、60秒以内ならば自動的に[トレース整形]ボタンを実行します。





トップページに戻る
桐の釣魚大全のトップ > フォームアプリケーション教書 第2部