VBAでUserFormの全プロパティ値を取得するについての内容を少しづつバージョンアップしています。前回はVBAでコンテナ単位にまとめる動作を検討しました。今回は、いよいよコントロールのプロパティー値をコンテナ単位で取得していけるようにコーディングを見直していきます。
ザックリ言うと .Parent プロパティを使って親オブジェクトを確認し動作を分岐するような感じになります。コントロールのプロパティー値取得部分は別プロシージャにしていきたいと思ってます。それではさっそくやっていきましょう。
階層が深くなりそうなのをクリアしていく感じですか?
よろしくお願いしますm(__)m
以前の記事「VBA で Userform の全プロパティ値を取得する」のコードを修正しています。
【この記事でわかることは】
Parent プロパティを使って UserForm 内の全コントロールのプロパティ値をコンテナ単位にまとめて取得する方法
Parent プロパティでコンテナ単位にまとめる
取得したプロパティ値を書き込むシートがこちらです(前回記事で設定)
3行目の「Parent:」と2行目の「オブジェクト名:」を見れば、E列のオブジェクト名「Page1」は「MultiPage1」のコンテナ内にあることがわかります。
この関係をコーディングに反映していきます。
Parent プロパティを組み入れたコード
さっそくメインのコード下に表示します。かなり長くて深くなっちゃいました。
最深部は、UserForm > MultiPage > Page > Frame > Control
'UserFormと配置コントロールの全プロパティ値を取得する
Sub getCtrlProperty()
Dim i As Long, j As Long, k As Long
Dim n As Long: n = 0 'UserForm数カウント用
Dim ufrm As Object 'UserFormオブジェクト用
Dim Ctrl As Control, InCtrl As Control, InC As Control
Dim fname As String 'UserFormオブジェクト名
Dim wb As Workbook, ws As Worksheet
Set wb = ActiveWorkbook
Set ws = ThisWorkbook.Sheets("Ctrl_SetValue")
Dim ctrlStr() As String 'プロパティ値保存用
Dim c As Long 'Control用
Dim p As Long 'Page用
With wb.VBProject 'Typeがユーザーフォームの場合だけ処理する
For i = 1 To .VBComponents.Count
If .VBComponents(i).Type = 3 Then 'ユーザーフォーム
n = n + 1 'ユーザーフォーム数をカウント
'2つ目のUserFormの場合シートコピー
If n > 1 Then ws.Copy after:=ws: ws.Activate
'シートの入力データをクリアする
ws.Columns(2).Clear
ws.Range(Columns(4), Columns(4).End(xlToRight)).Clear
ReDim ctrlStr(41) '配列の要素数初期化
fname = .VBComponents.Item(i).Name
ctrlStr(0) = "UserForm"
ctrlStr(1) = fname
ctrlStr(2) = ""
Set ufrm = UserForms.Add(fname) 'UserFormをオブジェクトに
On Error Resume Next
With ufrm
For k = 3 To 41 '↓プロパティ値取得関数使用
ctrlStr(k) = getPVal(ws.Cells(k + 1, 1), ufrm)
Next k
End With
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, 2) = ctrlStr(j) 'セルに値を書き込む
Next j
On Error GoTo 0
'ここからコントロールのプロパティ取得
On Error Resume Next
c = 0
For Each Ctrl In ufrm.Controls
'すでに取得済みなら処理しない
If WorksheetFunction.CountIf(ws.Rows(2), Ctrl.Name) <> 0 Then
GoTo Next_Ctrl
End If
ReDim ctrlStr(125) '配列の要素数を初期化
c = c + 1
'Typeで処理を分岐
Select Case TypeName(Ctrl)
Case "MultiPage" 'MultiPageだった場合の処理
With Ctrl
'プロパティ値取得処理へ
Call getP(ctrlStr(), Ctrl, ws)
'MultiPageだけはPage数をカウントして上書き
ctrlStr(125) = .Pages.Count 'Page数を書き込む
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j) 'セルに値を保存
Next j
'Page毎に取得していく
For p = 0 To .Pages.Count - 1
'Page のプロパティ値取得へ
Call getP(ctrlStr(), .Pages(p), ws)
c = c + 1
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j)
Next j
'対象Page内のコントロール分ループ
For Each InCtrl In .Pages(p).Controls
'親がフレームだった場合は処理せずパスする
If InCtrl.Parent.Name Like "Frame*" Then GoTo the_next
'プロパティ値取得処理へ
Call getP(ctrlStr(), InCtrl, ws)
c = c + 1
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j)
Next j
'Page内にフレームがあった場合の処理
If InCtrl.Name Like "Frame*" Then
'フレーム内のコントロール分ループ
For Each InC In InCtrl.Controls
'プロパティ値取得処理へ
Call getP(ctrlStr(), InC, ws)
c = c + 1
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j)
Next j
Next
End If
the_next:
Next
Next p
End With
Case "Frame" 'Frameだった場合の処理
'プロパティ値取得処理へ
Call getP(ctrlStr(), Ctrl, ws)
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j)
Next j
'フレーム内のコントロール分ループ
For Each InCtrl In Ctrl.Controls
'プロパティ値取得処理へ
Call getP(ctrlStr(), InCtrl, ws)
c = c + 1
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j)
Next j
Next
Case Else
'プロパティ値取得処理へ
Call getP(ctrlStr(), Ctrl, ws)
For j = 0 To UBound(ctrlStr)
ws.Cells(j + 1, c + 3) = ctrlStr(j)
Next j
End Select
Next_Ctrl:
Next Ctrl
On Error GoTo 0
Set ufrm = Nothing
End If
Next i
If n = 0 Then MsgBox "UserFormはありません!"
End With
Set ws = Nothing
Set wb = Nothing
End Sub
コード内にコメントは入れていますが、必要な部分を解説していきます。
※以前の記事で解説しているところは省略している部分がありますので参照いただければ幸いです。
プロパティ値取得処理部分を別プロシージャに分けました
コントロールのプロパティ値を取得するためのプロシージャが次のコードです。
'コントロールのプロパティ値取得用プロシージャ
Sub getP(ByRef PStr() As String, Ctrl As Object, ws As Worksheet)
Dim i As Long
Dim c As Long
Dim InC As Control
ReDim PStr(125) '要素数を初期化
With Ctrl
PStr(0) = TypeName(Ctrl) 'タイプ
PStr(1) = .Name 'オブジェクト名
PStr(2) = .Parent.Name '親オブジェクト名
On Error Resume Next
For i = 3 To 124 '関数でプロパティ値取得
PStr(i) = getPVal(ws.Cells(i + 1, 3), Ctrl)
Next i
On Error GoTo 0
c = 0
For Each InC In .Controls 'コンテナ内のコントロール分ループ
c = c + 1
Next
PStr(125) = c 'コントロール数を書き込む
End With
End Sub
配列を参照渡しにしているので、呼び出し元にそのまま取得できた値が帰ります。
実行結果
実行結果をどのように示せるか考えましたが、思いつかなかったのでGIF画像貼っておきます。
コード実行動画(一部分のみ)
コンテナとなる MultiPage、Page、Frame などの処理の際に、そのコンテナ内に配置されたコントロールを処理することでコンテナ単位にまとめることができました。
コンテナ単位で処理することによって、コンテナ内のコントロールは順番より先に処理してしまうことになります。
そこで、順番がきた段階で処理済みかどうかを判別して重複して処理しないようにして回避する設定にしました。
まとめ(おわりに)
以上、UserForm の コントロールを Parent プロパティを使ってコンテナ単位でまとめながら取得するVBAコードの設定でした。
まとめと感想など
Type別にプロシージャを分ければもっとコードを短くできるけど、あえて一度に見られるようにしています(^^;
次回は、取得したデータを使って、MultiPage のある UserForm を復元できるかどうか試していきたいと思います。
うまくコンテナ単位でまとめることができましたね。
次回ちゃんと復元できるのかどうかが楽しみです(^^)
★★★ ブログランキング参加中! クリックしてね(^^)/ ★★★
【今後の記事について】
今回の記事はいかがだったでしょうか。皆さまのお役に立てたなら幸いです(^^;
「汎用でだれでも使えて活用できるように考える」というポリシーで、記事を継続して書いていきたいと思っています。どうぞよろしくお願いしますm(_ _)m
【検討中の今後の記事内容は・・・・】
・実務に役立つものを提供できるよう常に検討しています(^^ゞ
・その他雑記的に「プチネタなど」もいろいろ考えていきたいと思っています・・・・
・今後の記事にご期待ください(^^)/
過去記事のサンプルファイルをダウンロードできます
リンク先に今回記事のサンプルファイルを登録しています!
過去の記事で使用したサンプルファイルをダウンロードできるようにページを設置していますので、こちら(このリンク先)からご利用ください
【今回わかったことは】
UserForm 内の全コントロールのプロパティ値を
Parent プロパティを使ってコンテナ単位にうまくまとめる方法がわかりました