ユーザが選択したファイル名を取得する(4)

ユーザが選択したファイル名を取得する

前回までの三回

akashi-keirin.hatenablog.com

akashi-keirin.hatenablog.com

akashi-keirin.hatenablog.com

で、ユーザにファイルを選ばせるところまでたどり着いた。

いよいよ、選択させたファイルのフルパスを取得するときがきた。

まさに

時は来た! それだけだ!

状態である。

Showメソッド実行後

FileDialog.Showメソッドを実行すると、ダイアログボックスが表示される。これは前回までに記した通り。

問題は、Showメソッド実行後に何が起こるか、である。

みんな大好き、オブジェクト ブラウザーで見てみよう。

f:id:akashi_keirin:20190922075354j:plain

おわかりだろうか。

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

としてやれば、ファイルが選択されていたら(ファイルを選択せずに[開く]をクリックしても何も起きないので、)isSelectedTrueになり、[キャンセル]したり、[×]ボタンでボックスを閉じたりした場合には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プロパティの返り値を突っ込んでおく。

これで、fileNamesStringコレクションとして扱うことができる。

あとは、(3)の

Dim i As Long
For i = 1 To fileNames.Count
  Debug.Print fileNames(i)
Next

fileNamesの要素を一つづつ取り出すしてイミディエイトに表示。

実行

f:id:akashi_keirin:20190922075359g:plain

こんなふうに操作すると、

イミディエイトに

f:id:akashi_keirin:20190922075357j:plain

選択したファイルのフルパスが列挙された。

おわりに

リスト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

の過程が必要ないことも十分承知の上です。

ちゃっちゃと済ませるつもりが、異様に長くなってしまった……。