t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA デザインしたユーザーフォームを元にNewで複数のフォームインスタンスを作る。

VBAでユーザーフォームはふつう、単一のオブジェクトとして扱う。

たとえば以下のようなフォームを作ったとしよう。
f:id:t-hom:20170117201737p:plain

オブジェクト名は「frm成績」としたので、このフォームを表示させるコードはこうだ。

Sub hoge()
    frm成績.Show
End Sub

この時フォームは、「frm成績」オブジェクトとして扱われいてる。

さて、たとえばこのフォームを3つ同時に起動させたいとする。
どうすればいいか。

まずフォームのShowModalがTrueのままでは3つ同時に表示させることはできないので、これをFalseにしておく。
f:id:t-hom:20170117202340p:plain

ShowModalとは、フォームを表示させた際にそのフォームを閉じるまで次に進めないか、それとも次のコードをそのまま実行させるかというプロパティで、FalseにするとフォームをShowしたあと閉じられるのを待たずに次のコードに進む。

そして記述するコードは次のとおり。

Sub hoge()
    Dim f As frm成績
    Set f = New frm成績
    f.Show
    Set f = New frm成績
    f.Show
    Set f = New frm成績
    f.Show
End Sub

実行するとフォームは1つに見えるが、重なっているだけでずらしてみるとこのとおり。
f:id:t-hom:20170117203051p:plain

つまりユーザーフォームはオブジェクト(インスタンス)でありながら、クラスのようにも振る舞うことができるのだ。なんとも不思議な特性である。クラスモジュールはインスタンス化して初めてつかえる。シートなどのオブジェクトモジュールは単一オブジェクトとしてのみ扱え、Newはできない。対してフォームモジュールは単一オブジェクトとして扱うこともできるし、クラス(オブジェクトのひな形)として扱うこともできるのだ。


さて、これが何に使えるのかというとそこはみなさんの創造力次第。

私がひとつ思いついたのは、データをフォームに読み取ってカードのように並べて表示させたいケース。

単一フォームで対応するのは難しいが、この手法なら大丈夫。

たとえばSheet1に以下のようなデータがあるとする。
f:id:t-hom:20170117203344p:plain

Sheet1モジュールに以下のコードを記入し、

Enum 列
    名前 = 1
    国語
    数学
    理科
    社会
End Enum

Sub FormからFormをNew()
    Dim C As Collection
    Set C = New Collection
    Dim frm As frm成績
    
    Dim i
    For i = 2 To 4
        Set frm = New frm成績
        frm.lblName = Cells(i,.名前).Value
        frm.txt国語 = Cells(i,.国語).Value
        frm.txt数学 = Cells(i,.数学).Value
        frm.txt理科 = Cells(i,.理科).Value
        frm.txt社会 = Cells(i,.社会).Value
        frm.Show
        frm.Left = frm.Left + (i - 3) * frm.Width
    Next
End Sub

実行するとこのとおり。
f:id:t-hom:20170117203710p:plain

あるいはデータを格納するためのPersonクラスを作成し、そのクラスにフォームのインスタンスを持たせるとか。。
そうすれば各Personインスタンスがそれぞれ別個のユーザーインターフェースを持つことができる。

他にも工夫次第で色々と面白いことができそうな気がする。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。