2010年11月11日

UserFormsオブジェクト1.UserForm

 このカテゴリーページでは、Excelのユーザーフォームを使う上で、中々思い通りに動かなかったり、見落としがちな後処理・落とし穴的な事柄などを覚え書きとして書き綴っています。  Excelに標準で添付されているVisual Basic Editorを使うと、市販のアプリケーションソフトでは?と、見紛う外観を持ったソフトが作れます。(たぶんね。内部もそうだと良いけど、なかなかできません。)  VBAマクロと組み合わせて、オリジナルのユーザーフォームを組み上げていくと、「やったぁ〜、できたど〜!」と達成感が得られます。でも、いざ他の人に使ってもらうと、動かないんです。  殆どの場合は、作者の操作上の癖が邪魔をして、VBAマクロのエラー中断を隠したりしています。自分で組んでいると、操作は一定の手順を踏んでいくので、バグフィックスにかからないんですね。  自分の思い込みで作っても、ユーザーはA→B→C→D→・・・という手順通りに操作するとは限りません。作業ステップが多ければ多いほど、はしょられる(省かれる)手順が多くなります。  想定外の操作でもマクロが動くようにするには、あらゆる角度からのテストが必要です。入力値を計算するプロシージャなのに、文字が入力されてしまったためにマクロが中断してしまったり、数値が大きすぎてオーバーフローしたりということは、よくあることでしょう。

ユーザーフォームズオブジェクト[ UserForm* ]

 ユーザーフォームズオブジェクトは、コントロールやオブジェクト、コレクションを配置する台座のようなものです。ユーザーフォームウィンドウは、いろいろなコントロールを収めたツールボックス(ラベル・テキストボックス・リストボックス・チェックボックス・オブションボタン・トグルボタン・フレーム・コマンドボタン・タブストリップ・マルチページ・スピンボタン・イメージ・RefEditなどのコントロール)と、ユーザーフォームの間をマウスでクリック&ドロップの操作で、楽にオリジナルのユーザーフォームが作れるようになっています。

  • ユーザーフォームを表示する
    Private Sub UserForm1_Show()
      UserForm1.Show
    End Sub
     
    となりますが、覚えていることがこれだけだと、先行きに不安が残ります。[ Sowメソッド ]によって表示された[ UserForm1 ]に、次のプロシージャを持ったコマンドボタンがあると、面倒なことになります。※場合によって、Excelを強制終了するハメに・・・。
     
  • コマンドボタンのクリックイベントで、アクティブシートの印刷プレビューを行う
    Private CommandButton1_Click()
      ActiveSheet.PrintPreview
    End Sub
     
    このマクロは、[ Showメソッド ]の引数を既定値[ vbModal ]のモーダル状態のまま走り始め、ユーザーが[ CommandButton1 ]をクリックした[ Clickイベント ]によって、VBAマクロから、Excelの[ PrintPreviewメソッド ]へ処理が移ります。そうするとExcelは、印刷プレビュー状態のままユーザーの処理選択を待ちます。中断されているVBAマクロ[ CommandButton1_Click() ]プロシージャへは処理が戻らないので、マウスもキーボード操作も受け付けません。対策としては・・・
     
  • ユーザーフォームをモードレスで表示する
    Private Sub UserForm1_Show()
      UserForm1.Show vbModeless
    End Sub
     
    これなら、[ PrintPreviewメソッド ]を実行しても、[ 印刷プレビュー ]画面の操作([ 閉じる ])で、再び[ UserForm1 ]へ、処理を戻すことができます。でも、[ 印刷プレビュー ]画面の前面には、フォーカスの与えられていない[ UserForm1 ]が、邪魔な位置で被さっていますね。しかも、[ UserForm1 ]が表示されているのに、ワークシートの操作も出来てしまいます。でも、使いようによっては、便利なことでもありますので、モードレスの使い道からいきましょう。
     
    Excelのメニューにある[ 検索 ]コマンドですが、[ 検索ダイアログボックス ]が表示されている時は、ワークシートのセルデータを編集する事が出来ません。検索ワードがヒットしても、[ 検索ダイアログボックス ]を閉じるか、[ 置換 ]を使わなければ、[ 検索 ][ 置換 ]以外のことが出来ないので不便ですね。[ 置換 ]を使うにしろ、置き換える条件が複数あったり、ユーザーの判断で行う必要があるときは、不便さを感じます。そんな時にはVBAマクロで、オリジナルの[ 検索 ]ダイアログを作ってみましょう。【VBAマクロ:さっくり検索君】
     
  • ※ユーザーフォーム[ UserForm1 ]・テキストボックス[ TextBox1 ]・コマンドボタン[CommandButton1]を予め作っておいてください。
     
    標準モジュールへ記述
    Sub Auto_Open()
      Application.OnDoubleClick = "UserForm1_Show"
    End Sub
     
    [ Auto_Openイベント ]で、Excelの[ OnDoubleClick ]プロパティに、[ UserForm1_Show() ]プロシージャを設定
     
  • フォームのコードへ記述
    Private Sub UserForm1_Show()
      UserForm1.Show vbModeless
    End Sub
     
    ’[ UserForm1 ]をモードレスで表示する
     
    Private Sub CommandButton1_Click()
    On Error GoTo TRAP
      Range(ActiveSheet.Cells.Find(TextBox1).Address).Select
      Exit Sub
    TRAP:
      MsgBox "検索内容に該当する文字は" & vbCrLf _
            & "見つかりませんでした。", vbInformation, "検索結果"
    End Sub
     
    [ TextBox1 ]の検索文字が見つからなかった場合の、エラートラップを用意してあります。検索文字が見つかった場合は、対象のセルを選択(アクティブに)して、[ CommandButton1_Click() ]]のプロシージャを抜けるマクロです。抜ける(終了)とはいっても、あくまでもコマンドボタンのクリックイベントだけが終了し、ユーザーフォームは表示され続けます。このあたりで、ExcelのVBAマクロは、イベントドリブン(キッカケによって、プログラムが実行される)なのだと解ります。
     
    あとは、検索対象となるデータを任意のワークシート・セルに入力して[ Auto_Openイベント ]を実行後、どこかのセルをダブルクリックすれば、モードレスの[ 検索 ]ダイアログボックスを試すことができます。
     
    通常ユーザーフォームの表示中は、[ UserForm* ]の中で操作を進めるように、VBAマクロを組んでいきます。[ TextBox1 ]の値を変えるたびに、フォームを閉じてExcelのメニューを使って印刷して、再びフォームを表示して・・・、とはせず、[ UserForm* ]上に配置された[ CommandButton* ]を使って印刷する方が、ユーザーの手順が少なくてすみます。操作した結果、変更されたデータやワークシート、作成された表などを[ UserForm* ]の表示中に印刷するには、やはり[ PrintPreviewメソッド ]や[ PrintOutメソッド ]が必要になります。
     
    では、モーダル状態で表示されている[ UserForm* ]と[ PrintPreviewメソッド ]が、競合しない手はあるのでしょうか。
     
  • Private CommandButton1_Click()
      Me.Hide
      ActiveSheet.PrintPreview
      Me.Show
    End Sub
     
    [ PrintPreviewメソッド ]や[ PrintOutメソッド ]を実行する前に、Me(UserForm1)を一時的に非表示[ Hideメソッド ]にします。ここで、[ Meキーワード ]を使っていますが、プロシージャをフォーム(UserForm1)のコードに書いているので成り立つコードです。
     
    ユーザーフォームズオブジェクト[ UserForm* ]を表示させる前に初期設定、例えばリストボックス[ ListBox* ]の項目設定など、事前に処理しておきたい事があるときは、[ Loadステートメント ]と[ Initializeイベント ]も使います。[ Addメソッド ]を使って、ラベルコントロール[ Label1 ]をVBAマクロで追加してみます。
     
  • 標準モジュールへ記述
    Private Sub  UserForm1_Show()
      Load UserForm1
      UserForm1.Show
    End Sub
     
    フォーム[ UserForm1 ]のコードへ記述
    Private Sub UserForm_Initialize()
      With Me
        .Caption = "VBAマクロでラベルを追加"
        With .Controls.Add("Forms.Label.1", "Label1", True)
          .Top = 2
          .Left = 2
          .Width = 100
          .Caption = "ラベルコントロール"
        End With
      End With
    End Sub
     
    [ UserForm1 ]のウィンドウタイトルが「VBAマクロでラベルを追加」、ユーザーフォーム上に「ラベルコントロール」というキャプションを持つ[ Label1 ]を追加、表示します。
     
    ユーザーフォームに、ユーザーの操作を受け付ける役割と、VBAマクロの実行結果を表示させるという、双方向の役割を持たせる場合、ひと役買いそうなメソッドがあります。例えばユーザーフォームを使って、顧客管理のインターフェースを作るとして、データがワークシートや外部ファイル(CSV形式やテキスト)にあって、個々の顧客情報を印刷するとき、専用の帳票様式をワークシートに用意したり、個々の顧客データをワークシートやセルに展開しなくても、表示中のユーザーフォームを印刷したほうが、手っ取り早いこともあります。
     
  • Private CommandButton1_Click()
      UserForm1.PrintForm
    End Sub
     
    [ PrintFormメソッド ]は、その名の通り[ UserForm* ]と、フォーム上のクライアント領域を印刷します。細かな設定や引数は持っていませんが、スクリーンキャプチャーソフトや[ Print Screen ]代わりになるでしょう。
posted by くきお at 11:11| Comment(0) | UserFormオブジェクト | このブログの読者になる | 更新情報をチェックする