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

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

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

  ====================================================================
  §10  擬似からの脱却
  ====================================================================

2005/3/11 解説文・クラスソースにおいて、オブジェクト定義時での[New]指定 を止めて、Initialize 時に
                インスタンス生成(Set ステートメント)するように修正しました。
2007/3/18 [clsBpcaCmd モジュール] 内に Terminate イベントを追加(汎用クラス等では当初より盛り込んであります)。
2014/7/22 [clsBpcaCmd モジュール] 内の Item プロパティ で、Index 引数のエラーチェック(>0)が抜けていたのを修正しました。
2014/8/11  クラスモジュールで Enter 等のイベントが利用できない理由の解説を追加しました。
               汎用クラス ( clsBpca ) Ver 2.0 で、Enter 等のイベントが利用可能になりました
2020/5/1  本ページ内に記載してある clsBpcaCmd クラス に ItemCtrl プロパティ を追加しました( Name プロパティ 取得用)


(前節より‥‥‥)
      [ 擬似の足枷 ]
      擬似コントロール【配列】である以上、[RaiseEvent:WithEvents]のセットを
      使った非常に便利な機能(カスタムイベント)とは 『完璧に縁が無い』


  ここからが、いよいよ「擬似からの脱却」の本編中の本編です。

  先ず、足枷となっている問題を整理してみると
        ・送り手であるクラス側では「Event宣言 および RaiseEventステートメントの実行」に
          何ら問題は無い
        ・受け手であるフォーム側で、配列宣言とWithEvents宣言が共存できないので
          カスタムイベントが使えない
という事になります。逆に言えば、
        フォーム側でクラスオブジェクト定義に配列宣言が無ければ問題なし
という事ですね。でも、配列宣言しなければ、そもそも「コントロールの配列化」にはなりません
から、このままでは矛盾する考えです。

  ここが「擬似からの脱却」手法(略してBpca手法 (命名 : σ(^_^))のキーポイントですが、
一言で言えば
        『イベント発生』 と 『配列化』 を役割分担させましょう
という事になります。    φ(..) メモ メモ…

  どう役割分担させるかと言うと
 
  (1) 先ず、クラスを2重に使います

  (2) 1段目のクラスでは
      (a) UserFormで定義(利用)するクラス
            UserFormでの変数定義では配列宣言しない
                → WithEvents宣言が書ける  → カスタムイベントが受け取れる
      (b) UserForm上の配列化するコントロールは、1段目クラス内に用意するコレクション
           に登録する(Add メソッド)
      (c) コレクションに登録された数に応じて、1段目のクラス内で、2段目のクラスオブジェ
           クトを動的配列として作り出す
      (d) 動的に作ったクラス配列に、コレクション内のコントロールをひとつずつ割り当てる

  (3) 2段目のクラスでは
      (a) 1段目のクラスで、配列定義(動的配列)により作成される
      (b) 2段目のクラスでは、コントロールひとつにつき、クラスがひとつですから、前節まで
          と同様に、割り当てられたコントロールに対し、WithEvents宣言によりイベントを
          取得できる
 
という風にします。

  ただ、このままでは結局のところ、2段目のイベント発生を、1段目でカスタムイベントとして受け
取る事はできません(配列宣言していますから)。

  では、どのようにしてイベントを引き継ぐかといえば、7節で解説した方法を使います。7節では、
        受け手のUserFormモジュール内にサブプロシジャーを用意して、クラス側から
        [ Call MyCaller.xxxxx ( MyIndex ) ] という風に呼び出して貰う
という内容でした(MyCaller は、Object型のUserForm参照変数)。

  クラスから、別のクラス内にあるサブルーチンを呼び出す場合も同じように記述する事で呼び出せ
ます。ただし、クラスで [ Public Sub ] と書けば、それはサブプロシジャーではなく 『メソッド』と呼
ばれるものになりますが‥‥‥。
  メソッドは、クラスオブジェクト変数の後にピリオドを挟んで記述するものですから、どこから呼ばれ
ていようが、その「どこから呼んだか」を示すクラスオブジェクト参照(親)を引き継いでさえおけば、
コーディングは
        クラスオブジェクト変数 . xxxxx ( MyIndex )     ‥‥  xxxxx は メソッド名
という風に出来ます(Call ステートメントではなく、メソッドの実行)。

纏めると、

  コントロールのイベント発生
    ⇒ 2段目の WithEvents により、2段目でイベントを取得
        ⇒ 2段目内から、1段目のメソッドを呼び出して
            イベント発生を1段目に通知する
            ⇒ 呼ばれた1段目のメソッドから [ RaiseEvent ]を
                実行してカスタムイベントを発生
                ⇒ UserFormの WithEvents により、
                    1段目のカスタムイベントを取得

という流れになります。    φ( ̄▽ ̄)o

判り易く図示したものを用意しましたので、
左図または下記リンクをクリックしてください。
        【 clsBpca 概念図 】 


  この方法では、コントロールのコレクションを1段目のクラスに備えていますので、ここから8節
書いたように [ Item ]プロパティに番号を渡してコレクション内からコントロールを受け取る事が
可能です(UserFormモジュール内に、コントロールの配列/コレクションは不要)。

  曜日ボタンの例題を「擬似からの脱却」手法でコーディングすると下記のようになります。
===== UserForm1 モジュール =========================

  Private WithEvents WeekBtn As clsBpcaCmd

  Private Sub UserForm_Initialize()
      Set WeekBtn = New clsBpcaCmd    ' インスタンスの生成
      With WeekBtn
          .Add cmdSun      ' コントロールをクラス(親)内に登録していく
          .Add cmdMon
          .Add cmdTue
          .Add cmdWed
          .Add cmdThu
          .Add cmdFri
          .Add cmdSat
          .Rgst            ' クラス(親)に登録したコントロールでクラス配列(子)を作成させる
      End With
  End Sub

  Private Sub UserForm_Terminate()
      WeekBtn.Clear    ' Clear メソッドは最後(Terminate で)に必ず実行する事
      Set WeekBtn = Nothing
  End Sub

  Private Sub WeekBtn_Click(ByVal Index As Integer)
      Dim vntWeekName As Variant
      Dim i As Integer
      vntWeekName = Array("", "", "", "", "", "", "", "")

      MsgBox vntWeekName(Index) & "曜日ボタンがクリックされました(" & Index & ")"
      If (WeekBtn.Item(Index).BackColor = vbButtonFace) Then
          WeekBtn.Item(Index).BackColor = vbRed

          For i = 1 To WeekBtn.Count    ' クリックしたボタン以外を元の色に戻す
            If (i <> Index) Then
              WeekBtn.Item(i).BackColor = vbButtonFace
            End If
          Next i
      End If
  End Sub
 
            Add メソッド で コントロールの登録をするのは何故?
                 Item プロパティ で良いじゃないか?という問いがあったので、それへの回答


どうでしょうか。UserFormモジュールのコーディングは完全にVB並になりましたね。

違っているのは、
 
 VB6     : cmdWeek(Index).BackColor
 Bpca手法 : WeekBtn.Item(Index).BackColor
 
と、間に[ Item ]というプロパティ記述が挟まっているだけです。

また、8節 と比べて、 Item と (Index) を書く順番が変わっていますが、これは (Index) が「配列の添え字」
ではなく、「Itemプロパティの引数」という位置付けに変わった為です。

汎用クラス および アドイン化したクラスでは、[ Item プロパティ] を【既定のプロパティ】として
     定義してありますので、[ .Item ] を省略して
 
 WeekBtn.Item(Index).BackColor    WeekBtn(Index).BackColor
 
      と記述する事が可能です(これで完璧にVBと同じです)。

    ----  「既定のプロパティ」 の定義方法  ----

  下記の赤文字部分を、クラスモジュールのエクスポートファイル上で書き込み、
  インポートで再度取り込みます(赤文字部分はコードウィンドウ上では見えません)。

  [ Export file : clsBpcaCmd.cls ]
  '---( Item property )---------------------------------------------
  Public Property Get Item(ByVal Index As Integer) As MSForms.CommandButton
  Attribute Item.VB_UserMemId = 0
  If (blnRgst = True) And _
      (Index > 0) And (Index <= colCtrl.Count) Then


また、イベントルーチンがUserForm内に戻った事によって、
    UserForm内の他のコントロールやモジュール変数へのアクセスも自由
になります。

  クラスモジュールのコードは下記になります。
===== clsBpcaCmd モジュール(1段目) =================================

  '------[ 発生イベント定義(利用側へ上げる) ]--------------
  Public Event Click (ByVal Index As Integer)

  '------[ コントロール配列定義 ]--------------------------
  Private clsCtrlCh() As clsBpcaCmdCh      'BpcaCmd 子クラス
  Private colCtrl As Collection            '登録コントロール

  Private blnRgst As Boolean      'Rgst 済(True)/未(False)

  Private Sub Class_Initialize()
      Set colCtrl = New Collection     ' インスタンスの生成
  End Sub

  Private Sub Class_Terminate()
      If (blnRgst = True) Or (Not (colCtrl Is Nothing)) Then
          '呼び元(UserForm)での「後始末: Clear メソッド実行」忘れへの対策
          Me.Clear
      End If
  End Sub

  '---( Add メソッド )------------------------------------
  '配列化するコントロールをコレクションに追加

  Public Sub Add (ByVal NewCtrl As MSForms.CommandButton)
      colCtrl.Add NewCtrl
  End Sub

  '---( Rgst メソッド)------------------------------------
  'コレクションに載せたコントロールをクラス登録して配列化

  Public Sub Rgst()
  Dim i As Integer
      If (blnRgst = True) Then
          '実行済み
      ElseIf (colCtrl.Count = 0) Then
          blnRgst = False
      Else
          ReDim clsCtrlCh(1 To colCtrl.Count)
          For i = 1 To colCtrl.Count
              Set clsCtrlCh(i) = New clsBpcaCmdCh    ' インスタンスの生成
              With clsCtrlCh(i)
                  .Item = colCtrl(i)
                  .Index = i
                  .Parent = Me
              End With
          Next i
          blnRgst = True
      End If
  End Sub

  '---( Clear メソッド Classの解放/初期化 )--------------------
  Public Sub Clear()
  Dim i As Integer
      If (blnRgst = True) Then
          For i = 1 To colCtrl.Count
              clsCtrlCh(i).Clear
          Next i
      End If
      Set colCtrl = Nothing
      Erase clsCtrlCh
      blnRgst = False
  End Sub

  '---( Count プロパティ)--------------------------------------
  '登録されているコントロール数を返す

  Public Property Get Count() As Integer
      Count = colCtrl.Count
  End Property

  '---( Item プロパティ)---------------------------------------
  'コントロール配列から、個々のコントロールオブジェクトを返す

  Public Property Get Item(ByVal Index As Integer) As MSForms.CommandButton
      If (blnRgst = True) And _
        (Index > 0) And (Index <= colCtrl.Count) Then
          Set Item = colCtrl(Index)
      Else
          Set Item = Nothing
      End If
  End Property

  '---( ItemCtrl プロパティ)---------------------------------------
  ' Item ( MsForms.CommandButton )ではオブジェクトのNameプロパティを取得できないので、
  ' Nameプロパティを取得可能なControlクラスで返す

  Public Property Get ItemCtrl(ByVal Index As Integer) As MSForms.Control
      If (blnRgst = True) And _
        (Index > 0) And (Index <= colCtrl.Count) Then
          Set ItemCtrl = colCtrl(Index)
      Else
          Set ItemCtrl = Nothing
      End If
  End Property

  '===========================================================
  '===== clsBpcaCmdCh から呼ばれるイベント励起メソッド =========
  '===========================================================

  Public Sub RaiseClick(ByVal Index As Integer)
      RaiseEvent  Click(Index)
  End Sub
 
            Add メソッド で コントロールの登録をするのは何故?
                 Item プロパティ で良いじゃないか?という問いがあったので、それへの回答



===== clsBpcaCmdCh モジュール(2段目) ================================

  '------[ イベントを取得する為のコントロール定義 ]-------------------
  Private WithEvents MyCtrl As MSForms.CommandButton
  Private MyIndex As Integer                'コントロール番号
  Private MyParent As clsBpcaCmd      '親クラスへの参照
  Private blnParent As Boolean            '[Parent]登録の有無

  '---( Clear メソッド)----------------------------------------------
  Public Sub Clear()
      Set MyCtrl = Nothing
      Set MyParent = Nothing
      blnParent = False
      MyIndex = 0
  End Sub

  '---( Item プロパティ)------------------------------------------------
  Public Property Let Item(NewCtrl As MSForms.CommandButton)
      Set MyCtrl = NewCtrl
  End Property

  '---( Index プロパティ)------------------------------------------------
  Public Property Let Index(NewIndex As Integer)
      MyIndex = NewIndex
  End Property

  '---( Parent プロパティ)------------------------------------------------
  Public Property Let Parent(NewParent As clsBpcaCmd)
      blnParent = True
      Set MyParent = NewParent
  End Property

  '===================================================================
  '===== 登録したコントロールのイベントを取得する ======================
  '===================================================================
  'コントロールのイベントを受けたら、そのまま、呼び元の親クラスへ、更にイベントを上げる

  Private Sub MyCtrl_Click()
      If (blnParent = True) Then
          MyParent.RaiseClick MyIndex
      End If
  End Sub
 

  この [ clsBpcaCmd / clsBpcaCmdCh ] クラスは、
        殊、コマンドボタンのクリックイベントに関しては完全に汎用なクラスモジュール
です。今回の曜日ボタンに限らず、他のコマンドボタンの配列化にも、そのまま利用できますし、
ひとつのUserFom上で、複数のコマンドボタン配列を作る事も可能です。
UserFormで
 
 Private WithEvents CmdGrp1 As clsBpcaCmd
 Private WithEvents CmdGrp2 As clsBpcaCmd
            :
            :
 
という風に、クラスオブジェクト定義を複数用意すれば良いだけです。

また、個々のコマンドボタン配列に幾つのコマンドボタンが含まれるかは全くの任意です。
それによって、クラスモジュールに修正が必要となる事はありません。
単に[Add ]メソッドを何回繰り返すかだけです

テキストボックス等の他のコントロールや、クリック以外のイベントもサポートする
        汎用クラス 【 clsBpca 】  (Ver 4.0  2020/9/1)
を用意してありますので、実際には、そちらを利用して下さい。
(Ver 2.0 以降では、下記で問題提起している Enter イベントなども利用可能になっています)

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



(2014/8/11 追記)
実は、最後にもうひとつ問題が残っています(Ver2.0 にて解決済)。それは ・・・・
      VBAのクラスモジュールでは Enter , Exit , BeforeUpdate , AfterUpdate の
      イベント定義ができない。
ということです。これらのイベントはエラーチェックやActiveControl表示 などで非常によく使用
するイベントです。これらのイベントが折角可能になったコントロール配列で利用できないという
のは非常に残念ですね。

何故、クラスモジュールで Enter 等が利用できないかを説明します。
    (a) UserForm モジュールでは、UserFormに配置したコントロール、または MsForms.TextBox
        等で定義したコントロールオブジェクト(WithEvents 付き)に対して、モジュールウィンドウ右
        上の[Declarations] リストから、様々なイベントプロシジャーを展開できます(その中には、
        当然、Enter 等も含まれます)。
    (b) しかし、クラスモジュールでは、MsForms.TextBox等で定義したコントロールオブジェクト
        (WithEvents 付き)に対して、モジュールウィンドウ右上の[Declarations] リストに Enter 等
        の項目がありません。
    (c) そもそも、MsForms.TextBox 等には Enter, Exit, BeforeUpdate, AfterUpdate の定義が
        ありません。(これは、オブジェクトブラウザで確認できます。)
    (d) Enter, Exit, BeforeUpdate, AfterUpdate は MsForms.Control というクラスで定義されて
        います。(これもオブジェクトブラウザで確認できます)
    (e) UserFormモジュールでは、VBAが裏で MsForms.TextBox 等とMsForms.Controlを繋い
        でくれています。そのお蔭で、UserFormモジュールではMsForms.Text 等のコントロール
        に対して、Enter等を含めたイベントプロシジャーを構築できます。
    (f) クラスモジュールには、そのサポートがないので、MsForms.Text 等のコントロールから Enter
        イベント等を構築できません。

ここで、クラスモジュール内に、MsForms.Control で定義したオブジェクト(WithEvents 付き)を用意
してみます。そうすると、ウィンドウ右上の [Declalations] のリストから Enter 等のイベントプロシジャー
の雛形を展開することができます。
       

それならば、MsForms.TextBox 等から MsForms.Control へコントロールオブジェクトをコピー
すれば、それで問題を解決することができないでしょうか?

残念ながら、それでは解決にはなりません。何故なら・・・
    MsForms.TextBox 等からMsForms.Control へのコントロールオブジェクトのコピー
が出来ないのです。下記のコピーはエラーになります。
    Dim Ctrl1 As MsForms.TextBox
    Dim Ctrl2 As MsForms.Control
    Set Ctrl2 = Ctrl1    'Error

上記の理由で、クラスモジュールでは、Enter 等が利用できないのです。


なお、汎用クラス(Ver 2.0)では、別の方法でEnter等のイベントをクラスモジュールに
構築する事ができました。その解説は汎用クラスのページを参照してください。




      2020年現在、Excel 97 どころか、Excel 2010 ですら、もう間もなくサポート終了を迎えるという時期ですから、
    ここから先の 『 Excel 97 向け解説』 は不要です。読み飛ばしてください ( 尚、記事としては今後も残します )。

  ところで、Excel97は、未だ未だ現役のバージョン(これを執筆/リリース した 2004年頃の話です)
ですから、97を含めた混在環境で使うというケースは充分に考えられます。しかし、RaiseEvent は97
では使えません
ので、このままでは役に立ちません。

  そこで、「擬似からの脱却」手法の骨格はそのまま(2段目→1段目のメソッドによるイベント引継ぎ
は全く問題ない)にして、RaiseEvent の代わりになる機能を自作する事にします。それには、7節
で解説したUserFormモジュール内のサブルーチンを直接Callする方法を使います。
      1段目のクラスで
          ・Event宣言を無くす
          ・Rgstメソッドに、呼び元のUserFormを引き継ぐ為の[Caller]引数(Object 型)を追加
            UserForm側では、ここに[Me]を記述します。
          ・RaiseEventの代わりに、下記の処理でUserFormへイベントを上げます。
                  RaiseEvent Click (MyIndex)
                      ↓
                  Call MyCaller.xxxx_Click (MyIndex)

  '===============================================================
  '===== イベント通知プロシジャー ==================================
  '===============================================================

  Private Sub Raise_Click(ByVal Index As Integer)
      Call MyCaller.WeekBtn_Click(Index)
  End Sub
 

  これは、クリックイベント専用で、ここから直接UserForm側のクリックルーチンを呼び出しています。
しかし、実際の汎用クラス(clsBpca97/clsBpca97Ch)を考えた場合、
        1VBAProject 内の複数のUserFormから利用される
という事が有り得ます。また、当然クラスモジュールを他のブックにインポートして使う事も有る訳で
すから、上記のままでは『利用に際してクラスの手直しが必須』となってしまい、ブラックボックス的
なクラスの利用が出来ません。上記では、呼び元のUserFormに
        WeekBtn_Click
という名前のサブプロシジャーを用意してあるという前提のコードですが、他のUserFormでも『この
名前で』とは言えませんね。そうして、UserFormごとに別の名前のサブプロシジャーを用意したら、
UserForm名によって分岐処理を構築しなければなりませんから、『利用の度に手直し』が必要となっ
てしまいます。

  これでは大変ですので、[ clsBpca97 ]クラスでは、UserForm側に用意する『イベント通知受領プ
ロシジャー』の名前を
        clsBpca97__Event    (間のアンダーバーは2つ。名前の重複回避策)
で【固定】にしています。1VBAProject 内の複数のUserForm から利用する場合であっても、全て
のUserForm で、用意するプロシジャーの名前は[ clsBpca97__Event ]で同じにします。

 また、1UserForm内で複数の『コントロール配列』グループを作る場合も有り得ます。その場合で
あっても、UserForm側に用意する「イベント通知受領プロシジャー」は上記の[ clsBpca97__Event ]
只1つです。このままでは、別グループを区別できませんので、これに対応する為、Rgst メソッドに
[GrpId]引数を加え、この内容をイベント通知の際に返して貰う事にします。これにより、「UserForm
内の、どのコントロール配列か」を識別できるようになります。

  ところで、2段目のクラスモジュールにおいて、個々のイベントで個別にUserFormモジュール側
の[ clsBpca97__Event ]呼び出しを記述するのはコーディング的に無駄が多いですね。そこでクラ
ス側でも、一端『イベント通知窓口ルーチン』へ集約し、そこから、UserForm側の代表窓口『イベン
ト受領窓口ルーチン』を呼び出します。

  UserForm側のイベント受領窓口ルーチンでは、引数で受け取った[GrpId]と[発生イベント種別]
により、最終的なイベントルーチンへ分岐させます。

  下記に汎用クラス【clsBpca97 】のイベント通知処理の部分だけ掲載します。ここでは、[ WeekBtn_
Click ]というプロシジャーは、[WeekBtn]クラスオブジェクトの[Click イベントプロシジャー]という意味
ではなく、単に[ WeekBtn_Click ]という名前のサブプロシジャーに過ぎません。[clsBpca97__Event]
のCall ステートメントと名前が合ってさえいれば、例えば[ABC]という名前でも構いません。
===== UserForm モジュール ==================================

  Private Sub WeekBtn_Click(ByVal Index As Integer)
  Dim vntWeekName As Variant
      vntWeekName = Array("", "日", "月", "火", "水", "木", "金", "土")
      MsgBox vntWeekName(Index) & "曜日ボタンがクリックされました(" & Index & ")"
      If (WeekBtn.Item(Index).BackColor = vbButtonFace) Then
          WeekBtn.Item(Index).BackColor = vbRed
      Else
          WeekBtn.Item(Index).BackColor = vbButtonFace
      End If
  End Sub

  '===================================================================
  '===== イベント通知受領プロシジャー(Public) ==========================
  '===================================================================
  '※ [clsBpca97]クラスでは、[clsBpca97]クラスに登録したコントロールの
  ' イベントは、全てのグループが、この
  '      通知受領プロシジャー[clsBpca97__Event]  <名称固定>
  ' を通して送られてくる。
  ' [GrpId]によって、所定のグループ別のイベントプロシジャーに分岐させる。
  ' (通知受領プロシジャーは、名前の重複を防ぐ為に敢えてアンダーバーを2つ繋げている)

  Public Sub clsBpca97__Event _
          (ByVal GrpId As String, _ByVal EventId As Long, ByVal Index As Integer, _
            ByVal Cancel As MSForms.ReturnBoolean, _
            ByVal KeyCode_Ascii As MSForms.ReturnInteger, _
            ByVal Button As Integer, ByVal Shift As Integer, _
            ByVal X As Single, ByVal Y As Single)
      Select Case GrpId
          Case "WeekBtn"
              Select Case EventId
                  Case BPCA_Click
                      Call WeekBtn_Click(Index)
                  Case Else
              End Select
          Case Else
      End Select
  End Sub
 

===== clsBpca97 モジュール(1段目) ==================================

  '===================================================================
  '===== clsBpca97Ch から呼ばれるイベント励起メソッド ==================
  '===================================================================

  Public Sub RaiseClick(ByVal Index As Integer)
      Call Raise_Event(BPCA_Click, Index, DmyCancel, DmyKeyCode_Ascii, 0, 0, 0, 0)
  End Sub

  Public Sub RaiseDblClick _
                      (ByVal Index As Integer, ByVal Cancel As MSForms.ReturnBoolean)
      Call Raise_Event(BPCA_DblClick, Index, Cancel, DmyKeyCode_Ascii, 0, 0, 0, 0)
  End Sub
      :
      :
  '===================================================================
  '===== イベント通知共通プロシジャー ==================================
  '===================================================================
  '※ [clsBpca97]クラスでは、呼び元のUserFormに用意してある
  '      通知受領サブ[clsBpca97__Event]    <名称固定>
  ' をCallする事でイベント発生を通知する
  ' (通知受領サブは、名前の重複を防ぐ為に敢えてアンダーバーを2つ繋げている)

  Private Sub Raise_Event _
          (ByVal EventId As Long, ByVal Index As Integer, _
            ByVal Cancel As MSForms.ReturnBoolean, _
            ByVal KeyCode_Ascii As MSForms.ReturnInteger, _
            ByVal Button As Integer, ByVal Shift As Integer, _
            ByVal X As Single, ByVal Y As Single)

      Call MyCaller.clsBpca97__Event _
                    (MyGrpId, EventId, Index, Cancel, KeyCode_Ascii, Button, Shift, X, Y)

  '※[MyCaller]は[Object]型のUserFormオブジェクトです。
  ' [MsForms.UserForm]型では、サブルーチンを参照できません。

  End Sub


===== clsBpca97Ch モジュール(2段目) ==================================

  Private WithEvents MyCtrlCmd As MSForms.CommandButton

  Private Sub MyCtrlCmd_Click()
      If (blnParent And blnEventClick And MyEnableEvents) Then
          MyParent.RaiseClick MyIndex
      End If
  End Sub

  Private Sub MyCtrlCmd_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
      If (blnParent And blnEventDblClick And MyEnableEvents) Then
          MyParent.RaiseDblClick MyIndex, Cancel
      End If
  End Sub
      :
      :
 


  判り易く図示したものを用意しましたので、下記の図を参照してください。
       【 clsBpca97 概念図 】 
コード自体については、『汎用クラス』のサンプルブックを参照して下さい。



  最後に、この「擬似からの脱却」手法の汎用クラスモジュール【 clsBpca 】を利用したサンプルの
幾つかを紹介します。

  ====================================================================
  次節 : §11  その他のサンプルコード
  ====================================================================

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


[ Home へ戻る ]

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

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