ユーザが選択したファイル名を取得する
前回までの三回
で、ユーザにファイルを選ばせるところまでたどり着いた。
いよいよ、選択させたファイルのフルパスを取得するときがきた。
まさに
時は来た! それだけだ!
状態である。
Showメソッド実行後
FileDialog.Showメソッドを実行すると、ダイアログボックスが表示される。これは前回までに記した通り。
問題は、Showメソッド実行後に何が起こるか、である。
みんな大好き、オブジェクト ブラウザーで見てみよう。

おわかりだろうか。
Function Show() As Long
と書いてある。
Subではなく、Functionなんである。
これまたみんな大好き、Office デベロッパー センターで見てみよう。FileDialog.Show Methodの項によると、
Displays a file dialog box and returns a Long indicating whether the user pressed the Action button (-1) or the Cancel button (0).
『ODC』「FileDialog.Show Method」の項より
[Action]ボタン(日本語版だと、デフォルトでは[開く]ボタン)がクリックされたか、[Cancel]ボタン(同[キャンセル]ボタン)がクリックされたかに応じてLong型の値を返す、ということらしい。
[開く]だと「-1」が返り、[キャンセル]だと「0」が返る。(ボックスの[×]をクリックして閉じた場合も「0」が返る。)
VBAの場合、「-1」はTrueを意味するので、たとえばBoolean型の変数isSelectedを用意して、
isSelected = [FileDialog].Show
としてやれば、ファイルが選択されていたら(ファイルを選択せずに[開く]をクリックしても何も起きないので、)isSelectedがTrueになり、[キャンセル]したり、[×]ボタンでボックスを閉じたりした場合にはFalseが返る。
つまり、Showメソッドの返り値を調べることでファイル名取得の成否がわかる。従って、Showメソッドの返り値によってその後の処理を分岐すれば良い。
SelectedItemsプロパティを使う
再びみんな大好き、Office デベロッパー センターで見てみよう。FileDialog.SelectedItems propertyの項によると、
Gets a FileDialogSelectedItems collection. This collection contains a list of the paths of the files that a user selected from a file dialog box displayed by using the Show method of the FileDialog object. Read-only.
同「FileDialog.SelectedItems property」の項より
Showメソッドを実行すると、FileDialog.SelectedItemsプロパティを参照することによって、ユーザが選択したファイルのパスのリストをFileDialogSelectedItemsオブジェクトの形で取得することができる。
みたびみんな大好き、Office デベロッパー センターで見てみよう。FileDialogSelectedItems objectの項によると、
A collection of String values that correspond to the paths of the files or folders that a user has selected from a file dialog box displayed through the FileDialog object.
同「FileDialogSelectedItems object」の項より
つまり、ユーザが選んだファイルパスが詰まったFileDialogSelectedItemsオブジェクトの正体は、String型のコレクションなのである。
ついに、準備が整った! まさに、
時は来た! それだけだ!状態!!!!!!!!
胸熱!!!!!!!!!!
選択したファイル名を取得する
やってみよう。
リスト1
Private Sub test05()
Dim fpDialog As FileDialog
Set fpDialog = Application.FileDialog(msoFileDialogFilePicker)
With fpDialog
.AllowMultiSelect = True
.InitialFileName = "D:\Music\DEF LEPPARD"
Call .Filters.Add("FLACファイル", "*.flac")
Dim isSelected As Boolean '……(1)'
isSelected = .Show
If Not isSelected Then Exit Sub
Dim fileNames As FileDialogSelectedItems '……(2)'
Set fileNames = .SelectedItems
Dim i As Long '……(3)'
For i = 1 To fileNames.Count
Debug.Print fileNames(i)
Next
End With
End Sub
(1)からの
Dim isSelected As Boolean isSelected = .Show If Not isSelected Then Exit Sub
Showメソッドの返り値を調べ、ファイル名が取得できていなければ即Exit。
ここを乗り越えたら、何らかのファイル名が取得できているということなので、(2)の
Dim fileNames As FileDialogSelectedItems Set fileNames = .SelectedItems
で、FileDialogSelectedItems型の変数fileNamesを用意して、SelectedItemsプロパティの返り値を突っ込んでおく。
これで、fileNamesをStringコレクションとして扱うことができる。
あとは、(3)の
Dim i As Long For i = 1 To fileNames.Count Debug.Print fileNames(i) Next
でfileNamesの要素を一つづつ取り出すしてイミディエイトに表示。
実行

こんなふうに操作すると、
イミディエイトに

選択したファイルのフルパスが列挙された。
おわりに
リスト1の、
Dim fpDialog As FileDialog Set fpDialog = Application.FileDialog(msoFileDialogFilePicker) With fpDialog
のところは、
With Application.FileDialog(msoFileDialogFilePicker)
と1行で書くことができるし、
Dim fileNames As FileDialogSelectedItems Set fileNames = .SelectedItems Dim i As Long For i = 1 To fileNames.Count Debug.Print fileNames(i) Next
のところも
Dim i As Long For i = 1 To .SelectedItems.Count Debug.Print .SelectedItems(i) Next
と書けば短く済むことはわかっています。
それでも、一旦オブジェクトを変数に突っ込んだのは、「オブジェクトを利用している」意識を持つため。
初学者のうちは、むやみやたらとコードを短くするよりも、プログラムの挙動を丁寧に追うことができるような書き方をする方が大切だと思うのです。
実際、フォルダやファイルのパスをユーザに選ばせる処理は初心者の頃からよく書いていたので、FileDialogオブジェクトもしょっちゅう利用していたのですが、たとえば
With Application.FileDialog(msoFileDialogFilePicker)
の意味(何をしているのか)が全然わかっていませんでした。
これを、
ApplicationオブジェクトのFileDialogプロパティに引数msoFileDialogFilePickerを渡したらFileDialogオブジェクトが返るから、「Application.FileDialog(msoFileDialogFilePicker)」がFileDialogオブジェクトを指し示すことになる。そいつで括っているのだ。
ということがちゃんと意識できていなかったのです。
こういうことをきちんと理解するためにも、初心者向けのサンプルコードほど、丁寧な書き方をするべきだと思ったのですが、いかがでしょうか。
あと、ファイル名取得前にSelectedItems.Countを参照しても0を返すだけで別にエラーが出るわけではないから、今回のような使用法に限っては、
Dim isSelected As Boolean isSelected = .Show If Not isSelected Then Exit Sub
の過程が必要ないことも十分承知の上です。
ちゃっちゃと済ませるつもりが、異様に長くなってしまった……。