★Access2000VBA・Excel2000VBA独学~今・選択されてる or 指定したオブジェクトの省略の無い階層構造をさっと調べる自作関数 ~イミディエイトウィンドウで使う自作関数 ★ ~Current無省略オブジェクト式記述02~
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
※関連記事
● Access2000VBA・Excel2000VBA独学~イミディエイトウィンドウで使う自作関数 ★ ~Current無省略オブジェクト式記述~
★ (01)指定したオブジェクトの親のオブジェクトたちを、1段階ずつ上に上がって調べていく自作関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
' ' Function ObjTypeChk01(ObjTest01 As Object) Dim s_TmpTypeName01 As String s_TmpTypeName01 = TypeName(ObjTest01.Parent) If s_TmpTypeName01 <> "Application" Then Debug.Print s_TmpTypeName01 Else Debug.Print "Application" Exit Function End If ' Debug.Print "===============================" ' Stop Call ObjTypeChk01(ObjTest01.Parent) ' Debug.Print TypeName(ObjTest01.Parent) Set ObjTest06 = Nothing End Function ' ' |
このプログラムは、適当なセルを選択してから、イミディエイトウィンドウにて、
? ObjTypeChk01(Application.Selection)
と書いてEnterすると、次のように表示されます。
Worksheet
Workbook
Application
階層が、逆順で出てきます。
そのほか、例えば棒グラフを作って、例えばそのグラフの棒の部分を2回クリックしたのち、同じく
? ObjTypeChk01(Application.Selection)
とやると、
Series
ChartGroup
Chart
ChartObject
Worksheet
Workbook
Application
と、出てきます。
これも、階層が逆順で出てきます。
この関数だけだと、一番モト(起点・出発点)となる、「Application.Selection」のオブジェクトの種類がわからないのと、もちろん、逆さまに出てきてしまうので少々不便です。
それを以降の(02)と(03)のプログラムで解決したいと思います。
============================
★ (02)指定したオブジェクトの親のオブジェクトたちを、1段階ずつ上に上がって調べていき、グローバル変数(配列)に書き込んでいく自作関数
この自作関数は、動きとしては前項のものとまったく変わりません。
ただ、イミディエイトウィンドウに表示するのではなく、グローバル変数(配列の変数)に、オブジェクトの種類の名前を書き込んでいきます。そこが異なります。
また、配列のグルーバル変数に書き込むので、このプログラムが完了したあとも、グローバル変数と書きこまれた名前はメモリ上に残っています。
なので、それを、他のプログラムにて、また引き続き使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
' ' Const g_i_KaisouReservNum As Integer = 29 Dim g_s_ObjKaisou01(g_i_KaisouReservNum) As String '↑オブジェクトの種類の名前を格納するグローバルな配列変数 ' とりあえず30階層分、用意した。 ' 30階層分にした理由は、さすがに30階層は無いと思うのでこれで足りると思ったから。 ' 本来は、Redimで要素数を決めないといけないのでしょうが、 ' 今回は、再帰的なプログラムにするので、その場合だと ' Redimは使い方が面倒くさい気がするし、よくわからないので今回は使いません。 ' ' (=配列には、階層の数だけオブジェクトの種類の名前を代入するのですけど、 ' Redimを使うとなると、再帰処理をApplicationの階層まで全部完了して、 ' その上で階層の総数を求めてからでないと ' 配列の要素の総数を求め・決められないのでめんどくさいので ' Redimを使うのはやめます。) Dim g_s_Cnt01 As Integer '↑そのグローバルな配列変数のインデックス(添え字=要素数)を表すためのカウンタ変数。 Function ObjTypeChk02(ObjTest01 As Object) Dim s_TmpTypeName01 As String s_TmpTypeName01 = TypeName(ObjTest01.Parent) '↑引数によって渡されるオブジェクトの ' 1階層上位のオブジェクトの種類の名前をゲットして、変数に代入。 If s_TmpTypeName01 <> "Application" Then '↑ゲットした内容が、「Application」じゃなかったら以下の処理 g_s_ObjKaisou01(g_s_Cnt01) = s_TmpTypeName01 'グローバル配列に、現在のオブジェクトの種類を書き込み、 ' 処理を続ける。 ElseIf s_TmpTypeName01 = "Application" Then '↑s_TmpTypeName01の値が、「Application」だったら以下の処理。 g_s_ObjKaisou01(g_s_Cnt01) = "Application" 'グローバル配列に、「Application」と書き込む。 Exit Function 'プログラムの強制終了。 ' 「Application」が階層の最上段なので、 ' それ以上やっても「Application」が繰り返されるだけで無駄なので ' 強制終了する。 Else End If g_s_Cnt01 = g_s_Cnt01 + 1 '↑カウンタ変数にグローバル配列の要素数を表す数値を入れる。 ' Debug.Print "===============================" ' Stop Call ObjTypeChk02(ObjTest01.Parent) '↑再帰的に、1階層ずつ、上に行って、 ' オブジェクトの種類をグローバル配列に書き込む。 End Function ' ' |
============================
★ (03)上記の関数を利用して、①起点(=出発点)となるオブジェクトの名前もゲットし、②階層構造を逆さまではなくて正しい順序で書き出す自作関数
選択したオブジェクトを起点として階層構造を正順に書き出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
' ' Function SelectionObject_ObjModelKaisouCheck01() 'イミディエイトから呼び出せるように「Function」プロシージャにした。 Dim i As Integer g_s_ObjKaisou01(0) = TypeName(Application.Selection) '↑グローバル配列に今現在選択しているオブジェクトの種類を書き込む g_s_Cnt01 = 1 '↑ObjTypeChk02に正しいカウンタの値を渡すために ' グローバルのカウンタ変数に、1を代入。 '「0」は今さっき、やったので。 Call ObjTypeChk02(Application.Selection) 'グローバル配列に、1階層ずつ上位の、オブジェクトの種類を書き込む。 ' Stop 'グローバル変数の中身のチェック(不要時はコメントアウト) '●メイン 'グローバル配列に書き込んだ内容をお尻から表示する For i = g_i_KaisouReservNum To 0 Step -1 'グローバル配列の最後から処理。 If g_s_ObjKaisou01(i) <> "" Then '↑グローバル配列の現在の要素の内容が空白じゃないなら、以下の処理。 Debug.Print g_s_ObjKaisou01(i) '↑オブジェクトの種類の名前をイミディエイトに表示 Else '空白などなら何もしない。 End If Next i Erase g_s_ObjKaisou01 '↑配列の初期化 '(これしないと、次回、Applicatinや ' その他がダブって表示されることがあるので ' やっておく。 ' グローバル変数だから、何もしないと前回の結果がそのまま消えずに残ってしまうので、 ' それで、Applicatin などがダブって表示されてしまうことがあるので。) g_s_Cnt01 = 0 '↑不要ではあるけど、念のため、カウンタも初期化 End Function ' ' |
(01)にて、棒グラフの棒の部分をクリックしたのち、
? ObjTypeChk01(Application.Selection)
とやると、以下のように出てくる、と書きました。
Series
ChartGroup
Chart
ChartObject
Worksheet
Workbook
Application
このプログラムでは、同じことをすると、
(? SelectionObject_ObjModelKaisouCheck01 でEnterすると)
Application
Workbook
Worksheet
ChartObject
Chart
ChartGroup
Series
Point
と表示されます。
「グラフの棒」は、どうやら「Point」というオブジェクトであり、そしてその階層まで、上記のような階層構造をたどってくる・・・、ということが分かります。
(※「Point」は、「棒」という意味ではなくて、値を描画(=点=Point)で表現しているモノ?という感じの意味のようです。折れ線グラフの場合は、「Point」は、値を示す場所にできる各「点」のことっぽいです。その点は、1個1個、そこだけを選択できるので、そのように選択すると「Point」としてイミディエイトに表示されます。折れ線だけを選択するとすべての「点(Point)」が同時選択され、「Point」の1つ上位の「Series」がイミディエイトに「起点」のオブジェクトとして表示されます。詳しくはヘルプと実際の動きを見てみてください。
棒グラフでも、同じ色の棒が複数選択された状態だと「Series」が、いっぽう、1つだけが選択された状態だと「Point」が、選択されたとみなされるっぽいです。)
============================
★ (04)前項の(03)を、選択したオブジェクトではなくて、「オブジェクト式で指定したオブジェクト」を使って、それによって階層構造を調べられるように少し改変したもの。
Range.Font オブジェクトとか、Range.Interior オブジェクト などは、「マウスで選択」することが「できない」「オブジェクト」なので、オブジェクト式を手動で指定してからでないと、その階層構造が調べられません。
このプログラムはそういう場合について、対応させてみました。
内容はほとんど同じです。
また、「Range(×××)」という書き方のように、「(例えば上位の)階層が省略されたオブジェクト式の書き方」の場合、その「Range(×××)」などをそのまま引数に指定していただくと、その上位に何が(どの階層が)省略されているか?もわかると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
' ' Function DesignateObj_ObjectModelKaisouCheck01(o_ChoseObj01 As Object) 'イミディエイトから呼び出せるように「Function」プロシージャにした。 Dim i As Integer g_s_ObjKaisou01(0) = TypeName(o_ChoseObj01) '↑グローバル配列に今現在選択しているオブジェクトの種類を書き込む g_s_Cnt01 = 1 '↑ObjTypeChk02に正しいカウンタの値を渡すために ' グローバルのカウンタ変数に、1を代入。 '「0」は今さっき、やったので。 Call ObjTypeChk02(o_ChoseObj01) 'グローバル配列に、1階層ずつ上位の、オブジェクトの種類を書き込む。 ' Stop 'グローバル変数の中身のチェック(不要時はコメントアウト) '●メイン 'グローバル配列に書き込んだ内容をお尻から表示する For i = g_i_KaisouReservNum To 0 Step -1 'グローバル配列の最後から処理。 If g_s_ObjKaisou01(i) <> "" Then '↑グローバル配列の現在の要素の内容が空白じゃないなら、以下の処理。 Debug.Print g_s_ObjKaisou01(i) '↑オブジェクトの種類の名前をイミディエイトに表示 Else '空白などなら何もしない。 End If Next i Erase g_s_ObjKaisou01 '↑配列の初期化 '(これしないと、次回、Applicatinや ' その他がダブって表示されることがあるので ' やっておく。 ' グローバル変数だから、何もしないと前回の結果がそのまま消えずに残ってしまうので、 ' それで、Applicatin などがダブって表示されてしまうことがあるので。) g_s_Cnt01 = 0 '↑不要ではあるけど、念のため、カウンタも初期化 End Function ' ' |
例えば、イミディエイトで、
? DesignateObj_ObjectModelKaisouCheck01(Range("A1").Font)
とやることで、
Application
Workbook
Worksheet
Range
Font
といった階層構造が得られます。
ただ、この自作関数は、関数の引数にオブジェクト式を指定する時に、結局、オブジェクトの階層構造を指定して書くので、正直この自作関数は、「無意味・無駄」な自作関数かもしれません。
それに、場合によっては正しく単一オブジェクトを指定しているのに、エラーになったりもします。
また、FontやStyle、のように、1つだけではなくて色んなオブジェクトの下位に居るオブジェクトに付いては意図せず、すごく上の階層に居るかのごとく、表示されてしまうこともあります。
なので、何かを調べるときのヒントくらいにしかならないかもしれません。
でも、まあ、プログラムの「汎用化」「部品化」の練習にもなるし、もしかしたら何か「使い道」があるかもしれませんので、もしよかったら動きを見てみてください。
※参考
? DesignateObj_ObjectModelKaisouCheck01(Range("A1").Border)
でEnterすると、正しいと思いきや、エラーになってしまいます。
? DesignateObj_ObjectModelKaisouCheck01(Range("A1").Borders)
と、コレクションを指定してEnterすると、以下のように、正しく階層構造が表示されます。
Application
Workbook
Worksheet
Range
Borders
作ったプログラムが悪いのかもしれませんが、それを修正しようと何か探ってみると、また別の新しいことが分かるかもしれません。
============================
- 投稿タグ
- 「ニセモノ」への道, 「本物」に近づくために, AccessVBA, Accessの独学, Access操作の基礎, Accesの独学, ADO/DAO, ExcelSQL, ExcelVBA, Excelの独学, Excel操作の基礎, Excel連携VBA, MicrosoftQuery, ODBC, SQL, パソコンでの自動化, ビジネスパソコンの基礎, ビジネス一般常識, マクロ, ワークシート関数, 独学, 自動化