サブフォルダも含め配下のフォルダパス全てを返すFunction
サブフォルダも含め配下のフォルダパス全てを返すFunction
作ってみた
いや、FileSystemObject
使えよ、って話なんですけどね。
Dir
関数使って作ったらどうなんのかな、と思って。
ソースコードを晒す
場当たり的に作ったやつなので、だいぶ恥ずかしいのですが、晒します。
リスト1
Public Function GetFolderPathAll( _ ByVal a_FolderPath As String) As String '配下の全てのフォルダのパスを、「>」で区切った文字列にして返す。 ' Dim ret As String ret = "" '対象のフォルダがなかったらReturn' If Dir(a_FolderPath, vbDirectory) = "" Then GoTo ReturnValues Dim tmp As String tmp = Dir(a_FolderPath & "\*", vbDirectory) Do 'Dirが文字列を返さなかったらループを抜ける。' If tmp = "" Then Exit Do 'Dirの返り値が「.」、「..」だったらContinue' If tmp = "." Then GoTo Continue If tmp = ".." Then GoTo Continue tmp = a_FolderPath & "\" & tmp '" 'フォルダパスじゃなかったらContinue' If GetAttr(tmp) <> vbDirectory Then GoTo Continue 'ここまでたどり着いたらフォルダパスのはず。' 'あとでSplitするときのために、区切り文字をファイルパスに' '使えない文字にする' ret = ret & tmp & ">" Continue: tmp = Dir() Loop Dim arr() As String arr = Split(ret, ">") Dim i As Long 'この段階では右端に「>」があるので、配列の最後の要素は空。' For i = LBound(arr) To UBound(arr) - 1 'GetFolderPathAllメソッドに投げるときには右端が「>」で' 'でないといけない。' If Right(ret, 1) <> ">" Then '一番底のフォルダまで行ったときは、右端に「>」が付いてい' 'ない文字列が「arr()」に入っている。' ret = ret & ">" End If 'サブフォルダを調べる。(再帰呼び出し)' ret = ret & GetFolderPathAll(arr(i)) Next ReturnValues: If ret <> "" Then If Right(ret, 1) = ">" Then '最後は右端の「>」をトル。' ret = Left(ret, Len(ret) - 1) End If End If GetFolderPathAll = ret End Function
ルートのフォルダのフルパスを渡して実行すると、配下のフォルダ全てのフルパスを「>
」で区切って一列棒状にした長~い文字列を返す、というもの。
地味に再帰を使っています。
使ってみる
とりあえずフォルダの準備
こんなフォルダ構成を、マクロを書いたDocumentのあるフォルダに作りました。
WordでVBAを書いているところにはツッコミなしで!
こんなコードで実行
次のコードを実行します。
リスト2
Private Sub test03() Dim tgtDir As String tgtDir = ThisDocument.Path Dim arr() As String arr = Split(GetFolderPathAll(tgtDir), ">") Dim i As Long For i = LBound(arr) To UBound(arr) Debug.Print arr(i) Next End Sub
GetFolderPathAll
メソッドの返り値は、配下の各フォルダパスが「>
」によって数珠つなぎにされた長~い文字列なので、Split
で区切って配列化し、それを一つづつ取り出してイミディエイトに書き出します。
実行結果
ほれ、この通り。
バッチリ!
おわりに
長らくDir
関数なんて使いませんでしたが、良い復習になりました。
今回作成したFunction、作った自分でも理解が追いついていないところがあるので、誰か解説よろしくお願いします。
組み込み定数(列挙体)を自作(?)しておく
組み込み定数(列挙体)を自作(?)しておく
CreateObject派への転向
実は、だいぶ前からCreateObject
派に転向しておりました。
やっぱり、参照設定せずに使えるってのはいいよね、ということで。
CreateObject派になって困ること
いろいろあると思いますが、やはり
組み込み定数(列挙体)が使えねえ!
これに尽きるのではないでしょうか。(異論は認めます。)
なかったら、作ればいいじゃない
そこで、私は、よく使う組み込み定数(列挙体)を自作し(というか、パクッ)ています。
これまでにパクッ完コピした組み込み定数(列挙体)
代表的なものをいくつか紹介します。
基本的に、クラスモジュールとかの中に封印してしまうことが多いのでPrivate
指定ですが、Public
メソッドなんかの引数にするときには、適宜Public
指定に変えてやればいいと思います。
ADODB関係
ADODB.Stream
オブジェクトを扱うときによく使うやつです。
StreamTypeEnum列挙体
Private Enum StreamTypeEnum adTypeBinary = 1 adTypeText = 2 End Enum
SaveOptionsEnum列挙体
Private Enum SaveOptionsEnum adSaveCreateNotExist = 1 'ファイルがあるとき上書きしない' adSaveCreateOverWrite = 2 'ファイルがあるとき上書きする' End Enum
StreamReadEnum列挙体
Private Enum StreamReadEnum adReadAll = -1 adReadLine = -2 End Enum
StreamWriteEnum列挙体
Private Enum StreamWriteEnum adWriteChar = 0 adWriteLine = 1 End Enum
Scripting.FileSystemObject関係
IOMode列挙体
Private Enum IOMode ForReading = 1 ForWriting = 2 ForAppending = 8 End Enum
Tristate列挙体
Private Enum Tristate TristateFalse = 0 TristateTrue = -1 TristateUseDefault = 2 End Enum
おわりに
こんなふうに、代表的な組み込み定数(列挙体)を自作(?)しておけば、たとえばScripting.FileSystemObject
オブジェクトを利用するコードを書いたときに、参照設定していなくても、たとえば次のように読んで意味がわかるように書くことができます。
Set m_TextStream = m_FSO.OpenTextFile(FileName:=a_Path, _ IOMode:=ForReading, _ Create:=True, _ Format:=a_CharCode)
OpenTextFile
メソッドの引数「IOMode
」のところ、IOMode:=1
とか書かれていても、何のことかわからんでしょう?
完コピ自体は、オブジェクト ブラウザー様を見たら誰でもできるので、CreateObject
派の人は、Enum集を作っておけばいいのではないでしょうか。
WordでMarkdownっぽいことをするマクロ(Word)
WordでMarkdownっぽいことをするマクロ(Word)
やりたいこと
- 先頭に
#
を付けた段落には、「#
」の数に応じた階層の「見出し」スタイルを当てる。 - その他の「標準」スタイルの段落には、「本文」のスタイルを当てる。
こういうことがしたい。
仕事柄、文章の資料を作成することが多い。下書き段階ではテキストエディタでぐりぐり書いていきたいのだが、見出しとかの表現がmachine-readableでなくていまいちだった。
「だったら、Markdown的に書けるようにしたらいいんじゃね?」と思って、冗談半分で作り始めたのがきっかけ。
今ではいろんな表現に対応した立派な〝インチキMarkdownマクロ〟になり、非常に重宝しているのだが、今回は「見出し」だけに対応した簡易ヴァージョンをご紹介、というわけ。
こんなコード
Document
オブジェクトを渡したら、その配下のParagraphs
コレクションの要素であるParagraph
オブジェクトを一つづつ調べ、先頭に「#
」があったら「#
」の数に応じた「見出し」スタイルを、先頭に「#
」がなくて、なおかつ「標準」スタイルの段落なら、「本文」用のスタイルを当てる、というもの。
さっそくコードをお示ししよう。
リスト1
Public Sub SetHeaderStyle(ByVal a_Document As Document) Dim tgtDoc As Document Set tgtDoc = a_Document Dim tgtPara As Paragraph Dim tmpLen As Long Dim tmpStr As String Dim i As Long Dim j As Long For Each tgtPara In tgtDoc.Paragraphs With tgtPara With .Range '「#」で始まらない段落は飛ばす。' If .Characters.Item(1).Text <> "#" Then GoTo Continue tmpLen = Len(.Text) - 1 '改段落文字分を引く。' '2文字未満なら見出しのわけがないので飛ばす' If tmpLen < 2 Then GoTo Continue '見出しレベル9でも10字にしかならないので最大10字で切る。' If tmpLen > 10 Then tmpLen = 10 tmpStr = Left(.Text, tmpLen) '「# 」が含まれていなかったら飛ばす。' If InStr(1, tmpStr, "# ") < 1 Then GoTo Continue '先頭が〈「#」の連続+半角スペース〉になっていたら見出し。' For i = tmpLen To 2 Step -1 '……(*)' If Left(tmpStr, i) = String(i - 1, "#") & " " Then tgtPara.Style = "見出し " & CStr(i - 1) For j = i To 1 Step -1 Call .Characters.Item(j).Delete Next End If Next End With End With Continue: '見出しでない標準スタイルの段落には本文字下げスタイル。' If tgtPara.Style = "標準" Then tgtPara.Style = "My本文字下げ1" '……(**)' End If Next End Sub
だいたい見ての通りなので、説明は省略。
ただし、「(*)
」のところだけ簡単に説明しておく。
For i = tmpLen To 2 Step -1 '……(1)' If Left(tmpStr, i) = String(i - 1, "#") & " " Then '……(2)' tgtPara.Style = "見出し " & CStr(i - 1) '……(3)' For j = i To 1 Step -1 '……(4)' Call .Characters.Item(j).Delete Next End If Next
まず、(1)の
For i = tmpLen To 2 Step -1
では、段落先頭から最大10まで(段落の文字数が、改段落マークを除いて10字未満なら、10よりも小さな数になる。)の数値を表す変数tmpLen
を1
づつ減じながらループする。
(2)の
If Left(tmpStr, i) = String(i - 1, "#") & " " Then
で、tmpStr
に入っている文字列(段落先頭からtmpLen
字分切り取った文字列。)を先頭からi
字分切り取った文字列を調べる。
たとえば、i
が4
のときに、tmpStr
の先頭i
文字、つまり先頭4字が「###
」(#
3個と半角スペース)だったら、見出しレベル3を適用すれば良いことになる。
(2)の条件式がTrue
になると、(3)の
tgtPara.Style = "見出し " & CStr(i - 1)
で、当該の段落に「見出し」スタイルを適用する。
先の例でいうと、i
が4
のときには、見出しレベル「3
」を適用するのだから、"見出し " & CStr(i - 1)
とすれば、めでたく「見出し 3」という文字列を組み立てることができる。
あとは、(4)からの3行、
For j = i To 1 Step -1 '……(4)' Call .Characters.Item(j).Delete Next
で、見出しであることを表す「# 」を削除する。
コレクションの要素を削除すると、自動でインデックスが繰り上がる仕様なので、こうしないとおかしなことになる。
「削除はケツから!」は常識中の常識である!
ちなみに、(**)
の
If tgtPara.Style = "標準" Then tgtPara.Style = "My本文字下げ1" End If
のところに出てくる「My本文字下げ1
」というのは、私が勝手に作ったスタイルの名前。めちゃくちゃダサい名前にしてしまって、激しく後悔している。
使ってみる
原稿をテキストエディタで作って、Wordに貼り付ける。
次のリスト2を実行する。
リスト2
Private Sub test01() Dim tgtDoc As Document Set tgtDoc = ActiveDocument Call SetHeaderStyle(tgtDoc) End Sub
すると、一瞬で
こうなる。
ナビゲーション ウインドウも
この通り!
バッチリである!
おわりに
このほか、アンダーライン、太字強調、傍点、ルビ、引用、箇条書きに対応済み(ただし、箇条書きは1階層にしか対応していません。)なのですが、めちゃくちゃ便利です。
今回ご紹介した「見出し」対応だけでも十分便利だと思います。
段落罫線を気軽に追加する(Word)
段落罫線を気軽に追加する
段落罫線を追加するのはめんどくさい
文書に区切りの線を入れたいときがある。
たとえば、
こいつを、
こんなふうにしたいときである。
(あ。「そんなもん、ハイフン三つ連チャンで入力したらいいじゃねえか。タコ!」というツッコミはなしね。それでうまくいかなくて、段落罫線をいじるしかない場合を想定しているので。)
しかし、ただこれだけのことが異様にめんどくさい。
どのぐらいめんどくさいか、今からお目にかけよう。
「そんなもん、どーでもええわい。早よ、結論を言えや。」と言う人は、コチラをどうぞ。
段落罫線を追加する手順
段落罫線を追加する手順を示す。(各手順のカッコ内は、最低限必要なクリックの数/累計クリック数。)
まず、「デザイン」タブをクリックする。(1回/1回)
「ページ罫線」をクリックする。(1回/2回)
「罫線」タブをクリックする。(1回/3回)
「設定対象」ドロップダウンを展開し、「段落」を選択する。(2回/5回)
罫線の位置を設定し、[オプション]ボタンをクリックする。(2回/7回)
(線種や色、太さはデフォルトのまま、という場合。当然、これらを設定するとクリック数は増える。)
段落から罫線への距離を設定して、[OK]ボタンをクリックする。(1回/8回)
(もちろん、段落から罫線への距離をスピンボタンをクリックして設定すると、その回数に応じてクリック数は増える。画像だと「下」を「5」にしているので、4回クリックすることになる。)
で、最後に「線種とページ罫線と網かけの設定」ダイアログボックスの[OK]ボタンをクリックすることになるので、最低でも実に9回もクリックをしないと、段落罫線一つ追加できないのである。(段落から罫線への距離をデフォルトのままにしたら7回。)
これはめちゃくちゃめんどくさい。
そこで、VBAの出番なのである!
段落罫線を追加するFunction
次のようなFunctionを作った。
リスト1
Public Sub AddParagraphBorder( _ ByVal a_Paragraph As Paragraph, _ ByVal a_BorderType As WdBorderType, _ Optional ByVal a_LineStyle As WdLineStyle = wdLineStyleSingle, _ Optional ByVal a_LineWidth As WdLineWidth = wdLineWidth050pt, _ Optional ByVal a_Color As WdColor = wdColorAutomatic, _ Optional ByVal a_DistanceFrom As Long = 1) Dim tgtPara As Paragraph Set tgtPara = a_Paragraph 'a_DistanceFromが負の数だったら、「1」にする' Dim distPts As Long If a_DistanceFrom < 0 Then distPts = 1 Else distPts = a_DistanceFrom End If '元の罫線情報を取得しておく' With tgtPara.Borders '罫線への距離' Dim distTop As Long: distTop = .DistanceFromTop Dim distBottom As Long: distBottom = .DistanceFromBottom Dim distLeft As Long: distLeft = .DistanceFromLeft Dim distRight As Long: distRight = .DistanceFromRight '罫線の種類・太さ・色' With .Item(wdBorderTop) Dim topStyle As WdLineStyle: topStyle = .LineStyle Dim topWidth As WdLineWidth: topWidth = .LineWidth Dim topColor As WdColor: topColor = .Color End With With .Item(wdBorderBottom) Dim bottomStyle As WdLineStyle: bottomStyle = .LineStyle Dim bottomWidth As WdLineWidth: bottomWidth = .LineWidth Dim bottomColor As WdColor: bottomColor = .Color End With With .Item(wdBorderLeft) Dim leftStyle As WdLineStyle: leftStyle = .LineStyle Dim leftWidth As WdLineWidth: leftWidth = .LineWidth Dim leftColor As WdColor: leftColor = .Color End With With .Item(wdBorderRight) Dim rightStyle As WdLineStyle: rightStyle = .LineStyle Dim rightWidth As WdLineWidth: rightWidth = .LineWidth Dim rightColor As WdColor: rightColor = .Color End With End With '指定された罫線の形態を上書きする' Select Case a_BorderType Case wdBorderTop topStyle = a_LineStyle: topWidth = a_LineWidth topColor = a_Color: distTop = distPts Case wdBorderBottom bottomStyle = a_LineStyle: bottomWidth = a_LineWidth bottomColor = a_Color: distBottom = distPts Case wdBorderLeft leftStyle = a_LineStyle: leftWidth = a_LineWidth leftColor = a_Color: distLeft = distPts Case wdBorderRight rightStyle = a_LineStyle: rightWidth = a_LineWidth rightColor = a_Color: distRight = distPts End Select '罫線の形態を再セットする' With tgtPara.Borders .DistanceFromTop = distTop .DistanceFromBottom = distBottom .DistanceFromLeft = distLeft .DistanceFromRight = distRight With .Item(wdBorderTop) If topStyle = wdLineStyleNone Then Else .LineStyle = topStyle: .LineWidth = topWidth .Color = topColor End If End With With .Item(wdBorderBottom) If bottomStyle = wdLineStyleNone Then Else .LineStyle = bottomStyle: .LineWidth = bottomWidth .Color = bottomColor End If End With With .Item(wdBorderLeft) If leftStyle = wdLineStyleNone Then Else .LineStyle = leftStyle: .LineWidth = leftWidth .Color = leftColor End If End With With .Item(wdBorderRight) If rightStyle = wdLineStyleNone Then Else .LineStyle = rightStyle: .LineWidth = rightWidth .Color = rightColor End If End With End With End Sub
こんな感じ。説明はめんどくさいから省略。
簡単に手順だけ示しておく。
- 元の段落罫線の状態を取得
- 引数で渡された箇所の罫線情報だけ上書きする
たったこれだけ。
こんなにカンタンになりました
カーソルのある段落の下に5ポイント離して罫線を引くマクロを作る。
リスト2
Public Sub AddParagraphBottomBorder() Dim tgtDoc As Document Set tgtDoc = ActiveDocument Dim tgtPara As Paragraph Set tgtPara = tgtDoc.Paragraphs( _ ParagraphUtil.GetParagraphIndex(Selection.Range)) Call ParagraphUtil.AddParagraphBorder(tgtPara, wdBorderBottom, _ wdLineStyleSingle, _ wdLineWidth050pt, _ wdColorAutomatic, 5) End Sub
ちなみに、上掲コード中のGetParagraphIndex
は、標準モジュールParagraphUtil
内に書いた自作のメソッド。
一応、そのコードも載っけておく。
リスト3
Public Function GetParagraphIndex( _ ByVal a_Target As Range) As Long Dim ret As Long Dim rng As Range Set rng = a_Target rng.Start = 0 ret = rng.Paragraphs.Count Dim pos As Long pos = rng.End 'カーソルが全体の先頭にあるときは pos - 1 でエラーになる' If pos = 0 Then GoTo ReturnValue Dim char As String char = rng.Parent.Range(pos - 1, pos).Text '直前が改段落マークのときはカーソルが段落の先頭にある' If char = Chr(13) Then ret = ret + 1 End If ReturnValue: GetParagraphIndex = ret End Function
要するに、
こいつの修正版。ちょっとぶさいくな修正結果だが。(エレガントな方法を知っている人がいたら教えろえてください。)
リスト2のマクロをクイック アクセス ツール バーに登録して、実行した様子が、
コチラ。
楽勝!
おわりに
こういう、〝通常の操作がメンドクサイやつをマクロ化する〟というのが、Wordの場合のVBAの使いどころなんじゃないかなあ、と思い始めています。
カーソルが段落の先頭にあると正しい段落インデックスが取得できない(Word)
カーソルが段落の先頭にあると正しい段落インデックスが取得できない
[Range].Startプロパティと[Range].[Paragraphs].Countプロパティを用いる方法
Range
オブジェクトの終端がある段落インデックスを取得する方法は、かつて
で紹介したことがある。
簡単に言うと、
Range
オブジェクトのStart
プロパティを強引に「0
」にすることにより、Range
オブジェクトの始端をドキュメントの先頭にしてRange
オブジェクトを拡張。その中のParagraphs
コレクションの数(Count
プロパティで取得可能)を勘定する
というやり方である。
当時は、脳天気に「最初にこのアイディアを考えついたやつは天才だと思う。」などと喜んでいたものだ。
落とし穴があった!
ところが、「上手の手から水が漏る」のことば通り、先の方法には落とし穴があったのである!
落とし穴をお目にかけよう。
この通り、どう見てもカーソルは第4段落の先頭にある。したがって、Selection.Range
が返すRange
オブジェクトは、第4段落の先頭を指し示すのである。
しかし!
リスト1
Public Function GetParagraphIndex( _ ByVal a_Target As Range) As Long Dim ret As Long a_Target.Start = 0 ret = a_Target.Paragraphs.Count GetParagraphIndex = ret End Function
このGetParagraphIndex
メソッドに、Selection.Range
を渡して実行すると、
この通り、「3
」が返る〔*〕のである!
これでは全然だめである!
*
GetParagraphIndex
メソッドは、Normal.dotm
プロジェクトの標準モジュールParagraphUtil
に書いてあるので、このような呼び出し方になっている。
検証:なんでこうなるのか
先のリスト1に、次の1行を付け加える。
リスト2
Public Function GetParagraphIndex( _ ByVal a_Target As Range) As Long Dim ret As Long a_Target.Start = 0 Call a_Target.Select '……(*)' ret = a_Target.Paragraphs.Count GetParagraphIndex = ret End Function
a_Target
のStart
プロパティを「0」にした直後、つまりa_Target
の始端をドキュメントの先頭まで拡張した直後に、Select
メソッドを実行して止めてみる。
確かに、第3段落目までしか選択されていない。
道理で「3
」が返るわけである。
検証終わり。
おわりに
というわけで、カーソルが段落の先頭にある場合にも正しい段落インデックスを返すように、改修する必要があります。
いちおう、改修自体はしているのですが、なんとも不細工なやり方で、もっとスマートな方法はないものか、と思っています。
〈カーソルが段落先頭にあることを判定するスマートな方法〉を知っていたら教えろえてください。
RemovePersonalInformationプロパティというものがある(Word)
RemovePersonalInformationプロパティというものがある
結論だけ知りたければ、コチラをどうぞ。
前回の方法
文書の「作成者」とか「最終更新者」の情報を消す方法として、前回は、
こういう方法を紹介した。
しかし、これもあまり良い方法ではなかった。
たとえば、
こういうドキュメント(笑)があったとする。
ぱっと見はわからないが、実はこのドキュメントは、表題のところに
このように「タイトル」という文書情報(ドキュメントプロパティ)を「挿入」している。(で、「ヘッダー」のところにも同じように「タイトル」を「挿入」しているので、表題を変えたら「ヘッダー」も連動して変わるようになっている。
で、文書情報を見ると、
このとおり。非常に恥ずかしい状態である!
ここで、前回の方法を用いる。
リスト1
Private Sub test() Dim tgtDoc As Document Set tgtDoc = ActiveDocument Call tgtDoc.RemoveDocumentInformation(wdRDIDocumentProperties) End Sub
こいつを実行してやる。
すると、当然、
文書情報は消えている。
しかし!
おわかりだろうか。
「タイトル」という文書情報を挿入していた箇所が、ただの文字列に置き換わってしまっているのである!
これはいかん!
タンザニアのイカンガーである!
RemovePersonalInformationプロパティ
さて。
そうこうしているうちに、[Document].RemovePersonalInformation
というプロパティを見つけた。
有名なのだろうか。
ぐぐってみた。
Document.RemovePersonalInformation プロパティ (Word)
True 場合は、Microsoft Word は、コメント、変更履歴、およびドキュメントの保存時に [プロパティ] ダイアログ ボックスからすべてのユーザー情報を削除します。 読み取り/書き込みが可能な Boolean です。
『Office VBA リファレンス』
なるほど。これなら日本語版でも意味がわかる。
やってみよう。
あっさり解決
リスト2
Private Sub test() Dim tgtDoc As Document Set tgtDoc = ActiveDocument tgtDoc.RemovePersonalInformation = True End Sub
こいつを、先のドキュメント(笑)をアクティヴにして実行!
(゚Д゚)ハァ?
上書き保存をしてやると、
ほれ、このとおり。
挿入した「タイトル」も生きておる!
ずばっと解決してしまった。
もちろん、これは真の解決ではないであろう。
旅はまだまだ続く……。
未完!
おわりに
とりあえず、
こいつも、早くも役目を終えてしまった。
用なし。
諸行無常!
RemoveDocumentInformationメソッドというものがある(Word)
RemoveDocumentInformationメソッドというものがある
RemoveDocumentInformationメソッド
知らなかった。
Document
クラスのメンバ一覧を「オブジェクト ブラウザー」様で見ていて見つけた。
有名なのだろうか……。
使ってみる
例によって、私がマイPCで文書を作成すると、
ドキュメントの「情報」として、非常に恥ずかしい情報がクレジットされてしまっている。
このドキュメントをアクティヴにした状態で、次のリスト1を実行してみる。
リスト1
Private Sub test() Dim tgtDoc As Document Set tgtDoc = ActiveDocument Call tgtDoc.RemoveDocumentInformation(wdRDIDocumentProperties) End Sub
すると、どうなるか。
実行結果
こうなるのである!
おわりに
[Document].RemoveDocumentInformation
メソッドの引数には、WdRemoveDocInfoType
列挙体のメンバを渡す。
今回は、「wdRDIDocumentProperties
」を渡したのだが、メンバの中には、他にも「 wdRDIRemovePersonalInformation
」など、非常に気になる名前のものがある。
こういうものも、今後きちんと調べておくべきだろう。
というわけで、早くも
コイツは役目を終えたのである!
諸行無常!
追伸
ちなみに、このたびの〝発見〟は、和風スパゲティのレシピ氏からのインスパイヤのおかげです。
VBA初心者のみなさん! あるていど「オブジェクト」とか「プロパティ」ということばの意味がわかってきたら、「オブジェクト ブラウザー」様でいろんなクラスのメンバ一覧を眺めてみましょう! きっと、大発見がありますよ!
たぶん、次のフレーズの意味がわかるようになったときが、「オブジェクト ブラウザー」様を眺めてみる一つの契機かも。
Worksheet
オブジェクトのRange
プロパティがRange
オブジェクトを返す。
昔は、これ、何言ってんのか全然わかりませんでした。