連載:アップグレード・ウィザードに学ぶVB 6→VB 2005

第4回 アップグレード・ウィザードもお手上げ? VB 6と.NETの印刷の違い

グレープシティ株式会社 八巻 雄哉
2007/04/17
Page1 Page2 Page3

VB 2005における印刷処理のコーディング

 まず以下が、リスト1のコードをVB 2005用に手動で変換したコードになります。

Public Class Form1

  Private Sub PrintButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PrintButton.Click

    ' 用紙サイズをA4に設定
    For Each paperSize As Printing.PaperSize _
          In PrintDocument1.PrinterSettings.PaperSizes
      If paperSize.Kind = Printing.PaperKind.A4 Then
        PrintDocument1.DefaultPageSettings.PaperSize = paperSize
        Exit For
      End If
    Next

    ' 用紙方向を縦に設定
    PrintDocument1.DefaultPageSettings.Landscape = False

    ' 印刷処理を実行
    PrintDocument1.Print()

  End Sub

  ' 現在のページ番号
  Private currentPage As Integer

  ' 印刷で使用するリソース
  Private printFont As Font
  Private linePen As Pen
  Private crossBrush As Drawing2D.HatchBrush
  Private vblabBitmap As Bitmap

  ' BeginPrintイベントを利用して、
  ' フォントなどの印刷で使用するリソースを初期化します。
  ' ドキュメントの最初のページが印刷される前に発生します。
  Private Sub PrintDocument1_BeginPrint( _
            ByVal sender As Object, _
            ByVal e As System.Drawing.Printing.PrintEventArgs) _
            Handles PrintDocument1.BeginPrint

    ' ページ番号を初期化
    currentPage = 1

    ' 印刷で使用するリソースを初期化
    printFont = New Font("MS 明朝", 72, _
        FontStyle.Bold Or FontStyle.Italic Or FontStyle.Underline)
    linePen = New Pen(System.Drawing.Color.Blue, 1.5)
    linePen.DashStyle = Drawing2D.DashStyle.Dot
    crossBrush = New Drawing2D.HatchBrush( _
            Drawing2D.HatchStyle.Cross, Color.Cyan, Color.White)
    vblabBitmap = New Bitmap("C:\vblab.bmp")

  End Sub

  ' QueryPageSettingsイベントは、
  ' PrintPageイベントの直前に発生します。
  Private Sub PrintDocument1_QueryPageSettings( _
    ByVal sender As Object, _
    ByVal e As System.Drawing.Printing.QueryPageSettingsEventArgs) _
    Handles PrintDocument1.QueryPageSettings

    ' ページごとに異なるページ設定を使用する場合には
    ' このイベントを使用します。

  End Sub

  ' PrintPageEventArgs.HasMorePagesプロパティがTrueに設定されて
  ' いる間、PrintPageイベントが発生し続けます。
  Private Sub PrintDocument1_PrintPage( _
          ByVal sender As Object, _
          ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
          Handles PrintDocument1.PrintPage

    With e.Graphics

      ' 座標単位をミリメートルに設定
      .PageUnit = GraphicsUnit.Millimeter

      If currentPage = 1 Then
        ' 1ページ目の描画

        ' 文字列の描画
        .DrawString("テスト印刷", printFont, Brushes.Black, 30, 30)

        ' 点線の描画
        .DrawLine(linePen, 30, 70, 180, 70)

        ' 四角形の描画
        .FillRectangle(Brushes.Red, 30, 90, 60, 60)

        ' 円の描画
        .FillEllipse(Brushes.Green, 110, 90, 60, 60)

        ' 網掛けの四角形の描画
        .DrawRectangle(Pens.Cyan, 30, 170, 150, 50)
        .FillRectangle(crossBrush, 30, 170, 150, 50)

        ' 画像の描画
        e.Graphics.DrawImage(vblabBitmap, 30, 240)

        ' 次のページが存在します。
        e.HasMorePages = True

      Else
        ' 2ページ目の描画
        .DrawString("2ページ目", printFont, Brushes.Black, 30, 30)

        ' このページが最終ページ
        e.HasMorePages = False

      End If

      ' ページ番号を繰り上げる
      currentPage += 1

    End With
  End Sub

  ' EndPrintイベントを利用して、
  ' 印刷で使用されたリソースを解放します。
  ' ドキュメントの最後のページが印刷される前に発生します。
  Private Sub PrintDocument1_EndPrint( _
              ByVal sender As Object, _
              ByVal e As System.Drawing.Printing.PrintEventArgs) _
              Handles PrintDocument1.EndPrint

    ' 印刷で使用されたリソースを開放
    printFont.Dispose()
    linePen.Dispose()
    crossBrush.Dispose()
    vblabBitmap.Dispose()

  End Sub

End Class
リスト2 リスト1のコードを再現したVB 2005のコード
フォームには1つのボタン(PrintButton)と1つのPrintDocumentコンポーネント(PrintDocument1)が配置されているものとする。

 若干長くなってしまっていますが、このリスト2はリスト1の内容をVB 2005で再現したコードです。それではポイントとなる個所を見ていきましょう。

■PrintDocumentコンポーネントの追加

 VB 2005では、Printerオブジェクトではなく、

PrintDocumentクラス(System.Drawing.Printing名前空間)

を使用して印刷を行います。コードを記述してPrintDocumentクラスのオブジェクト・インスタンスを生成することももちろん可能ですが、フォームにPrintDocumentコンポーネントとして追加することができますので、今回は後者の方法を選択しています。

 フォーム・デザイナが表示された状態で、ツールボックスの[印刷]タブから「PrintDocument」を選択してフォーム上に配置すれば、「PrintDocument1」という名前のPrintDocumentコンポーネントがフォームに追加されます。これは、フォームのメンバとしてPrintDocument1という名前のPrintDocumentクラスのインスタンスを生成した状態と同様です。

■PrintDocumentコンポーネントのイベント

 では、コード部分を見ていきましょう。VB 6のPrinterオブジェクトを使った印刷の場合、特に印刷の開始を宣言することなくPrinterオブジェクトにアクセスした時点から自動的に印刷処理が開始されていました。

 VB 2005のPrintDocumentコンポーネント使った印刷では、Printメソッドを呼び出すことで印刷処理が開始されます。Printメソッドが実行されると、以下のような順序で各イベントが発生していきます。

  • BeginPrint
  • QueryPageSettings
  • PrintPage
  • EndPrint

 上記のイベントのうち、BeginPrintイベントとEndPrintイベントは1回のPrintメソッドの実行で1回だけ発生します。通常、BeginPrintイベントのイベント・ハンドラにフォントやペンといった印刷で使用するリソースを初期化するコードを記述し、EndPrintのイベント・ハンドラにそれらのリソースを開放するコードを記述します。このようにリソースを初期化する部分を分離することで、本来の印刷ページの描画部分のコードが見やすくなるというメリットもあります。

 一方、QueryPageSettingsイベントとPrintPageイベントは印刷するページの数だけ繰り返し発生します。QueryPageSettingsのイベント・ハンドラにはページごとに必要な印刷設定のためのコードを記述し、PrintPageのイベント・ハンドラには印刷ページに描画するコードを記述します。

■Graphicsオブジェクトを使った印刷ページの描画

 PrintPageイベント・ハンドラ内で印刷ページの描画を行うには、イベント・ハンドラとなるメソッドの第2パラメータで渡されるPrintPageEventArgsオブジェクト(System.Drawing.Printing名前空間)が持つGraphicsプロパティ(リスト2では「e.Graphics」の部分に該当)を使用します。このプロパティから取得できるGraphicsオブジェクト(System.Drawing名前空間)に用意されたさまざまなメソッドとプロパティを使って実際の描画(印刷)を行うことになります。

 リスト1で使われているPrinterオブジェクトの描画メソッドに対応するGraphicsオブジェクトの描画メソッドは以下のとおりです。

VB 6 VB 2005
Printerオブジェクトの描画メソッド Graphicsオブジェクトの描画メソッド
Print DrawString
Line DrawLine DrawRectangle FillRectangle
Circle DrawEllipse FillEllipse
PaintPicture DrawImage
表 Printerオブジェクトの描画メソッドとGraphicsオブジェクトの描画メソッドの対応(リスト1で使用されているメソッドのみ記載)

 VB 2005で対応するメソッドを見ると数は多くなっていますが、1つのメソッドをパラメータによっていくつかの描画に対応させていたVB 6よりも、それぞれの描画に対応して個々のメソッドを用意しているVB 2005の方が分かりやすくなっているといえるのではないでしょうか。

■複数ページの印刷

 最後に、VB 6と大きく異なる点として意識しておかなければならないのは、PrintPageイベント・ハンドラに記述したコードはページごとに毎回実行されるということです。

 今回のサンプル・プロジェクトのように1ページ目と2ページ目のレイアウトにまったく共通性がないような場合ですと、If〜Then〜Elseステートメントなどを用いて条件分岐を行い、ページごとに処理を分けて記述する必要があるため違和感を覚えるかもしれません。しかしながら、実際の複数ページの印刷で多いのは、各ページのレイアウトは共通で、描画されるデータが異なるというパターンです。イベント・ドリブンによる印刷処理は、このような場合にマッチしたものといえるでしょう。

 複数ページの印刷を行う場合には、PrintPageイベント・ハンドラの第2パラメータのPrintPageEventArgsオブジェクトが持つHasMorePagesプロパティを使います。HasMorePagesプロパティは、後続のページを印刷するかどうかをTrue/Falseで指定するためのものです。

 HasMorePagesプロパティのデフォルト値はFalseに設定されているため、ここに何も値を設定しなければPrintPageイベントはもはや発生せず、印刷は1ページで終わりとなります。

 HasMorePagesプロパティをTrueに設定しておくと、再びPrintPageイベントが発生し、2ページ目の描画を行えます。つまり、HasMorePagesプロパティにTrueを設定し続けることで2ページ目、3ページ目と描画を行え、Falseを設定した(もしくは何も値を設定しなかった)時点でそのページが最終ページとなります。

■印刷結果

 リスト2のコードの印刷結果は以下の図3のようになります。細かく見比べると点線の各点が丸から四角になっているなどの違いはありますが、ほぼ同じ内容の印刷を再現できていることを確認できます。


図3 リスト2のVB 2005プログラムの実行結果
Microsoft Office Document Image Writerを通常使うプリンタに設定し、リスト2のコードで印刷される内容をプレビューさせたもの。左側が1ページ目で、右側が2ページ目となっている。

 なお、より複雑な印刷の場合には、PrintDocumentクラスを継承したクラス(派生クラス)を独自に作成した方がよいでしょう。そうすることで、複数のイベント・ハンドラをまたいで管理する必要があったオブジェクトなども含めてカプセル化することができます。また、作成した印刷ロジックを再利用することも容易になります。


 INDEX
  アップグレード・ウィザードに学ぶVB 6→VB 2005
  第4回 アップグレード・ウィザードもお手上げ? VB 6と.NETの印刷の違い
    1.アップグレード・ウィザードでも変換できないVB 6のコード
  2.VB 2005における印刷処理のコーディング
    3.VB 6の資産の移行は?
 
インデックス・ページヘ  「アップグレード・ウィザードに学ぶVB 6→VB 2005」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH