開くブックをユーザーに選択してもらう場合は、[ファイルを開く]ダイアログボックスを表示するといいでしょう。
Sub Sample1() Dim OpenFileName As String OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") Workbooks.Open OpenFileName End Sub
[ファイルを開く]ダイアログボックスを表示するには、ApplicationオブジェクトのGetOpenFilenameメソッドを使います。GetOpenFilenameメソッドによる[ファイルを開く]ダイアログボックスは、ユーザーが選択したファイルのフルパスを返すだけで、自動的には開きません。GetOpenFilenameメソッドの書式は次の通りです。
GetOpenFilename FileFilter, FilterIndex, Title, ButtonText, MultiSelect
引数については、下記で解説します。
[ファイルを開く]ダイアログボックスに、どんな種類(拡張子)のファイルを表示するかは、引数FileFilterで指定します。上記のサンプルでは
"Microsoft Excelブック,*.xls?"
と指定しました。もちろん「FileFilter:="Microsoft Excelブック,*.xls?"」と指定しても同じです。両者の違いに関しては、下記のページを参考にしてください。
引数FileFilterには
の2つをセットで指定します。
複数の拡張子を表示したいときは、表示したい拡張子をセミコロン(;)で区切ります。
上のように、複数の拡張子をまとめて表示するのではなく、[ファイルの種類]に複数の拡張子を登録するには、登録したい数だけ「任意の文字列,拡張子」のセットを指定します。
引数FileFilterの注意点
正:"Microsoft Excelブック,*.xls?"
誤:"Microsoft Excelブック", "*.xls?"
引数Fileterには拡張子しか指定できません。たとえば
"Microsoft Excelブック,Book*.xls?"
のように「Bookで始まる」という意味のワイルドカードを指定しても機能しません。どうしても「○○で始まる」や「○○を含む」ファイル群を表示したいのでしたら、これはもうGetOpenFilenameメソッドではできませんので、下記のページを参考にしてください。
[ファイルを開く]ダイアログボックスで、ユーザーが[キャンセル]ボタンをクリックすると、GetOpenFilenameメソッドはFalseを返します。なので、ユーザーが[キャンセル]ボタンをクリックしたかどうかは、次のように判定します。
【受け取る変数が文字列型(String)の場合】
Sub Sample2() Dim OpenFileName As String OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") If OpenFileName <> "False" Then Workbooks.Open OpenFileName Else MsgBox "キャンセルされました" End If End Sub
【受け取る変数がバリアント型(Variant)の場合】
Sub Sample2() Dim OpenFileName As Variant OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") If OpenFileName <> False Then Workbooks.Open OpenFileName Else MsgBox "キャンセルされました" End If End Sub
文字列型(String)で「If OpenFileName <> False」や、バリアント型(Variant)で「If OpenFileName <> "False"」としても判定できますが、これはVBAが内部で自動型変換をしてくれているからです。文字列型は文字列で、バリアント型は論理値で判定するのが、理にかなってます。
何のファイルも選択しないで[開く]ボタンをクリックしても、何も起こりません。なので「[キャンセル]ボタンがクリックされたことと、空白のまま[開く]ボタンがクリックされたこと」を判定する必要はありません。てか、そういう状況は起こりません。
では、もしユーザーが、ファイルを選択するのではなく、[ファイル名]ボックスに任意のファイル名を入力したらどうでしょう。しかも、そのファイル名が間違っていたら・・・
大丈夫です。GetOpenFilenameメソッドが、うまくやってくれます。
ただし、下記で解説するような「複数ファイルが選択可能」なダイアログボックスでは、[キャンセル]ボタンがクリックされたときの判定が異なります。詳しくは下記をご覧ください。
GetOpenFilenameメソッドを実行して開いた[ファイルを開く]ダイアログボックスでは、カレントフォルダが表示されます。なので、任意のフォルダを開きたいときは、GetOpenFilenameメソッドを実行する前に、カレントフォルダを移動してやります。次のコードは、CドライブのWorkフォルダを表示します。
Sub Sample3() Dim OpenFileName As String ChDrive "C" ChDir "C:\Work" OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") If OpenFileName <> "False" Then Workbooks.Open OpenFileName Else MsgBox "キャンセルされました" End If End Sub
ChDriveステートメントは、カレントフォルダを移動するコマンドです。ただし、ドライブを割り当てていない「\\OtherPC\~」のようなUNCには移動できません。ネットワークパスに移動する方法は、下記のページを参考にしてください。
GetOpenFilenameメソッドの返り値は「E:\Work\Book1.xlsx」のようにパス名を含んだファイル名です。これは、そのままファイルを開くときなどには便利ですが、ときにはパスを除いた純粋なファイル名を使いたい場合もありますし、逆にファイル名を除いたパスだけが欲しいときもあります。GetOpenFilenameメソッドが返すフルパスのファイル名から、パスとファイル名を分離する方法を解説します。なお、ここでは「E:\Work\Book1.xlsx」が選択されたものとします。
まず、パスを除いたファイル名(ここでは、Book1.xlsx)を取得するには、どうしたらいいでしょう。簡単です。Dir関数を使えばいいんです。Dir関数は、引数に指定したファイルが存在するとき、そのファイル名を返します。そのとき、パスは含まれません。
Sub Sample4() Dim OpenFileName As String, FileName As String OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") If OpenFileName <> "False" Then FileName = Dir(OpenFileName) MsgBox FileName Else MsgBox "キャンセルされました" End If End Sub
さて、フルパス「E:\Work\Book1.xlsx」から「Book1.xlsx」を取得できました。では、パス部分の「E:\Work\」を得るにはどうしたらいいでしょう。こちらも簡単です。「E:\Work\Book1.xlsx」から「Book1.xlsx」を消せばいいんです。任意の文字列から、ある文字を消すには・・・そう、Replace関数ですね。
Sub Sample5() Dim OpenFileName As String, FileName As String, Path As String OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") If OpenFileName <> "False" Then FileName = Dir(OpenFileName) Path = Replace(OpenFileName, FileName, "") MsgBox Path Else MsgBox "キャンセルされました" End If End Sub
ちなみに、FileSystemObjectを使う手もあります。
Sub Sample6() Dim OpenFileName As String, FileName As String, Path As String OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?") If OpenFileName <> "False" Then With CreateObject("Scripting.FileSystemObject") FileName = .GetFile(OpenFileName).Name Path = .GetFile(OpenFileName).ParentFolder End With MsgBox FileName & vbCrLf & Path Else MsgBox "キャンセルされました" End If End Sub
[ファイルを開く]ダイアログボックスで、複数のファイルを選択するには、引数MultiSelectにTrueを指定します。
Sub Sample7() Dim OpenFileName As Variant OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls?", _ MultiSelect:=True) If IsArray(OpenFileName) Then ''選択されたファイルへの処理 Else MsgBox "キャンセルされました" End If End Sub
今までは「GetOpenFilename("Microsoft Excelブック,*.xls?")」と書いてきましたが、今度は「GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls?")」としました。その理由は、下記のページを参考にしてください。
さて、注目すべきは、GetOpenFilenameメソッドの返り値を受け取る変数の型です。複数ファイルを選択可能にしたときは、受け取る変数をバリアント型(Variant)で宣言します。これは、複数ファイルを選択可能にしたGetOpenFilenameメソッドは配列を返すからです。さらに、[キャンセル]ボタンがクリックされたときには、今度は配列ではなくFalseを返します。つまり「配列と論理値(False)」を格納できる変数でないと困ります。だからバリアント型です。
ということは、変数OpenFileNameが配列だったらファイルが選択されたということで、変数FileSystemObjectが配列でなかったら[キャンセル]ボタンがクリックされたということです。変数OpenFileNameが配列かどうかを判定するには、IsArray関数を使います。
さて、ユーザーがファイルを選択して[開く]ボタンをクリックすると、選択したファイルが配列で返ります。たとえ1つしか選択しなかったとしてもです。配列のデータを個別に取り出すには、For Eachステートメントを使います。もし、選択されたすべてのブックを開くなら、次のようにします。
Sub Sample7() Dim OpenFileName As Variant, Target As Variant OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls?", _ MultiSelect:=True) If IsArray(OpenFileName) Then For Each Target In OpenFileName Workbooks.Open Target Next Target Else MsgBox "キャンセルされました" End If End Sub
For Eachステートメントの制御変数(ここではTarget)は、バリアント型で宣言します。As Workbookとしてはいけませんよ。For Eachに指定した配列OpenFileNameには文字列が入っているのですから。かといって、As Stringもダメです。For Eachの制御変数には、オブジェクト型かバリアント型しか使えないからです。なので、ここはバリアント型です。