web-dev-qa-db-ja.com

VBAで動的に作成されたユーザーフォームのコントロールにイベントハンドラーを割り当てます

私はインターネット上でそうする多くのリソースを見つけました ほとんど 私がやりたいことですが、完全ではありません。名前付きの範囲「daylist」があります。 dayListの各日について、その日のマクロを実行するボタンをユーザーフォームに作成したいと思います。私は ボタンを動的に追加する ができますが、daycell.textを名前付き範囲からボタン、イベントハンドラー、マクロに渡す方法がわかりません:Sこれが私がしなければならないコードですユーザーフォームを作成します。

Sub addLabel()
ReadingsLauncher.Show vbModeless
Dim theLabel As Object
Dim labelCounter As Long
Dim daycell As Range
Dim btn As CommandButton
Dim btnCaption As String


For Each daycell In Range("daylist")
    btnCaption = daycell.Text
    Set theLabel = ReadingsLauncher.Controls.Add("Forms.Label.1", btnCaption, True)
    With theLabel
        .Caption = btnCaption
        .Left = 10
        .Width = 50
        .Top = 20 * labelCounter
    End With

    Set btn = ReadingsLauncher.Controls.Add("Forms.CommandButton.1", "runButton", True)
    With btn
        .Caption = "Run Macro for " & btnCaption
        .Left = 80
        .Width = 80
        .Top = 20 * labelCounter
    '   .OnAction = "btnPressed"
    End With

    labelCounter = labelCounter + 1
Next daycell

End Sub

上記の問題を回避するために、私は現在、実行したい日(Day1など)を入力するようにユーザーに促し、これをマクロに渡すと機能します。

Sub B45runJoinTransactionAndFMMS()


loadDayNumber = InputBox("Please type the day you would like to load:", Title:="Enter Day", Default:="Day1")

Call JoinTransactionAndFMMS(loadDayNumber)

End Sub

Sub JoinTransactionAndFMMS(loadDayNumber As String)
xDayNumber = loadDayNumber

Sheets(xDayNumber).Activate
-Do stuff

End Sub

したがって、runButtonごとに、daycell.textを表示し、同じテキストをパラメーターとして使用するマクロを実行して、作業を行うワークシートを選択する必要があります。

どんな助けでも素晴らしいでしょう。マクロを処理するためにvbaコードを動的に書き込む応答を見たことがありますが、パラメーターを渡すことでもう少しエレガントに実行できる必要があると思います。方法はわかりません。よろしくお願いします!

11
BiGXERO

私はあなたがあなたのために働くそして以下よりはるかに簡単な解決策を今受け入れたことを知っています、しかしあなたが興味を持っているなら、これはあなたの質問に対するより直接的な答えでしょう。

ボタンのクリックを処理するクラスを作成する必要があるため、ボタンがクリックされるたびにクラス内のイベントが使用されます。これを1回実行するだけで、ボタンごとに新しいインスタンスを作成できます。これらのクラスがスコープ外になって失われるのを防ぐには、クラスレベルの宣言に格納する必要があります。以下では、コードを少し移動しました。

クラスモジュール内(私はそれをcButtonHandlerと呼んでいます)

Public WithEvents btn As MSForms.CommandButton

Private Sub btn_Click()
    MsgBox btn.Caption
End Sub

ほとんどのイベントをコントロールに使用できるため、イベントありが使用されます。以下のように、ボタン生成コードをユーザーフォームに移動しました。

Dim collBtns As Collection

Private Sub UserForm_Initialize()

Dim theLabel As Object
Dim labelCounter As Long
Dim daycell As Range
Dim btn As CommandButton
Dim btnCaption As String
'Create a variable of our events class
Dim btnH As cButtonHandler
'Create a new collection to hold the classes
Set collBtns = New Collection

For Each daycell In Range("daylist")
    btnCaption = daycell.Text
    Set theLabel = ReadingsLauncher.Controls.Add("Forms.Label.1", btnCaption, True)
    With theLabel
        .Caption = btnCaption
        .Left = 10
        .Width = 50
        .Top = 20 * labelCounter
    End With

    Set btn = ReadingsLauncher.Controls.Add("Forms.CommandButton.1", "runButton", True)
    With btn
        .Caption = "Run Macro for " & btnCaption
        .Left = 80
        .Width = 80
        .Top = 20 * labelCounter
        'Create a new instance of our events class
        Set btnH = New cButtonHandler
        'Set the button we have created as the button in the class
        Set btnH.btn = btn
        'Add the class to the collection so it is not lost
        'when this procedure finishes
        collBtns.Add btnH
    End With

    labelCounter = labelCounter + 1
Next daycell


End Sub

次に、別のルーチンからuseformを呼び出すことができます。

Sub addLabel()
ReadingsLauncher.Show vbModeless

End Sub

VBAのクラスは、多くのVBAブックで特に十分にカバーされていません(通常、理解するにはVB6ブックを読む必要があります)が、クラスとその仕組みを理解すると、非常に便利になります:)

お役に立てれば

編集-追加のクエリに対処する

コレクション内のオブジェクトを参照するには、これはキーまたはインデックスを介して行われます。キーを使用するには、アイテムをコレクションに追加するときにキーを追加する必要があります。

collBtns.Add btnH

になります

collBtns.Add btnH, btnCaption

このため、キーは一意である必要があります。その後、次のように参照できます。

'We refer to objects in a collection via the collection's key
'Or by it's place in the collection
'So either:
MsgBox collBtns("Monday").btn.Caption
'or:
MsgBox collBtns(1).btn.Caption
'We can then access it's properties and methods
'N.B you won't get any intellisense
collBtns("Monday").btn.Enabled = False

必要に応じて、クラスにプロパティ/メソッドを追加することもできます。たとえば、次のようになります。

Public WithEvents btn As MSForms.CommandButton

Private Sub btn_Click()
    MsgBox btn.Caption
End Sub

Public Property Let Enabled(value As Boolean)
    btn.Enabled = value
End Property

その後、アクセスされます:

collBtns("Monday").Enabled = False

これは役に立ちますか?さらに読むために、私はあなたにチップピアソンのサイトを紹介します、彼はほとんどのトピックについて素晴らしいものを持っています http://www.cpearson.com/Excel/Events.aspx

VBAはVB6に基づいているため、本格的なOO言語ではありません。たとえば、通常の意味での継承はサポートされておらず、インターフェイスの継承のみがサポートされていることを覚えておいてください。

お役に立てれば :)

19
SWa

ワークシートのクリックをキャッチする例。これをワークシートモジュールに入れます。

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  ' e.g., range(A1:E1) is clicked
  If Not Application.Intersect(Target, Range("A1:E1")) Is Nothing Then
    MsgBox "You clicked " & Target.Address
  End If
End Sub
1
andy holaday