C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA(最近はPMillマクロとFusion360APIが多い)

Formにボタンを動的に追加し、イベントを発生させたい

色々と思うことが有って、VBAのFormに取り組んでいるのですが
知識が足りず悩んでます。

UserFromにコマンドボタンを動的に追加し、イベントも動的に発生させたいです。
こちらで教わったのですが
Formの内容を、DrawTableに反映する - C#ATIA

こちらを参考にしてみました。
VBA。フォームにコントロールを動的に追加する - Qiita

が、こちらのコード、色々とまずかったのでこんな風に
してみました。


まず、フォームモジュールですが作りましたが何もしません。
とにかく作るだけで、名前は "UserForm1" です。

続いて、クラスモジュール。 名前は "Class1" です。

'vba Class1.cls
Option Explicit

Private WithEvents mBtn As MSForms.CommandButton

Sub InitBtn(ByVal Btn As MSForms.CommandButton)
    Set mBtn = Btn
End Sub

Private Sub mBtn_Click()
    Dim Msg$
    Msg = "オートコンプリートで、" & vbNewLine & _
    "ControlTipText出ませんが" & vbNewLine & _
    "このボタンでは[ " & mBtn.ControlTipText & " ]です"
    MsgBox Msg
End Sub

続いて標準モジュール。 名前は "Module1" です。

'vba Module1.bas
Option Explicit

Sub FormTest()
    Dim CapAry As Variant: CapAry = Split("hoge,piyo,fuga", ",")
    Dim TipAry As Variant: TipAry = Split("foo,bar,baz", ",")
    Dim BtnInfoAry() As Variant: ReDim BtnInfoAry(UBound(CapAry))
    Dim i&
    
    For i = 0 To UBound(CapAry)
        BtnInfoAry(i) = Array(CapAry(i), TipAry(i))
    Next
    
    Call Init_Form(BtnInfoAry)
End Sub
Private Function Init_Form(ByVal InfoAry As Variant) As UserForm1
    Dim BtnCnt&: BtnCnt = UBound(InfoAry)
    Dim Uf As UserForm1: Set Uf = UserForm1
    
    With Uf
        .Width = 70
        .Height = (BtnCnt + 1) * 20 + 30
    End With
    
    Dim i&, Btn As MSForms.CommandButton
    Dim BtnAry() As Class1: ReDim BtnAry(BtnCnt)
    For i = 0 To BtnCnt
        Set Btn = Uf.Controls.Add("Forms.CommandButton.1", i, True)
        With Btn
            .Top = 5 + (i) * 20
            .Left = 5
            .Height = 20
            .Width = 70
            .Caption = InfoAry(i)(0)
            .ControlTipText = InfoAry(i)(1)
        End With
        Set BtnAry(i) = New Class1
        Call BtnAry(i).InitBtn(Btn)
    Next
    UserForm1.Show
End Function

Init_Form関数は戻り値返していないのですが、後のテストの為です。
この関数のキモは、こちら

    Dim Uf As UserForm1: Set Uf = UserForm1

インスタンスを生成しているのではなく、最初に作った空っぽのForm自体を
受け取っています。
で、この状態であれば無事動き、イベントも発生します。
f:id:kandennti:20171006002619p:plain
自宅なのでExcelでやってますが、CATIAでも同じでした。

問題はここから。先程の部分をインスタンスに変更します。

    Dim Uf As UserForm1: Set Uf = New UserForm1

これだと、イベントが発生しません・・・。

又、インスタンスではなく最初の状態に戻し、

'vba Module1.bas
Option Explicit

Sub FormTest()
 ・・・
    Dim Uf As UserForm1
    Set Uf = Init_Form(BtnInfoAry)
    Uf.Show 
End Sub

Private Function Init_Form(ByVal InfoAry As Variant) As UserForm1
    Dim BtnCnt&: BtnCnt = UBound(InfoAry)
    Dim Uf As UserForm1: Set Uf = UserForm1

 ・・・
    Next
    'UserForm1.Show
    Set Init_Form = Uf
End Function

FormTest側で戻り値を受け取り、FormTest側でShowさせても
同様にイベントが発生しません。
(本当はこうしたかったので、関数名をInit_Formしたのに…)

こんなもんなのでしょうか?


追記です。 教えていただきました。
フォームモジュールは空っぽではなく、この様にしました。

'vba UserForm1.frm
Option Explicit

Private mAry As Variant

Sub SetBtn(ByVal Ary As Variant)
    mAry = Ary
End Sub

標準モジュールはこの様に

'vba Module1.bas
Option Explicit

Sub FormTest()
 ・・・
    Dim Uf As UserForm1
    Set Uf = Init_Form(BtnInfoAry)
    Uf.Show 
End Sub

Private Function Init_Form(ByVal InfoAry As Variant) As UserForm1
    Dim BtnCnt&: BtnCnt = UBound(InfoAry)
    Dim Uf As UserForm1: Uf = New UserForm1

 ・・・
    Next
    'UserForm1.Show
    Call Uf.SetBtn(BtnAry)
    Set Init_Form = Uf
End Function

これで上手く行きました。 ありがとうございます。