【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で実装したこともあります)。

何かの参考になれば幸いです。