Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

帳票Windowsアプリ実践構築ガイド
ActiveReports for .NETを使いこなす!

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2009/05/14 14:00

 今回は、ActiveReportsに付随しているSeikyuサンプルを基にして、実際の業務システム構築時に近い形にアレンジした帳票アプリケーションを作ってみました。ActiveReports for .NETでの、より実践的なアプリケーション構築方法を解説していきます。

はじめに

 業務システムとは簡単に言えば、業務データを入力、蓄積、出力して活用する事で付加価値を高め、業務を効率的・効果的に遂行するシステムです。出力方法としては、画面表示、データ出力、印刷などがあります。

 グレープシティのActiveReports for .NETは、この3つの出力方法すべてにおいて業務システムに強力な表現力を付与できる.NETコンポーネントです。

 今回、ActiveReportsに付随しているSeikyuサンプルを基にして、より実際の業務システム構築時に近い形にアレンジしたWindowsアプリケーションをいくつか用意してみました。作成の手順を順に追っていきながら、ActiveReports for .NETでの実践的なアプリケーション構築方法を解説していきます。

Seikyuサンプルからの変更点

 Seikyuサンプルは、請求先を選択するとMicrosoft Accessのmdbファイルから請求先向けのデータを取得して、請求明細書をプレビュー表示するアプリケーションです。

図1:Seikyuサンプルの実行例
図1:Seikyuサンプルの実行例

 しかし、このままでは、複数の請求先の伝票を1度に印刷するなど、業務システムとして実際に起こりうる局面に対応できるとは限りません。

 そこで、Seikyuサンプルを拡張して、次のような変更を加えた「CZ0905Bound」を作成しました。

  1. 印刷単位ではなく請求書単位に請求額合計が印刷できるようにする
  2. 請求先+請求書順に印刷できるようにする
  3. 請求書が複数ページになる時を考慮して、請求書単位にページ番号を付与する

ActiveReportsでのレポート定義について

 サンプルプロジェクト「CZ0905Bound」作成の手順を追っていく前に、まずはActiveReportsでのレポート定義について説明しておきます。

 ActiveReportsの帳票デザイナは、Windowsフォームデザイナによく似た構成になっています。また、使用するコントロールも似ているため、Windowsフォームと同じ感覚でデザインできます。

 ActiveReportsでレポートを定義するには、まず[新しいプロジェクトの作成]で、Windowsフォームアプリケーションのプロジェクトを作成し、[新しい項目の追加]で「ActiveReports 3.0ファイル」を選択して、ActiveReports帳票定義体を追加します。この帳票定義体にいろいろなActiveReports帳票コントロールを配置することで、レポートを定義します。

ラベルコントロールとテキストボックスコントロールの使い分け

 ActiveReportsの帳票コントロールには、「ActiveReportsラベルコントロール」と「ActiveReportsテキストボックスコントロール」があります。

 Windowsフォームの場合、項目名などにラベルコントロールを、入出力データにテキストボックスコントロールを使うといった使い分けは、比較的直観的に判断できます。では、ActiveReportsでは2つのコントロールはどのように使い分けるのでしょうか。

 ActiveReportsラベルコントロールとActiveReportsテキストボックスのプロパティを比較したのが表1です。

表1:プロパティ比較
プロパティ名 Label TextBox 備考
Alignment コントロールの境界内のテキストの配置を取得・設定します。
Angle × コントロール領域のテキストの角度(傾き)を取得・設定します。
BackColor コントロール領域の背景色を取得・設定します。
Border コントロールの各辺の罫線スタイルを定義する罫線オブジェクトを取得します。
Bounds コントロールの位置とサイズを定義する矩形を設定する、もしくは返します。
CanGrow × コントロールの内容に合わせて、コントロールの高さを拡大するかどうかを決定します。
CanShrink × フィールドの値に合わせて、フィールドの高さを縮小するかどうかを決定します。
CharacterSpacing 文字ピッチを取得・設定します。単位はポイントです。
ClassName スタイルルールのクラス名を取得・設定します。スタイルルールはコントロールの書式設定に使用されます。
CountNullValues × DBNull値を集計フィールドにゼロとして含めるかどうかを決定します。
DataField データソースの、コントロールに連結するフィールドの名前を取得・設定します。
DistinctField × 重複を除去する集計関数で使用するデータフィールドの名前を取得・設定します。
Font コントロールテキストの印刷に使用するフォントオブジェクトを取得・設定します。
ForeColor コントロールの前景色(フォント)を取得・設定します。
Height コントロールの高さを取得・設定します(ピクセル単位)。
HyperLink ビューワのHyperLinkイベントで指定した場所に移動するためのURLを取得・設定します。HTMLやPDFにエクスポートした場合、URLは自動的にアンカータグやハイパーリンクに変換されます。
Left コントロールの左端の座標を取得・設定します。
LineSpacing 行間を取得・設定します。単位はポイントです。
Location コントロールの位置を取得・設定します。
MultiLine ラベルコントロールでテキストを複数行表示するかどうかを示す値を取得・設定します。
Name コントロールの名前を取得・設定します。
OutputFormat × ValueプロパティをTextプロパティに格納する前に書式設定するマスク文字列を取得・設定します。
Parent コントロールの親セクションへの参照を取得します。
RightToLeft 右から左へ記述するフォントを使う地域をサポートするために、コントロールの要素を並びかえるかどうかを示す値を取得・設定します。
Size コントロールのサイズを取得・設定します。
Style ラベルのスタイル文字列を取得・設定します。
SummaryFunc × DataField値の処理に使用する集計関数の種類を取得・設定します。
SummaryGroup × 小計を計算するときに集計値をリセットするのに使用するグループヘッダセクションの名前を取得・設定します。
SummaryRunning × データフィールドの集計値が各レベル(詳細、グループ、ページ)で累積されているかリセットされているかを表す値を取得・設定します。
SummaryType × 実行する集計の種類を表す値を取得・設定します。
Tag コントロールに付随するユーザー定義の情報を取得・設定します。
Text 印刷するラベルのテキストを取得・設定します。
Top セクション内のコントロールの上端の、セクションに対する相対的な座標を取得・設定します。
Value Labelコントロールの現在の値を取得・設定します。
VerticalAlignment コントロールの境界内におけるラベルテキストの垂直方向の配置を取得・設定します。
Visible コントロールを印刷するかどうかを決定します。
Width コントロールの幅を取得・設定します。
WordWrap ラベルコントロールで複数行表示するときに、必要に応じて自動的に折り返しを行うかどうかを示します。

 単純なデータ出力ならばActiveReportsラベルコントロールでも可能です。しかし、プロパティを比較すると分かるようにActiveReportsテキストボックスコントロールには、ActiveReportsラベルコントロールにない集計用プロパティが存在します。

 また、OutputFormatプロパティの存在からも推測すると、やはりActiveReportsテキストボックスコントロールは実行時に動的に変化するような部分に使う事を想定していると考えられます。

 今回のサンプルプロジェクト「CZ0905Bound」でも、この切り分けに基づいて2つのコントロールを使い分けています。

レポートを定義する

サンプル帳票デザイン

 今回のサンプルプロジェクト「CZ0905Bound」では、図2のような帳票デザインを採用しています。帳票定義体のDataSourceにDataSetのテーブルを指定し、テキストボックスのDataFieldプロパティにカラム名を指定することで、自動的に各レコードの値を印字します。

 デザイン上の工夫としては、帳票デザイナ画面でActiveReportsテキストボックスコントロールが一目で分かるよう、Textプロパティには「[xxxxx]」のように角括弧で囲んだ文字を設定している事です。このような決め事をしておくと、デザインの打ち合わせ時などに、帳票デザイナ画面のハードコピーを印刷しておくだけで、動的に値が変わる部分が明確に確認でき、便利です。

図2:「CZ0905Bound」の帳票デザイン
図2:「CZ0905Bound」の帳票デザイン

 また、グループを追加して[Bill_GroupHeader]ヘッダと[Bill_GroupFooter]フッタを作成しています。このグループはBillNOが同一のときに同じグループになるように定義してあるので、[Detail]セクションに定義された「日付」「伝票NO」「区分」「製品名」「単価」「数量」「金額」は「BillNO」が同一のもの同士でグループ分けされ、印刷されます。

 各ページの先頭には[PageHeader]セクションの内容が印刷され、各ページの最後には[PageFooter]セクションの内容が印刷されます。

(1)[Bill_GroupHeader]ヘッダと[Bill_GroupFooter]フッタ

 グループヘッダのプロパティで重要なのは、どの項目でグループ化するかを表すDataFieldプロパティです。例えば、今回は請求書Noである「BillNo」でグループ化するので、表2のように設定しています。

表2:グループヘッダのプロパティ設定
プロパティ
DataField BillCondition.BillNo
NewPage None

 グループフッタのプロパティで重要なのは、別のグループに代わる直前に改ページするためのNewPageプロパティです。表3のように「After」と設定すれば、用紙の途中であっても、BillNoの値が異なるデータが来ると改ページします。

表3:グループフッタのプロパティ設定
プロパティ
NewPage After

(2)[txtTotal]テキストボックス

 [PageHeader]セクションに置かれた[txtTotal]テキストボックスは、請求書ごとの金額合計を印字するためのテキストボックスです。ActiveReportsのグループ合計機能を使うためには、次のようにプロパティを設定しています。

表4:グループ合計機能のためのプロパティ設定
プロパティ
DataField Price
DistinctField  
SummaryGroup Bill_GroupHeader
SummaryRunning None
SummaryType SubTotal

 このようにプロパティを設定することで、データソースに存在する[Price]列の値を[Bill_GroupHeader]ヘッダに割り当てられた項目値(この場合BillNo)グループごとに中計(SubTotal)して、表示します。なお、SummaryRunningプロパティの値を設定すると、ページヘッダで正しく合計が計算されないので、注意してください。

(3)[txtPage]テキストボックス

 [PageFooter]セクションに置かれた[txtPage]テキストボックスは、請求書ごとの通しページ番号を印字するためのテキストボックスです。ActiveReportsのページカウント機能を使うためには、次のようにプロパティを設定します。

表5:グループ通しページのためのプロパティ設定
プロパティ
DataField  
DistinctField  
SummaryGroup Bill_GroupHeader
SummaryRunning Group
SummaryType PageCount

 もし、グループごとの総ページ数が必要な場合は、次のようにプロパティを設定します。

表6:グループ総ページのためのプロパティ設定
プロパティ
DataField  
DistinctField  
SummaryGroup Bill_GroupHeader
SummaryRunning None
SummaryType PageCount

帳票定義体にコードを記述する

 WindowsフォームがSystem.Windows.Forms.Formクラスを継承したクラスであるのと同様に、ActiveReports帳票定義体はDataDynamics.ActiveReports.ActiveReport3クラスを継承したクラスです。よって、Windowsフォームの場合と同様、実行時の各種イベントに対してコードを組み込むことができます。

 「CZ0905Bound」サンプルプロジェクトに組み込んだコードはリスト1になります。

リスト1:Seikyu_Report.vb
Public Class Seikyu_Report
    Private m_Row As Integer

    Private Sub PageHeader_BeforePrint(ByVal sender As System.Object, _
                                       ByVal e As System.EventArgs) _
                                       Handles PageHeader.BeforePrint
        '集計値を参照して、別のField コントロールに値を設定します。
        txtExcise.Value = CType(txtTotal.Value, Decimal) * 0.05  '消費税額
        txtBillTotal.Value = CType(txtTotal.Value, Decimal) * 1.05 + _
                           CType(txtCarryOver.Value, Decimal)  '請求額合計
    End Sub

    Private Sub GroupHeader1_BeforePrint(ByVal sender As Object, _
                                         ByVal e As System.EventArgs) _
                                         Handles Bill_GroupHeader.BeforePrint
        m_Row = 0
    End Sub

    Private Sub Detail_Format(ByVal sender As System.Object, _
                              ByVal e As System.EventArgs) _
                              Handles Detail.Format
        '行番号をインクリメントします。
        m_Row = m_Row + 1
        '1行ごとに背景色を切り替えます。
        If (m_Row Mod 2) = 0 Then
            shpDetailBack1.BackColor = Color.White '白色
        Else
            shpDetailBack1.BackColor = Color.LightYellow '黄色
        End If
    End Sub
End Class

(1)ページヘッダで計算結果を印字する

 PageHeader.BeforePrintイベントで、[PageHeader]セクションにある「今回消費税額」と「今回ご請求額」を計算しています。BeforePrintイベントで処理する事で、印字内容に介入できます。

(2)一覧部分の背景色を交互に切り替える

 [Detail]セクションの背景色を交互に切り替えるために、Detail.Formatイベントで背景色を設定しています。背景色の判断はグループごとの現在行の行位置が奇数か偶数かで行っているため、Bill_GroupHeader.BeforePrintイベントで行数を0にクリアしています。

 もし、行数のカウントがページごとでよければ、PageHeader.BeforePrintイベントに0クリアのコードを移動すると良いでしょう。

 以上が、帳票定義体クラスの準備です。続いて、プレビュー表示部分について解説していきます。

レポートをプレビュー表示する

 帳票定義体ができたら、mdbファイルからデータを取得してプレビュー表示する部分を作成します。プレビュー表示は、WindowsフォームにActiveReportsのViewerコントロールを配置して行います。「CZ0905Bound」では、下記のような手順で作業を行いました。

  1. mdbファイルとexeファイルが同じフォルダに配置されて動作するようにmdbファイルもプロジェクトに追加して、[出力ディレクトリにコピー]プロパティを「常にコピーする」に設定。
  2. Windowsフォームをプロジェクトに追加するか、新しいプロジェクトの作成時に自動的に作成されていたForm1.vbを、CZ0905Bound_Form.vbにリネーム。
  3. クラスファイルを追加し、CZ0905Bound.vbというファイル名に。
図3:「CZ0905bound」サンプルプロジェクトの構成
図3:「CZ0905bound」サンプルプロジェクトの構成

クラスにコードを記述する

 CZ0905Boundクラスには、mdbファイルからデータを取得してDataSetを作成するコードを記述しています。Windowsフォームファイルとは別のファイルにしているのは、UI部分とデータアクセス部分を分離しておいた方がコードの見通しがよく、データソースをSQL ServerやOracleなどに切り替える時も変更範囲が明確化するためです。

リスト2:CZ0905Bound.vb
Public Class CZ0905Bound
    Implements IDisposable

    Private connectionString As String = _
           "Provider=Microsoft.Jet.OLEDB.4.0;Password={1};User ID={0};" & _
                   "Data Source=" & _
                       System.IO.Path.Combine(My.Application.Info.DirectoryPath, _
                                              "BILL.MDB")

    Public Function GetRecords(ByVal userID As String, ByVal password As String) As DataSet
        Dim ds As New DataSet
        Using _cn As New OleDb.OleDbConnection( _
                                        String.Format(connectionString, userID, password))
            _cn.Open()
            Using _cmd As New OleDb.OleDbCommand
                Dim sqlString As String = _
                    "SELECT Bill.*, BillCondition.*, Customers.CustomerName " & _
                      "FROM Customers " & _
                     "INNER JOIN (Bill INNER JOIN BillCondition " & _
                                         "ON Bill.BillNo = BillCondition.BillNo)" & _
                        "ON Customers.CustomerID = Bill.CustomerID " & _
                     "ORDER BY Bill.CustomerID,Bill.BillNo,Bill.Date,Bill.SlipNo"
                _cmd.CommandText = sqlString
                _cmd.Connection = _cn
                Using _da As New OleDb.OleDbDataAdapter
                    _da.SelectCommand = _cmd
                    _da.Fill(ds)
                    'Priceを計算する
                    For Each row As DataRow In ds.Tables(0).Rows
                        row.BeginEdit()
                        row("Price") = CType(row("Number"), Decimal) * _
                                       CType(row("UnitPrice"), Decimal)
                        row.EndEdit()
                    Next
                End Using
            End Using
            _cn.Close()
        End Using
        Return ds
    End Function
End Class

 記述したコードは、ADO.NETにおけるDataAdapterクラスの基本的な使い方に準拠しています。少し特殊なのは、mdbファイルの[Price]項目に値が入っていないので、FillメソッドでDataSetに値を取得した後にPrice値を計算し、DataSetの[Price]項目に値を設定している点です(※1)。

※1

DataSetに加えた変更はmdbファイルに反映してないため、mdbファイルの内容が変わるような事はありません。

Windowsフォームにコードを記述する

 Windowsフォームの画面デザインはActiveReportsのViewerコントロールを貼り付け、Dockプロパティを「Fill」にすれば完成です。そして、DataSetと帳票定義体の2つをViewerコントロールに渡して、プレビュー表示するコードを記述しています。

リスト3:CZ0905Bound_Form.vb
Public Class CZ0905bound_Form
    Private Sub Form1_Shown(ByVal sender As Object, _
                            ByVal e As System.EventArgs) Handles Me.Shown
        Dim rpt As New Seikyu_Report()

        Application.DoEvents()
        Using _prco As New CZ0905Bound
            rpt.DataSource = _prco.GetRecords("admin", "").Tables(0)
            Viewer1.Document = rpt.Document
            rpt.Run()
        End Using
    End Sub
End Class

実行

図4:CZ0905boundの実行結果
図4:CZ0905boundの実行結果

 実行時には、請求書NO「WS-DF502」のデータを増やし、2ページに渡って印字されるようにしています。このように複数ページに渡るテストデータを用意しておく事で、同一グループ複数ページの挙動が調べられます。テストデータ作成時のちょっとした工夫ですが、後から予期せぬ問題が起きないようにするためには、非常に重要な事です。

レポートを印刷する

 最近の傾向として、紙資源の有効活用やセキュリティの面から、業務アプリケーションを利用する際も、プレビュー画面で確認したら、印刷をせずPDF出力などで済ませてしまうことも多くなってきたように思います。しかしながら、夜間に締め処理をしてから自動的に印刷するようなバッチ処理や、データ入力後は自動的に印刷するような画面が必要な仕様のアプリケーションもたくさんあります。

 ActiveReportsでは、WindowsフォームにViewerコントロールを張り付けてプレビュー表示から印刷するだけではなく、自動的に印刷・PDF出力する機能を追加することもできます。

 「CZ0905Bound」サンプルに上記機能を追加したのが、「CZ0905PDF」サンプルプロジェクトです。「CZ0905Bound」は、データアクセス部分と帳票定義体とWindowsフォーム部分からできています。このため、Windowsフォーム部分だけを置き換え、他の2つの部分は流用するだけで、自動的にPDF出力する機能を追加できました。

 Windowsフォームにコードを記述する前に、まず次の作業を行いました。

  1. 新しくWindowsフォームのプロジェクトを作成します。
  2. WindowsフォームにButtonコントロールを1つ配置して、「Pdf_Button」という名前にします。
  3. [既存の項目の追加]で、CZ0905BoundサンプルからSeikyu_Reports.vb、CZ0905Bound.vb、Bill.mdbの3つをプロジェクトにコピーし、追加します。

Windowsフォームにコードを記述する

 「CZ0905PDF」サンプルプロジェクトには、Viewerを使わずに、仮想プリンタ定義に基づきパスワード付きPDFファイルを出力するコードを記述しています。

リスト4:CZ0905PDF_Form.vb
Imports DataDynamics.ActiveReports
Imports DataDynamics.ActiveReports.Export.Pdf

Public Class CZ0905PDF_Form
    Private Sub Pdf_Button_Click(ByVal sender As System.Object, _
                                 ByVal e As System.EventArgs) _
                                 Handles Pdf_Button.Click
        Dim rpt As New Seikyu_Report()

        Application.DoEvents()
        Using _prco As New CZ0905Bound
            Dim pdf As New PdfExport

            rpt.DataSource = _prco.GetRecords("admin", "").Tables(0)
            ' 仮想プリンタを設定します。
            rpt.Document.Printer.PrinterName = ""
            rpt.PageSettings.PaperKind = Drawing.Printing.PaperKind.A4
            rpt.PageSettings.Orientation = Document.PageOrientation.Portrait
            rpt.PageSettings.Margins.Top = ActiveReport3.CmToInch(0.5F)
            rpt.PageSettings.Margins.Bottom = ActiveReport3.CmToInch(0.5F)
            ' レポートを作成します。
            rpt.Run()
            'PDF出力
            pdf.Security.Use128Bit = True
            pdf.Security.OwnerPassword = "hatsune"
            pdf.Security.UserPassword = "CodeZine"
            pdf.Security.Permissions = PdfPermissions.AllowPrint
            pdf.Security.Encrypt = True
            pdf.Export(rpt.Document, _
                       System.IO.Path.Combine(My.Application.Info.DirectoryPath, _
                                              "BILL.PDF"))
        End Using
    End Sub
End Class

 DataDynamics.ActiveReports.Export.Pdf.PDFExportのSecurityプロパティを使って、パスワード付きPDFファイルにしています。パスワードは「CodeZine」に設定しています。

実行

 「CZ0905PDF」を実行すると、「bin\debug」フォルダにBILL.PDFファイルが出力されます。

図5:「CZ0905PDF」の実行結果
図5:「CZ0905PDF」の実行結果

 PDFファイルを開こうとすると、パスワードが要求されます。「CodeZine」と入力することで、PDFの内容が表示できます(大文字小文字の区別あり)。

図6:CZ0905PDFの実行結果
図6:CZ0905PDFの実行結果

まとめ

 ここまで見てきたように、ActiveReportsはいくつかの点を押さえることで、Windowsアプリに帳票機能を効率的に追加できます。

 次回は、Webアプリケーションの作成方法を紹介していきます。

ワンポイントテクニック

 実際にシステム構築で使ってみると、1番時間がかかるのは帳票定義体で罫線の位置を合わせる作業だったりします。

 定義はコードとして*.Designer.vbに記述されているので、微妙な位置合わせを行う場合、設定箇所をコードから探し出し、プロパティの設定値を微調整すると、1発で決まります。テキストファイルなので、高機能なテキストエディタやVisual Studioの検索・置換機能を駆使すれば、効率的に定義できます。

 Windowsフォームと同じように、帳票定義体のコントロール名などにも命名規約を適用して、コードでも見やすいように工夫するとさらに効率があがるでしょう(今回は製品添付サンプルを改造したので、命名規約などの適用は行っていません)。

製品情報

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 初音玲(ハツネアキラ)

     国内SIerのSEでパッケージ製品開発を主に行っており、最近は、空間認識や音声認識などを応用した製品を手掛けています。  個人的には、仕事の内容をさらに拡張したHoloLensなどのMRを中心に活動しています。  Microsoft MVP for Windows Development...

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5