【ExcelVBA】CallByNameの使い方
- [記事公開]2022.12.14
- VBA
Yahoo!知恵袋の質問に答えた中から、CallByNameの使い方を紹介します。
質問
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11271827426
(VBA) EXCEL.2010 WINDOWS-XP(SP3)
VBAのFINDによる「書式検索」での、セルのフォント色 又は 背景色を検索して
セルが見つかれば、そのセルを Select する です。
但し、希望するコードは CallByName を運用したユーザー関数化ですが
そのコード、及び、Optionalデータの指定の仕方も不明です
———————————————————–
●例題
Rで定義された、あるセル列 26列 SET R = Range(A1:Z1) に対して
データは10セルにバラバラに列相対位置に合った数値1~26がセットされ
その他の16個は空白です。
フォント赤 RED=RGB(255,0,0) がセットされたセルが2個以上、最大5個あります
例えば C1, K1,R1にフォント色が赤である数値が存在
そこからカレントセルを除いた範囲を検索します
———————————————————–
現状で着手中の状況では、関数でOptional を使わずにFindFormat を定義
呼び出しっ式は カレントセルにある数値(例えばセルC1であれば 3)を渡して
Call CellCurOther(C1.Value)のように呼び出してます
なお、FINDで返却される変数 FNDCELはPublicで定義されてます。
Private Sub CellCurOther(ByVal CellCurValue)
Select Case CellCurValue
Case 1: Set SelRange = Range(R(1, 2), R(1, 26))
Case 26: Set SelRange = Range(R(1, 1), R(1, 25))
Case Else: Set SelRange = _
Union(Range(R(1.1), R(1, CellCurValue – 1)), Range(R(1, CellCurValue + 1), R(1, 26)))
End Select
Application.FindFormat.Clear ‘◆1
Application.FindFormat.Font.COLOR = RGB(255,0,0) ‘◆2
Set FNDCEL = SelRange.Find(what:=”*”, searchformat:=True)
If Not FNDCEL Is Nothing Then FNDCEL.Select
End Sub
———————————————————–
(1)上記の式を前提に、
Call文に OPTIONを追加して
文字色,背景色, FindFormat のその他を検索したい
そのとき Call文は Call CellCurOther(C1.Value, ▲,◆,・・)の形にして
▲,◆,・・にOPTION定義追加をしたい
(2)さらに、ユーザー関数としてOPTION指定によるコードをそれぞれ記入するのではなく、
長大になるのを防ぐため、’◆1”◆2の部分を CallByNameを利用するコードにしたい
私の拙い知識で、下記のようなコードにしましたが、当然ながら失敗してます。
‘ CallByName(Application.FindFormat, “FONT”, VbGet)
C = CallByName(Application, “FINDFORMAT”, VbGet)
C = CallByName(C, “FONT”, VbGet)
Call CallByName(C, “COLOR”, VbLet, “RED”)
以上の条件で、パス出来るコードをご教示ください
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11271827426
質問文が長いので、全部ではなく、最後の方にある(2)のご要望、CallByNameの使い方についてだけ、この記事では取り上げます。
回答
CallByNameの部分だけ、抜粋します。
Dim obj1 As Object
Set obj1 = Application.FindFormat
CallByName obj1, "Clear", VbMethod
'Application.FindFormat.Clear '◆1
Dim obj2 As Object
Set obj2 = obj1.Font
CallByName obj2, "Color", VbLet, RGB(255, 0, 0)
'Application.FindFormat.Font.Color = RGB(255, 0, 0) '◆2
解説
質問者の次のコード
C = CallByName(Application, "FINDFORMAT", VbGet)
は、エラーになるでしょうね。この辺が、VBAの分かりづらいところですが、Application.FindFormatというのは、オブジェクトなんです。vbGetでゲットしたいのなら、次のように記述します。
Set C = CallByName(Application, "FINDFORMAT", VbGet)
冒頭に、Setをつけただけです。でもこれでエラーは出なくなります。
次のコードもエラーになります。理由は、先のコードと同じ理由です。
C = CallByName(C, "FONT", VbGet)
エラーを出さないようにするには、Setをつければよいです。
Set C = CallByName(C, "FONT", VbGet)
もう一つ、エラーを出さないようにするには、対象となるオブジェクトを変数で宣言してしまえばよいです。
回答では、その方法にしました。
対象となるオブジェクトとは、例えば、Application.FindFormat.ClearというコードをCallByNameで置き換えたいのなら、Application.FindFormatの部分を変数にしてしまうのです。
Dim obj1 As Object
Set obj1 = Application.FindFormat
Objectというのは、どんなオブジェクトでも入るので、とても便利です。
ただ、代入の際は、Setが必要です。
CallByNameを使うときは、この例ですと、vbMethodとなります。
CallByName obj1, "Clear", VbMethod
Application.FindFormat.Font.Color = RGB(255, 0, 0)をCallByNameで置き換えたいのなら、これも適当なところをObject型の変数にいれてしまえばよいです。
今回は、obj1.Fontをobj2という変数にいれました。もちろんSetが必要です。
Dim obj2 As Object
Set obj2 = obj1.Font
CallByName obj2, "Color", VbLet, RGB(255, 0, 0)
CallByNameの使いどころ
正直言って、CallByNameは私は使ったことがないです。
先人者が使っていたのを、やむを得ず改修したことがあるくらいです。そのときに感じたのですが、CallByNameがあると、決して可読性はよくないですね。
汎用性は高くなるのでしょうが、使いどころが難しいな・・・と思いました。
抽象性を高めるためにはよいと思います。
汎用性と抽象性を高めるという目的以外では使わない(使えない)と思います。
昔、JavaJavaさん(私が勝手にそう呼んでいる)のサイトでCallByNameを効果的に使っていたのを思い出しました。
これも良記事ですので、引用しておきます。
昨日までJavaJavaしてた人がいきなりExcelのVBAを実装する羽目になったときのためのメモ
https://qiita.com/opengl-8080/items/5bd8ae7fe95f5c31dfc3
↑こちらのサイトのMVCの記事あたりでCallByNameを使っています。
こちらのサイトは、ずっとJavaを書いていた人が急にVBAを書けと言われて、自分のメモ用にまとめた記事のようでして、最初の方はたいして珍しくもない内容なんですが、半分以上スクロールダウンしたころから、非常に高度で専門的な内容になっていきます。さすがJava経験者だけあって、着眼点がおもしろく、特に”MVCで書く”というところは、何度も読んで、参考にしました(実際に真似してMVCをVBAで実装したこともあります)。
何かの参考になれば幸いです。
-
前の記事
【VBA】変数の宣言をしましょう【初心者向】 2022.12.13
-
次の記事
フォルダ配下(サブフォルダも)ファイル一覧を取得するには【CMD】【ExcelVBA】 2022.12.15