11

インターネット上で、私がやりたいことをほぼ実行できる多くのリソースを見つけましたが、完全ではありません。名前付き範囲「デイリスト」があります。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

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

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

4

2 に答える 2

19

あなたにとって有効で、以下よりもはるかに簡単な解決策を受け入れたことは知っていますが、興味がある場合は、これがあなたの質問に対するより直接的な答えになるでしょう。

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

クラス モジュール内 (私は 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

これは役に立ちますか?詳細については、Chip Pearson のサイトを参照してください。彼は、ほとんどのトピックに関する優れた情報を提供していますhttp://www.cpearson.com/excel/Events.aspx

VBA は VB6 に基づいているため、完全なオブジェクト指向言語ではないことを覚えておいてください。たとえば、通常の意味での継承はサポートされておらず、インターフェイスの継承のみがサポートされています。

お役に立てれば :)

于 2012-05-15T08:27:54.937 に答える
1

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

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
于 2012-05-15T02:02:10.037 に答える