hiroshi akutsuの日記

主にプログラミング関係のこと

vba【コールバックぽく処理を記述】

たとえば、findnextを使って、検索にヒットするすべてのセルに処理を行いたいとします。

こういう時は、コールバックが使えたら便利だなと思っていました。

ただvbaにコールバック関数的なものがあるのか分かりませんが、callbyname関数があってこれを使うとそれっぽくできるとのことなのでやってみたメモを残します。


コールバックする関数はクラスモジュールのCommonMethodsというクラスを作って、そこにパブリックメソッドとして記述します。

第1引数に検索でhitしたセル(findAll関数から渡される)
第2引数にコールバックの大元から送った引数(mainサブルーチンから渡される)

Public Sub changeColor(ByVal fcell As Range, ByRef co As Collection)
    fcell.Interior.ColorIndex = co(1)
End Sub


findnextのループを行う関数はつぎのようになります。
標準モジュールや、クラスモジュールの場合はメソッドとして記述します。

第1引数に検索範囲
第2引数に検索テキスト
第3引数にコールバック関数名のstring
第4引数にコールバック関数に渡す引数のCollection

Private Sub findAll(ByVal ra As Range, ByVal whattxt As String, ByVal callback As String, ByVal callback_args As Collection)
    Dim fcell As Range
    Dim fadd As String

    
    Set fcell = ra.Find(what:=whattxt, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=True)
    If Not fcell Is Nothing Then
        fadd = fcell.Address
        Do
            CallByName New CommonMethods, callback, VbMethod, fcell, callback_args
            
            
            Set fcell = ra.FindNext(fcell)
            If fcell Is Nothing Then
                Exit Do
            End If
            If fcell.Address = fadd Then
                Exit Do
            End If
        Loop
    End If
End Sub

あとはmainから呼び出します。

Sub main()
    Dim callback_args As New Collection
    callback_args.Add 10

    Call findAll(Cells, "test", "changeColor", callback_args)
End Sub


コールバック関数をクラスモジュールに書いているのが若干気持ち悪いです。
javascriptのように無名関数を渡せると非常に勝手がいいなと思いますが、まあそこまでなくても希望の動きはできました。