Excel VBAでファイルダイアログを使う


# ファイルダイアログの使い方

Excelには「名前をつけて保存」「ファイルを開く」などの機能を使う際にファイルダイアログを開いてファイルを指定する機能がありますが、これをVBAから呼び出してファイル選択に使うことが出来ます。

Excelの元々の機能を呼び出すにはApplicationオブジェクトを使います。ファイルダイアログを開く機能として以下の3つが用意されています。

<b>1. Application.GetOpenFilename
2. Application.GetSaveAsFilename
3. Application.FileDialog</b>


# 1. Application.GetOpenFilename


Excelでファイルを開くときに表示されるのと同じ挙動をするファイルダイアログを表示して戻り値としてPATHを受け取ります。名前にOpenFileとかあるのでファイルを開くのかと思いますがPATHを受け取るだけで開きません。

https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.getopenfilename

引数によりファイルフィルタ、見出し文字列、複数選択可否を指定できます
<b>Allication.GetOpenFilename (FileFilter, FilterIndex, Title, ButtonText, MultiSelect)</b>


## 1-1. 引数なしで使う


引数なしで呼んだ場合、ファイルフィルタなし、見出し文字列は「ファイルを開く」、複数選択無効でActiveWorkbookがあるフォルダを開いてくれます。


```vb:ファイルフィルタなし
Dim fileToOpen As Variant

fileToOpen = Application.GetOpenFilename()
If fileToOpen <> False Then
    MsgBox "受け取ったPATH: " & fileToOpen
End If
```


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/19bd779c-5f44-51e8-c74f-f2f2682af297.png" width=50%>


## 1-2. ファイルフィルタをつけて使う


### 1-2-1. 1つの拡張子を指定する


FileFilterに文字列で与えるとカンマの手前を見出し、カンマ以降をフィルタ条件として指定した条件のファイルのみを表示するようにしてくれます。指定が適切でない場合は無視されて省略したのと同じ動作になります。


```vb:拡張子がxlsxのファイルのみ表示する
Dim fileToOpen As Variant

fileToOpen = Application _
    .GetOpenFilename(FileFilter:="Excel Files, *.xlsx")
If fileToOpen <> False Then
    MsgBox "受け取ったPATH: " & fileToOpen
End If
```


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/f7d6309f-4f99-d7c0-2c85-13afd61098f2.png" width=50%>


### 1-2-2. 複数の拡張子を指定する


セミコロンで区切って複数の拡張子を渡せば複数の拡張子を指定することも出来ます


```vb:複数の拡張子でフィルタする
Dim fileToOpen As Variant

fileToOpen = Application _
    .GetOpenFilename(FileFilter:="Excel Files, *.xls;*.xlsx;*.xlsm")
If fileToOpen <> False Then
    MsgBox "受け取ったPATH: " & fileToOpen
End If
```


### 1-2-3. 拡張子をワイルドカードで指定する


拡張子にワイルドカードを使うことも出来ます


```vb:フィルタにワイルドカードを使う
Dim fileToOpen As Variant

fileToOpen = Application _
    .GetOpenFilename(FileFilter:="Excel Files, *.xl*")
If fileToOpen <> False Then
    MsgBox "受け取ったPATH: " & fileToOpen
End If
```


### 1-2-4. ファイル名は指定できない


ファイル名を限定することは出来ませんので、以下のように書くと省略した場合と同じ動作になります


```vb:ファイル名を指定した場合
Dim fileToOpen As Variant

fileToOpen = Application _
    .GetOpenFilename(FileFilter:="Excel Files, 20211124.*")
If fileToOpen <> False Then
    MsgBox "受け取ったPATH: " & fileToOpen
End If
```


## 1-3. 見出し文字列を変更する


Titleに文字列を与えると、ファイルダイアログ左上の見出し文字列を変更できます


```vb
Dim fileToOpen As Variant

fileToOpen = Application _
    .GetOpenFilename(Title:="ここの文字列を指定できます")
If fileToOpen <> False Then
    MsgBox "受け取ったPATH: " & fileToOpen
End If
```


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/5cb1f924-f508-2da8-beb2-c7d438ab9b97.png" width=50%>


## 1-4. 複数選択できるようにする


MultiSelectをTrueにすると複数選択できるようになります。複数選択を有効にした場合、戻り値が配列になります。


```vb
Dim fileToOpen, file As Variant

fileToOpen = Application _
    .GetOpenFilename(MultiSelect:=True)
If IsArray(fileToOpen) Then
    For Each file In fileToOpen
        Debug.Print file
    Next
End If
```


# 2. Application.GetSaveAsFilename


名前をつけて保存するときに表示されるのと同じ挙動をするファイルダイアログを表示して戻り値としてPATHを受け取ります。名前にSaveAsとかあるので保存するのかと思うんですが、PATHを受け取るだけで保存はしません。


https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.getsaveasfilename


引数によりファイル名の初期値、ファイルフィルタ、見出し文字列が指定できます
<b>Application.GetSaveAsFilename (InitialFilename, FileFilter, FilterIndex, Title, ButtonText)</b>



## 2-1. 引数なしで使う


引数を省略すると、ファイル名の初期値なし、すべてのファイルを対象に表示、見出し文字列は「名前を付けて保存」となります


```vb
Dim fileSaveName As Variant

fileSaveName = Application.GetSaveAsFilename()
If fileSaveName <> False Then
    MsgBox "Save as " & fileSaveName
End If
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/c2443be7-080e-a29e-c5ca-1547c923af09.png" width=50%>


## 2-2. ファイル名の初期値を指定する


規定のファイル名を指定できます


```vb:拡張子なしで指定
Dim fileSaveName As Variant

fileSaveName = Application.GetSaveAsFilename(InitialFileName:="ここを指定できます")
If fileSaveName <> False Then
    MsgBox "Save as " & fileSaveName
End If
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/e73cac05-76d5-443e-1d7f-c9676ebbe771.png" width=50%>
ファイル名の初期値に拡張子はファイルフィルタで指定したものしか使えません。ファイルフィルタを付けていない場合は拡張子を付けて指定しても無効になりますし、ファイルフィルタを付けた場合は指定した拡張子以外を規定ファイル名にすると無効になります。


```vb:拡張子ありで指定した場合
Dim fileSaveName As Variant

fileSaveName = Application.GetSaveAsFilename(InitialFileName:="ファイル名", fileFilter:="Excel File, *.xlsm")
If fileSaveName <> False Then
    MsgBox "Save as " & fileSaveName
End If
```


## 2-3. ファイルフィルタを使う


[上で書いたのと同じですのでそちらを参照してください](#1-2. ファイルフィルタをつけて使う)


## 2-4. 見出し文字列を変更する


[上で書いたのと同じですのでそちらを参照してください](#1-3. 見出し文字列を変更する)


# 3. Application.FileDialog


上の2つより多機能なオブジェクトで使い方も少し違います

https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.filedialog


使い方は以下のようになります


```vb
Public Sub ShowFileDialog()
    Dim fd As FileDialog
    Dim selectedPaths() As String
    Dim I As Integer

    Set fd = Application.FileDialog(msoFileDialogOpen)
    With fd
        .AllowMultiSelect = True
        .FilterIndex = 2
        .Title = "Select Excel File(s)"
        .InitialFileName = "ファイル名"

        If .Show = -1 Then
            ReDim selectedPaths(1 To .SelectedItems.count)
            For I = 1 To .SelectedItems.count
                selectedPaths(I) = .SelectedItems(I)
                Debug.Print selectedPaths(I)
            Next I
        End If
        .Execute
    End With
    Set fd = Nothing
End Sub
```


上記はざっくりと以下の4ステップに分けることが出来ます

<b>1. Application.FileDialogオブジェクトをつくる
2. プロパティをいろいろ設定する
3. .Showメソッドを呼んでファイルダイアログを開く
4. .Executeメソッドでタイプに応じた動作を実行する</b>


## 3-1. FileDialogType


Application.FileDialogの引数は以下の4つから選べます

<b>msoFileDialogFilePicker:　ユーザーにファイルを選択してもらう
msoFileDialogFolderPicker:　ユーザーにフォルダーを選択してもらう
msoFileDialogOpen:　ユーザーが選んだファイルを開きます
msoFileDialogSaveAs:　ユーザーが選んだファイル名で保存します</b>

msoFileDialogOpenは.Executeで選択ファイルを開く、msoFileDialogSaveAsは.Executeで指定ファイル名で保存することが出来ます。Picker2つの場合は.Executeしようとしてもエラーになります。


## 3-2. プロパティいろいろ


内容は同じですが書き方が違います


```vb:ファイルフィルタを指定する
With Application.FileDialog(msoFileDialogOpen)
    .Filters.clear  'フィルタを一旦クリアする
    .Filters.Add "Excel2003", "*.xls"  'フィルタにxlsを追加
    .Filters.Add "Excelファイル", "*.xlsx"  'フィルタにxlsxを追加
    .Filters.Add "Excelマクロ有効", "*.xlsm"  'フィルタにxlsmを追加
    .FilterIndex = 2  'フィルタの2番目を初期値として表示
    .InitialFileName = "D:\Excel"  'ファイル名の初期値を指定
    .AllowMultiSelect = False  '複数選択の可否を指定
    If .Show = True Then
        .Execute
    End If
End With
```


## 3-3. Showメソッド


.Showするとファイルダイアログを表示して、結果を戻り値として返してくれます。キャンセルボタンを押すか、ESCキーまたは×ボタンでダイアログを閉じると戻り値が0、ファイルまたはフォルダが正常に選択された場合は戻り値が-1になるので、.Show = TrueがTrueになりますので、これを使ってキャンセルされた場合の処理を書くことができます。


## 3-4. .Executeメソッド


FileDialogType が msoFileDialogOpen または msoFileDialogSaveAs である場合は.Executeするとファイルを開く、またはファイルを保存する動作を実行します。



# まとめ


Application.FileDialogの書き方が好きですが、どれを使うのでも良さそうです

レッツトライ