Endステートメントの有効利用

Endステートメントは処理を強制終了させます。数少ない有効利用場面の解説

'全ての処理を強制終了
End

処理を強制的に終了させるには「End」ステートメントを使用します

このステートメントの使用上の注意点があります、以下の記事で解説しています

基本的にこのコードは強制終了という側面から、あまり多用すべきコードではありません

終了する場合はしっかりプロシージャの最後まで実行するべきです

ですが、それも状況次第で有効に利用できる場合があります

フォームの起動を強制終了

ユーザーフォームを起動させるには、ShowメソッドとLoadステートメントがあります

どちらも、必ずInitializeイベントを発生させます
なのでフォームの初期化処理はこのイベントに作成します

起動条件を設定したフォームの場合は注意する点があります

例えば、入力補助のフォームであれば
作業するシート以外では、フォームは表示される必要はありませんし、場合によってはバグが発生する可能性があります
そもそも使用しないシートでフォームが表示されるのも邪魔です

そんな場合には、フォームの起動時に条件分岐を行い条件に一致しない場合にはフォームを起動しないようにします

そして、通常は問題にならないこの状況が問題になるのが、初期化処理に時間が多少かかる場合です

条件分岐によりフォームを表示させないのに、待ち時間をユーザーに発生させてしまいます
シートを切り替えるたびに、数秒待たされるような状況になったら非常に迷惑です

解決法として、あるのは2通りです
読み込みコード実行前に条件分岐を行うか、Initializeイベントの処理最上部に条件分岐を行うかのどちらかです

If ActiveSheet.Name = "対象" Then
UserForm1.Show
Else: End If

読み込みコード実行前に行うのが通常の方法です
If分岐で条件に一致しなければ、読み込みコードは実行しないようにします

ただ、このコードでも問題はあります
基本的にこういった処理の場合は、シートイベントのActivateイベントで表示処理、Deactivateイベントでフォームを終了させる動きにします

こうしておかないと、表示は条件分岐で対象シートで行えても、シートを切り替えた時にフォームが表示されたままになるためです

そこで問題の発生です

対象シートが複数あった場合、全てのシートに条件分岐を作成する必要があります
少しの修正があっても大変になってしまいます

そこで、フォームのInitializeイベントで一括して条件分岐を行います

If Not ActiveSheet.Name = "対象1" Or ActiveSheet.Name = "対象2" Then
End
Else: End If

Initializeイベントの最上部にこのコードを挿入します
アクティブシートの名前が指定シートでなければ、Endステートメントにより強制終了します
指定シートであれば処理が継続して、多少時間のかかる初期化処理が実行されます

Initializeイベント中に、Unloadステートメントを実行するとエラーが発生しますので、このEndステートメントが効果を発揮します

当然ですが、呼び出し元処理(ShowメソッドやLoadステートメント)も強制終了しますので読み込み処理には他の処理は入れないようにしましょう

使用場面は限られて少ないですが、あると便利な場面もありました

なお、気づいた方もいるかもしれませんが、終了処理に対応してません
これにはイベント最強のWithEventsキーワードを使用します

Initializeイベント

Initializeイベントはメモリ上に読み込みが完了した時点で発生するイベントです。起動時の注意点など

「Initialize」イベントは、UserFormがメモリ上に読み込まれたら発生するイベントです
表示される前に発生するイベントで、引数はありません

フォームの初期化処理で使用します

Loadステートメントを実行すると、このイベントが発生します
Showメソッドを実行した場合は、このイベントが発生後にActivateイベントが発生します

また、メモリ上に読み込みが終了しているので、UserFormの操作及び各コントロール全ての操作が可能な状態になります

表示前の処理になるので、このイベントに作成した処理が時間のかかるものであった場合は上記の各読み込みコード実行前に起動の明示をしていないとユーザーにフリーズさせているような誤解を与える可能性があります

そういった場合は、あえてActivateイベントに処理を入れてフォームを表示させておいてもいいかもしれません

フォームの起動条件の作成について

このイベント中にフォームを終了させるとエラーが発生します
フォームの起動条件の確認には、読み込みプロシージャかActivateイベントで行い終了させるようにしてください

ただ、この処理では少し問題がある場合があります
その状況と解決方法は以下の記事で解説しています

Zoomプロパティ

Zoomプロパティは、各コントロールの表示倍率の設定です。使用時の注意点も

'100%表示にする
UserForm1.Zoom = 100

「Zoom」プロパティは、フォーム内の表示倍率の設定です
初期値は100になっています
これは%表示と考えてもらっていいです

設定できる範囲が「10~400」の間に決まっています
元々の10分の1から4倍の大きさにまで、拡大縮小が出来るようになっています

Zoomが100の時の表示
初期値100の表示状態
Zoomが50の時の表示
50に設定した表示状態
Zoomが200の時の表示
200に設定した表示状態

以上の画像の様に、同じフォームの同じサイズのコントロールでも大きな違いが生まれます
なにより、見やすさを向上させるためのプロパティと思ってください

表示の乱れについて

このプロパティの難点が文字列がコントロールの表示領域からはみ出してしまうことがあることです

Zoomの数値によって文字列がはみ出している
labelの文字列がはみ出している状態

画像を確認してください、これは元は上記の画像と同じものです
赤枠内のlabelコントロールの表示文字列の最後の「n」がはみ出して消えてしまっています
これはコントロールのサイズの単位と文字列のサイズの単位が違うため、Zoomプロパティの数値を1ずつ動かしていくと必ずどこかで発生します
文字サイズが影響するため、文字の種類によっても差があります

なので、自動調整で文字列がはみ出す場合はいかんともしがたいです

このプロパティを主に使用するのは、フォームのサイズ調整に合わせて、各コントロールの表示も整える場合に使用します
フォームの自動サイズ調整については以下の記事で解説しています

解説にもありますが、いかんせん表示が乱れることがあるのが困っちゃう
困っちゃうのであんまり普段は使わんですねぇ

Tagプロパティ

Tagプロパティは追加情報を設定するプロパティです。設定するコード

'フォームの追加情報の設定
UserForm1.Tag = "追加情報"

「Tag」プロパティは追加情報を設定できます

これ自体は、設定してもなんの意味もないプロパティです
なんの意味もないということは、他に影響を与えないと言い換えれます

これはそのプロパティ値で、処理を行う為に使用します

タグという名前の通り、なんらかの判定に使用します
例えば、このプロパティに「グループA」という文字列を入力しておいて、そのグループごとに処理を実行するようなことを行えます

また、処理中の一時的なデータの保持にも使用できます
加工前の文字列をプロパティに代入しておき、加工後の文字列を出力後、Tagプロパティから加工前の文字列を取得する、というようなことも出来ます

使用方法は多岐にわたりますので、いろいろな使用方法を考えてみてください

IsReadyプロパティ

IsReadyプロパティは、ドライブの使用可能状態を返します。その状態を取得するコード

'Eドライブの使用可能状態を取得
Debug.Print bhFSO.GetDrive("E").IsReady

「IsReady」プロパティは、ドライブが使用可能な状態にあるかを調べるプロパティです

使用可能であれば「True」、使用不可であれば「False」が指定されます

これはUSBメモリーなどの着脱を行うドライブに対して、データのやり取りが可能な状態かを調べるのに使用します
そのため、これはドライブオブジェクトのプロパティになりますので、まずGetDriveメソッドを使用してドライブを取得します
その後、そのドライブオブジェクトのIsReadyプロパティを調べます

例コードでは1行で実行していますが、他にもドライブに対して処理を行うのであれば、GetDriveメソッドでオブジェクト変数に代入させるほうが良いです

ただ、使用状態を知りたいだけならこのコードで十分です

使用可能な状態とは、ドライブが接続されてデータの通信が可能になった状態です

ドライブを取り外す場合に、基本的には「取り外し」という操作を行います
この操作を行った段階ではまだ、物理的には取り外していません
なので、DriveExistsメソッドではTrueが返される状態です
ですがデータのやり取りは出来ない状態なので、IsReadyプロパティはFalseになります

物理的に取り外すと、DriveExistsメソッドでもFalseが返されるようになります

ドライブが存在しないときは、このプロパティを取得しようとするとエラーが発生します
つまり、DriveExistsメソッドとIsReadyプロパティの2つともがTrueを返したときにそのドライブとのデータのやり取りが可能になる、ということです

FileExists・FolderExists・DriveExistsメソッド

FileExists・FolderExists・DriveExistsメソッドは、ドライブ・フォルダ・ファイルの存在確認をするメソッドです

'ファイルの存在確認
Debug.Print bhFSO.FileExists("ファイルの絶対パス")
'フォルダの存在確認
Debug.Print bhFSO.FolderExists("フォルダの絶対パス")
'ドライブの存在確認
Debug.Print bhFSO.DriveExists("C")

FileSystemObjectを使用して、存在確認を行うメソッドです
「FileExists」メソッドはファイル
「FolderExists」メソッドはフォルダ
「DriveExists」メソッドはドライブ
それぞれの存在確認に、各メソッドを使用します

メソッドは全て、存在すれば「True」、存在しなければ「False」を返します

FileExistsメソッド

Debug.Print bhFSO.FileExists("ファイルの絶対パス")

FileExistsメソッドは、ファイルの存在確認を行うメソッドです

引数には拡張子までを含めた絶対パスを指定します
これは単体のファイルの存在確認のため、ワイルドカードは使用できません

指定の名前のファイルが存在していれば、処理を行うような場合に使用します
存在確認の中でも一番使用頻度が高いメソッドと思います

FolderExistsメソッド

Debug.Print bhFSO.FolderExists("フォルダの絶対パス")

FolderExistsメソッドは、フォルダの存在確認を行うメソッドです

引数にはフォルダ名を含む絶対パスを指定します

またパス指定であれば、ドライブの存在確認も行えます
「C:」のように「:」を付けて指定します
専用のメソッドがあるので、意味はありませんが一応可能です

フォルダは上書きされないので、あまり存在確認は必要ありません

DriveExistsメソッド

Debug.Print bhFSO.DriveExists("C")

DriveExistsメソッドは、ドライブの存在確認を行うメソッドです

引数にはドライブ名を指定します、小文字でも実行可能ですがなるべくドライブ名と同じ大文字で指定するほうがいいです

また、パスでも指定は可能です
「C:」というように指定しても確認を行えますが、メソッド的に意味はありませんので、ドライブ名で指定します

基本的には着脱されるドライブに対して使用します
USBメモリーなどのものです、これをPCで使用されているかを調べて存在すればそのドライブにデータを移動させたりする処理に使用します

なお、ドライブは存在が確認できても使用できる状態とは限りません
使用できる状態を調べるにはIsReadyプロパティを使用します

StartUpPositionプロパティ

StartUpPositionプロパティでフォームの初期表示位置を設定できます

「StartUpPosition」プロパティは、UserFormが表示される初期位置の設定です
基本的には初期表示位置なのでデザインウィンドウで設定します

「0 – 手動」は、初期位置を設定しません。この場合LeftプロパティとTopプロパティの設定値により表示位置が調整されますそれらのプロパティを使用して任意の位置に表示するにはこの設定にしておく必要があります

「1 – オーナーフォームの中央」は、Excelのウィンドウの中央に表示されます。Excelの位置によって表示位置が変更されます。マルチディスプレイで表示する場合に便利な設定です

「2 – 画面の中央」は、そのままの意味で画面の中央に表示します

「3 – Windows の既定値」は、画面の左上にぴったりくっついた場所に表示されます。Leftプロパティなどで位置調整を行っていない「手動」と同じ場所に表示されますので、あまり使いません
また、Leftプロパティなどを設定していても左上の表示位置は変わりません

フォームの初期表示位置設定の位置図
フォームの初期表示位置図

この画像が、各設定で表示される場所です
ピンクがフォームで、設定により場所が変わります

緑色がExcelのウィンドウです、UserFormのオーナーは基本Excelなのでその中央になるので、Excelの位置によって変化します

グレーが画面全体のウィンドウです、その中央に画面の中央に設定したフォームです
初期設定では、この位置設定になっています

コードで変更する場合

Private Sub UserForm_Initialize()

'フォームの初期表示を手動で表示する
Me.StartUpPosition = 0

End Sub

上記のコードを使用すれば、表示位置を変更して表示させられます
ですが上記にもあるように、初期表示位置なのであまり動的に変更する場面が少ないと思いますのでここで解説します

このプロパティは、初期表示位置なので表示されてから設定を変更しても意味はありませんので、表示前に設定を変更する必要があります

なので、メモリ上に読み込まれて表示前に発生するInitializeイベントに記載します

またリファレンスにもあるような、メモリ上に読み込みをしてプロパティを変更してから表示させる方法もあります

ただ、このコードの注意点として手動とWindowsの既定値の設定が切り替わりません
自分の環境のExcel2010でしか試していませんが、デザイン画面で手動にして、コードでWindowsの既定値の設定にしても手動のままです
逆も同様でした、それ以外の設定には切り替わります

まあ、使用場面の少なさからあまり影響は無いと思いますが・・・

画面の表示位置について

画面の表示位置とは、案外重要な要素です

入力補助などのフォームで、フォームの起動を繰り返すような場合に毎回表示位置をタイトルバーをドラッグして移動させるのは面倒です
特にマルチディスプレイを使用している場合に、毎回メインからサブへ移動させるというような動きは非常に面倒です

なので、最終的に完成したときにはこのプロパティから表示位置を調整するようにします

なお、表示位置を保存して前回と同じ場所に表示する処理は以下の記事で解説しています

レジストリのデータを削除

レジストリに保存したデータを削除するコード(DeleteSettingステートメント)

'レジストリの値の削除
DeleteSetting "ファイル名", "モジュール名", "データ名"
'レジストリのsection以下削除
DeleteSetting "ファイル名", "モジュール名"
'レジストリのappname以下削除
DeleteSetting "ファイル名"

レジストリに保存したデータを削除するには「DeleteSetting」ステートメントを使用します

ステートメントの書式

引数(太字は必須引数)
DeleteSetting appname, section, key

引数の指定によって削除される階層が変化します
引数と階層は以下の記事で解説しています

VBAのリファレンスでは、2つ目の引数「section」は必須となっていますが、実際には省略しても実行されます

削除する範囲と必要性

指定した箇所以下が全て削除されます

DeleteSetting "ファイル名", "モジュール名"

つまり、この様にsectionまでの指定を行うとsectionが削除されます
なので値のキーは全て削除されます

DeleteSetting "ファイル名"

appnameのみ指定した場合は、全てのデータを削除します

以下の全データとは言っても、VBAで作成したデータなので、知らないデータや別アプリのデータが削除されるわけではありませんので安心してください

また、このキーより上位のアイテムは本当に必要が無ければ削除したほうが良いと思います

これはエクスプローラーのフォルダ階層と同じ構造です
つまり、フォルダ内にあるファイルを全て削除しても空フォルダがそこに残ったままの状態になっています
空なので、影響はありませんが無駄ファイルであることは間違いありません
キーの値が全て必要ないのであれば、appnameのみで指定して全て削除してしまっていいと思います

レジストリのデータを取得

レジストリのデータを取得するコード(GetSetting関数)

'レジストリの取得
Debug.Print GetSetting("ファイル名", "モジュール名", "データ名", 0)

レジストリのデータを取得するには「GetSetting」関数を使用します

関数の書式

引数(太字は必須引数)
GetSetting(appname, section, key, default)

引数「appname」「section」「key」は、データまでのパス指定です
このあたりの解説は以下の記事で行っています

引数「default」は、パスも含めて指定のデータが存在しなかったときに返される値になります
「appname」は存在しているが、「section」が存在していなかった場合もこの引数の値が返される訳です

省略可能で、省略時は「””」(空白文字列)が返されます
データが無くてもエラーが発生しない点には注意が必要かもしれません

レジストリのデータ取得に関して

レジストリにデータを保存する場合は、SaveSettingステートメントでした

こちらは関数です、値の取得を行うため戻り値が存在するためです
なので、こちらのコードでは引数を「()」で囲むのと、代入先を指定する事を忘れないようにしましょう
例コードではイミディエイトに出力しています

また、レジストリの操作は編集・削除は要注意ですが
取得を行うこの関数の使用に関してはそこまで気にしなくても大丈夫です
取得を行うだけで編集は行いません

ただ、見たらあかんやつを見たらあかんので規則は大切に

レジストリにデータを保存

レジストリにデータを作成・保存するコード(SaveSettingステートメント)

'レジストリの保存
SaveSetting "ファイル名", "モジュール名", "データ名", "データ内容"

レジストリにデータを作成・保存するには「SaveSetting」ステートメントを使用します

ステートメントの書式

引数(太字は必須引数)
SaveSetting appname, section, key, setting

引数は全て必須項目となっており、引数「setting」が保存するデータとなります
それまでの3つの引数はデータの名称設定となり、階層構造になっています
全て文字列で指定し、決まった名称もありませんので自由に指定できます

レジストリの階層図
レジストリの階層図

レジストリの各引数の階層図になります
こういった形で階層が引数の順番に並びます

最上位の「VBA専用」のフォルダより上位は編集できません
編集可能な部分が限定的なので、他のVBAで作成されていなければ何もデータは存在しませんので好きに扱っても問題ありません

存在するデータを指定した場合は、既存のデータが上書きされ、データが無ければ新規作成されます

レジストリ使用上の注意点

レジストリには各アプリの重要なデータも含まれています
いくらVBAでは触れないとはいっても、レジストリの編集をしているという事実は変わらないので、基本的に編集する場合は要注意です

また「レジストリを編集していいすか?」と、気軽に確認するのはやめましょう
レジストリを知っている人からすれば、そんな恐ろしいこと許可できひんと言われます

とはいえ、上記にもあるようにVBAのコードで編集する分には問題ありません
元々何もデータが入っていない場所を編集するのでだいじょうぶです
他の場所を編集しようとしてもVBAのコードでは実行できません

ただ、レジストリエディタは簡単に起動が可能で編集もそのエディタで行えます
ここでは触れませんが、Web検索すればすぐに起動方法はでてきます
ですがVBAでの使用範囲内であれば使用しないでください
何かあったときの責任は非常に大きい可能性がありますので

VBAで触れる範囲のデータは全てVBAで取得も作成も削除も行えます
ま、しなくていいことはしないほうがいいですよね