ロゴ(青) 擬似からの脱却 ロゴ(緑)

    『擬似からの脱却』記事が公開から20周年を迎えます。
      (この20年で 「当たり前のテクニック」 として浸透してくれていると嬉しいです)


    【コントロール配列】 は多数のコントロールを扱うフォームでは非常に便利な機能です。しかし、「VBにあってVBAにはない」
    という、VBAユーザーにとって非常に残念で羨ましい機能でもあります。この記事では、本来、VBAが持っていない 「コント
    ロール配列」 機能をイベント処理を含めて 『VB並みに扱える』 ようになる手法について解説しています。

      小難しい解説はすっ飛ばして、とにかく今直ぐに使いたい、という方 ・・・・
    汎用クラス( clsBpca ) を ダウンロード して サンプルコード( $11 ) を参考に チャレンジ してください。
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    某QA掲示板の過去ログに、「擬似からの脱却手法(clsBpca ) の存在意義に対する疑問」 というような会話が
    ありましたので、それへの答えを このページの末尾 に掲載しました。 ( 2022/1/22 追記 )


  ------------------------------------------------------------------------------------------------------------

  【 擬似からの脱却 】  [ Breakthrough in the Pseudo-Control Arrays ]  

   
  [ http://addinbox.sakura.ne.jp/Breakthrough_P-Ctrl_Arrays_Eng.htm

「擬似からの脱却」と銘打っていても、そもそも
        「擬似」とは何を指しているの?
と聞かれるでしょうね。何なのかと言えば、それは、
        VBAで使われているコーディング手法の「擬似コントロール配列
の事です。すると次には
        じゃあ「擬似コントロール配列」って何?
となりますので、先ずは「そこから」解説を始めます。
§1 VB (Visual Basic) と VBA (Visual Basic for Application)
§2 Controls コレクション の利用 §7 クラスからフォーム内の情報を操作
§3 コレクション オブジェクトの利用 §8 擬似から先ず1歩踏み出す
§4 クラス モジュール って、何? §9 擬似の足枷
§5 クラス モジュールの利用 §10 擬似からの脱却
§6 「擬似コントロール配列」で残る問題点 §11 その他のサンプルコード
§12 Enter / Exit イベントの実装
( 初出 : §1〜5 [ 2004/5/17 ] , §6〜11 [ 2004/6/22 ] , §12 [2014/8/11]          clsBpca の 軌跡 )
( 英訳 初出 : [ 2014/7/24 ] )      【 旧 dion サーバー時の Internet Archive
   
( News )
    汎用クラス Ver 2.0  ( 2014/8/11 リリース )
    Enter , Exit , BeforeUpdate , AfterUpdate がサポートされました(仕組みは§12 を参照)。 

    ワークシート上のコントロールを通り扱う場合は、コントロールの指定方法が
         ワークシート名.OleObjects ( コントロール名 ).Object
      というスタイルになります(clsBpca 利用例 参照)


( 参 考 )
この「擬似からの脱却」以前では、『VBAでのコントロール配列』に関する情報といえば、moug
    「スキルアップ講座 : クラスモジュールを使った究極のVBAプログラミング
という記事(全7頁、内2頁でコントロール配列を解説)が唯一でした。残念ながら、moug の再編
に伴って、現在この記事は削除(2008年頃迄ありました)されていますが、Internet Archive
拾う事ができます(上記リンクはInternet Archiveによるものです) 。内容としては、ここの§1〜5
に相当します。

[ clsBpca の 軌跡 ] [ 前頁 , 次頁 , §1 , §2 , §3 , §4 , §5 , §6 , §7 , §8 , §9 , §10 , §11 , §12 ]
[ 汎用クラス , トグルラベル クラス , Focus クラス , クラス アドイン , カレンダークラス ] [ 質問はメール]

  ====================================================================
  §1  VB (Visual Basic) と VBA (Visual Basic for Application)
  ====================================================================

  フォームで同じ使い方のコントロールを複数配置する場合、VBでは当たり前のようにコント
ロール配列」という機能が利用できます。
    [ 例 ]
        曜日ボタン(日曜〜土曜の7つ)を配置して、ボタンをクリックした時に、その曜日を
        MsgBoxで表示してボタンカラーを変更する
という例を題材に考えてみます。

  先ず[cmdWeek ]という名前で CommandButton を1つ配置してから、その CommandButton
コピー&貼り付けすると、
        既に同じ名前のコントロール'cmdWeek' があります。
        コントロール配列にしますか?

というメッセージが表示されます。これに OK で応答した後、プロパティウィンドウを見ると、最初
のボタンは「cmdWeek (0)」に、今貼り付けたボタンは「cmdWeek (1)」という名前になっています。

これで”配列化”されたという事が判ります。同じ様に貼り付けを繰り返し、全部で7つのボタンを
用意します(キャプションは各々"日曜","月曜"〜"土曜"に変えます)。

  配置したボタン(7つの内のどれでも)をダブルクリックすると、コードウィンドウ内に
 
 Private Sub cmdWeek_Click(Index As Integer)
 End Sub
 
というイベントプロシジャーのコードが挿入されます。コントロール配列にしていない場合は、
 
 Private Sub cmdWeek_Click()
 End Sub
 
と、引数が入りません。つまり、実行時に、この7つのボタンのどれをクリックしても、呼び出され
るイベントプロシジャーは「cmdWeek_Click 」という『ひとつだけ』という事です。

  その時に
        「何番目のボタンか?」という番号(0〜) が [Index] という引数
で渡されます。このイベントプロシジャー内でボタンにアクセスする場合、このIndex値を使って
cmdWeek ( Index ) 』という風に記述すれば、クリックしたボタンに対してアクセスできます。
 
 -- 実際のプログラム例 --
 Private Sub cmdWeek_Click(Index As Integer)
 Dim vntWeekName As Variant
   vntWeekName = Array("", "", "", "", "", "", "")

   MsgBox vntWeekName(Index) & "曜日ボタンがクリックされました(" & Index & ")"
   If (cmdWeek(Index).BackColor = vbButtonFace) Then
     cmdWeek(Index).BackColor = vbRed
   Else
     cmdWeek(Index).BackColor = vbButtonFace
   End If
 End Sub
 
この『ひとつ』のイベントプロシジャーだけで【7つの曜日ボタン全て】をカバーしており、
    日曜ボタンをClick →「日曜ボタンがクリックされました ( 0 ) 」
    金曜ボタンをClick →「金曜ボタンがクリックされました ( 5 ) 」
と、どのボタンをクリックしても、同じ様に表示され、またクリックの度にボタンカラーが変わると
いう動きをしてくれます。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
では、VBAの場合は、どうでしょうか?

  VBAでは、元々VBのような「コントロール配列」という機能はありませんので、
        [ cmdWeek ]という名前で CommandButton を1つ配置してから、
        その CommandButton をコピー&貼り付けする

としても、貼り付けた2番目のボタンが[CommandButton1]という既定の名前になるだけです(その
まま、順次貼り付けていけば[CommandButton2] [CommandButton3]‥‥‥)。つまり、VBAでは
同じ名前での定義は出来ない】という訳です。仕方ないので、各々の名前を
        [cmdSun] [cmdMon] [cmdTue] [cmdWed] [cmdThu] [cmdFri] [cmdSat]
という風に変更します。当然、名前が違うのですからイベントプロシジャーも各々独立した別個の
ものとなります。
 
 Private Sub cmdSun_Click()
 End Sub

 Private Sub cmdMon_Click()
 End Sub
    :
    :
 Private Sub cmdSat_Click()
 End Sub
 
したがって、VBAで
    [ 例 ]
        曜日ボタン(日曜〜土曜の7つ)を配置して、ボタンをクリックした時に、その曜日を
        MsgBox で表示して ボタンカラーを変更する

という処理を行なうには、VBで書いたイベントプロシジャーの中身(と同等なコード)を、日〜土の
7つのイベントプロシジャーに【同じ様に】記述してやらなければいけない、という事です。
 
 Private Sub cmdSun_Click()
   MsgBox "日曜日ボタンがクリックされました"
   If (cmdSun.BackColor = vbButtonFace) Then
     cmdSun.BackColor = vbRed
   Else
     cmdSun.BackColor = vbButtonFace
   End If
 End Sub

 Private Sub cmdMon_Click()
   MsgBox "月曜日ボタンがクリックされました"
   If (cmdMon.BackColor = vbButtonFace) Then
     cmdMon.BackColor = vbRed
   Else
     cmdMon.BackColor = vbButtonFace
   End If
 End Sub

 --- 以下省略 ---
 

これでは、コーディング量が増えるばかりで、全く効率的ではありませんね。  ┐('〜`;)┌

  ====================================================================
  次節 : §2  Controls コレクション の利用
  ====================================================================

[ 前頁 , 次頁 , §1 , §2 , §3 , §4 , §5 , §6 , §7 , §8 , §9 , §10 , §11 , §12 ]
[ 汎用クラス , トグルラベル クラス , Focus クラス , クラス アドイン , カレンダークラス ] [ 質問はメール]


[ Home へ戻る ]

  ( この場所へのリンク )
      ( 2022/1/22 追記  ,  2022/6/26 一部加筆修正 , 2024/6/12 追記 )
    某QA掲示板 (既にかなりの過去ログではありますが …)で
          ・ 『  脱却 』 という言葉遣いが何か偉ぶってる?
          ・ そもそも、『 擬似からの脱却 』 手法を利用する事に意味が有るの?
          ・ clsBpca のインターフェースで、コントロールを登録するのに Add メソッド という方式を採用
            している意味が分からない。何故、迂遠な事をしてるのか?
            素直に [ 〜.Item ( Index ) = コントロール ] にすれば良いのに
    というような会話(議論)がされていたのを見つけてしまいました。それに答えていこうかと思います。
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    〜 『 脱却 』 という言葉遣いが何か偉ぶってる? 〜
    「擬似コントロール配列」 止まりで 「VB の コントロール配列」 との越せない高い壁を、当時未だ
    誰もやっていない方法を見つけ出して、VBAでも単体コントロールと同じレベルの扱い易さで
    コントロール配列のイベント処理を構築できたという 「難題を克服した、壁をぶち破ったぞ」 という
    感情を表現して 『 脱却Breakthrough 』 という言葉を敢えて選んでいます

    日本におけるVBAの先駆者であり、擬似コントロール配列というクラス利用法を世に広めた
    元 moug主催の大村あつしさんでも 「擬似 止まり」 でした。 なので、自信を持って「壁を破った」
    と自負していますし、『ブレークスルー』 と名乗れる内容の記事であると思っています。

    当時も、その後も暫くの間、散々ネットを海外(英語圏)も含めて探し回りましたけど、このような
    手法の解説は見当たりませんでした(公開していないだけで、何処かの誰かはとっくに知ってて
    使っていたのかもしれませんが…)
    ( clsBpca の軌跡 )

    〜 『 擬似からの脱却 』 手法 ( clsBpca モジュール ) を利用する意義? 〜
    この手法の目的は、最初から
          VB と同じように コントロール配列の 【 イベント処理を UserForm モジュール内に記述 】 できるようにする 
    という一点だけです。それだけです。

    その為の複雑な処理を ブラックボックス化して、ユーザーサイドでは難しい事は考えずに通常の単体コントロール
    と同じように、インテリセンス付きで、全く意識することなく簡単に コントロール配列を使って フォーム の プログラ
    ミング を サポート できるようにしたのが、汎用モジュール ( clsBpca ) です。

    「イベント処理を UserForm モジュール内に記述できるようにする 」 以上の機能を持たせる場合は、これを参考に
    新たに組み直せば良いと思います(例 : トグルラベルクラス )。
    「イベント処理を UserFormモジュール内に記述 」 だけで良いならば、元にして作り直す必要はありません。
    色々な機能が付いていて複雑だから シンプル にしたいというのかもしれませんが、不要ならばその機能を使わな
    ければ良いだけなので。

    〜 何故、 Add メソッド? 〜
    何故と言われても、それが一番自然であり、且つ、安全な インターフェース だったからです。

    不特定多数の人が利用する事が前提の ツール ですので、「どのような使われ方をしても正しく動作する/正しくエラー
    処理される」 というのが大事です。その事を検討した上で決めた インターフェース です。

    擬似からの脱却では、
        @ 対象コントロールを最初に全て登録 ( Add メソッド : クラス内部の Collection に Add )
            Collection に Add するステップなので clsBpca のインターフェース でも Add メソッド としています。
        A その後で一括して 「子クラス展開 & 動作条件の設定」 を行なう ( Rgst メソッド )
    という流れで コントロール の登録処理を行ないます。

    この手順にすることによって、擬似からの脱却手法の肝である 「子クラス展開」 を行なう際に (および、動作条件の
    設定についても)
        B この時点で対象 コントロール が決まっている (個数が固定されている)
        C その後で対象 コントロール が増えることが無い
        D コントロール番号 ( Index ) が連続して振られており、歯抜けが無い
    という メリット があります。この前提が得られるだけで、クラス 内での登録処理の ロジック がかなり楽になります。

    clsBpca では 「発生イベント の指定/制限」 という動作条件があり、全ての子クラス 内に等しく登録しておく必要が
    あるのですが、上記の保証があるおかげで無駄な チェックロジック も必要なく プログラミング できています。

    逆に、これらの保証が得られない インターフェース の場合、安全な ツール とするには、様々な 「もしも」 に漏れ
    なく対応しておかなければいけません。

    [ 〜.Item ( Index ) = コントロール ] という スタイル で コントロール の登録を行なう場合、
        a) Index を 1 から連番で指定して貰える保証がない
        b) 番号が歯抜けになったり ( 1, 3, 7, … )、登録順で番号が前後 ( 1, 5, 2, 7, 4, … ) したりする可能性もある
        c) 既に登録済みの番号 ( Index ) に重複して コントロール を登録してしまう可能性もある
        d) 「後で追加」 という可能性もある
    というような、「そんな事はしないだろう」 という 『もしも』 にも対処できてなければなりません。

    自分だけで使うものならば、どのように設計しようと、曖昧な部分が有ろうと、変な使い方では異常終了しようとも、
    設計者イコール唯一の使用者であれば、正しい使い方を熟知しているわけですから構わないでしょう。しかし、
    不特定多数の人に安全に利用してもらう以上は、このような事も考慮する必要があります。それだけ、余計な
    チェックロジック が必要になります。

    以上のような検討の結果、Add メソッドでコントロール を登録していく インターフェース が ベスト であろうという
    結論になりました。

    ちなみに、clsBpca では 『後で追加』 を禁止していますが、【 動的に明細行を増やす 】 という要求仕様は普通に
    あり得ます。このような ケース では、増やす際に 「一旦全て解除して、増えた コントロール も加えて登録し直す」
    という手順を踏むことによって対応できます。サンプルコード がありますので参考にしてください。

    ---- ( 2024/6/12 追記 ) ----
    尚、§5〜§9 節において、コントロール の登録を Item プロパティ で行っている のは、クラスモジュール
    の仕組みと使い方を説明するのが主眼で、その為に簡易な手順で済ませている事と、プロパティ (  Let / Get ) を
     説明する サンプル としても丁度良かった為です。不特定多数の利用を前提とする ツール を作製する場合には、
    上述のような配慮が必要になります。
 


ロゴ(ゴールド) ロゴ(ゴールド)

角田 桂一 Mail:addinbox@h4.dion.ne.jp CopyRight(C) 2004 Allrights Reserved.