はじめに
業務システムとは簡単に言えば、業務データを入力、蓄積、出力して活用する事で付加価値を高め、業務を効率的・効果的に遂行するシステムです。出力方法としては、画面表示、データ出力、印刷などがあります。
グレープシティのActiveReports for .NETは、この3つの出力方法すべてにおいて業務システムに強力な表現力を付与できる.NETコンポーネントです。
今回、ActiveReportsに付随しているSeikyuサンプルを基にして、より実際の業務システム構築時に近い形にアレンジしたWindowsアプリケーションをいくつか用意してみました。作成の手順を順に追っていきながら、ActiveReports for .NETでの実践的なアプリケーション構築方法を解説していきます。
Seikyuサンプルからの変更点
Seikyuサンプルは、請求先を選択するとMicrosoft Accessのmdbファイルから請求先向けのデータを取得して、請求明細書をプレビュー表示するアプリケーションです。
しかし、このままでは、複数の請求先の伝票を1度に印刷するなど、業務システムとして実際に起こりうる局面に対応できるとは限りません。
そこで、Seikyuサンプルを拡張して、次のような変更を加えた「CZ0905Bound」を作成しました。
- 印刷単位ではなく請求書単位に請求額合計が印刷できるようにする
- 請求先+請求書順に印刷できるようにする
- 請求書が複数ページになる時を考慮して、請求書単位にページ番号を付与する
ActiveReportsでのレポート定義について
サンプルプロジェクト「CZ0905Bound」作成の手順を追っていく前に、まずはActiveReportsでのレポート定義について説明しておきます。
ActiveReportsの帳票デザイナは、Windowsフォームデザイナによく似た構成になっています。また、使用するコントロールも似ているため、Windowsフォームと同じ感覚でデザインできます。
ActiveReportsでレポートを定義するには、まず[新しいプロジェクトの作成]で、Windowsフォームアプリケーションのプロジェクトを作成し、[新しい項目の追加]で「ActiveReports 3.0ファイル」を選択して、ActiveReports帳票定義体を追加します。この帳票定義体にいろいろなActiveReports帳票コントロールを配置することで、レポートを定義します。
ラベルコントロールとテキストボックスコントロールの使い分け
ActiveReportsの帳票コントロールには、「ActiveReportsラベルコントロール」と「ActiveReportsテキストボックスコントロール」があります。
Windowsフォームの場合、項目名などにラベルコントロールを、入出力データにテキストボックスコントロールを使うといった使い分けは、比較的直観的に判断できます。では、ActiveReportsでは2つのコントロールはどのように使い分けるのでしょうか。
ActiveReportsラベルコントロールとActiveReportsテキストボックスのプロパティを比較したのが表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]
」のように角括弧で囲んだ文字を設定している事です。このような決め事をしておくと、デザインの打ち合わせ時などに、帳票デザイナ画面のハードコピーを印刷しておくだけで、動的に値が変わる部分が明確に確認でき、便利です。
また、グループを追加して[Bill_GroupHeader]ヘッダと[Bill_GroupFooter]フッタを作成しています。このグループはBillNOが同一のときに同じグループになるように定義してあるので、[Detail]セクションに定義された「日付」「伝票NO」「区分」「製品名」「単価」「数量」「金額」は「BillNO」が同一のもの同士でグループ分けされ、印刷されます。
各ページの先頭には[PageHeader]セクションの内容が印刷され、各ページの最後には[PageFooter]セクションの内容が印刷されます。
(1)[Bill_GroupHeader]ヘッダと[Bill_GroupFooter]フッタ
グループヘッダのプロパティで重要なのは、どの項目でグループ化するかを表すDataFieldプロパティです。例えば、今回は請求書Noである「BillNo」でグループ化するので、表2のように設定しています。
プロパティ | 値 |
---|---|
DataField | BillCondition.BillNo |
NewPage | None |
グループフッタのプロパティで重要なのは、別のグループに代わる直前に改ページするためのNewPageプロパティです。表3のように「After」と設定すれば、用紙の途中であっても、BillNoの値が異なるデータが来ると改ページします。
プロパティ | 値 |
---|---|
NewPage | After |
(2)[txtTotal]テキストボックス
[PageHeader]セクションに置かれた[txtTotal]テキストボックスは、請求書ごとの金額合計を印字するためのテキストボックスです。ActiveReportsのグループ合計機能を使うためには、次のようにプロパティを設定しています。
プロパティ | 値 |
---|---|
DataField | Price |
DistinctField | |
SummaryGroup | Bill_GroupHeader |
SummaryRunning | None |
SummaryType | SubTotal |
このようにプロパティを設定することで、データソースに存在する[Price]列の値を[Bill_GroupHeader]ヘッダに割り当てられた項目値(この場合BillNo)グループごとに中計(SubTotal)して、表示します。なお、SummaryRunningプロパティの値を設定すると、ページヘッダで正しく合計が計算されないので、注意してください。
(3)[txtPage]テキストボックス
[PageFooter]セクションに置かれた[txtPage]テキストボックスは、請求書ごとの通しページ番号を印字するためのテキストボックスです。ActiveReportsのページカウント機能を使うためには、次のようにプロパティを設定します。
プロパティ | 値 |
---|---|
DataField | |
DistinctField | |
SummaryGroup | Bill_GroupHeader |
SummaryRunning | Group |
SummaryType | PageCount |
もし、グループごとの総ページ数が必要な場合は、次のようにプロパティを設定します。
プロパティ | 値 |
---|---|
DataField | |
DistinctField | |
SummaryGroup | Bill_GroupHeader |
SummaryRunning | None |
SummaryType | PageCount |
帳票定義体にコードを記述する
WindowsフォームがSystem.Windows.Forms.Formクラスを継承したクラスであるのと同様に、ActiveReports帳票定義体はDataDynamics.ActiveReports.ActiveReport3クラスを継承したクラスです。よって、Windowsフォームの場合と同様、実行時の各種イベントに対してコードを組み込むことができます。
「CZ0905Bound」サンプルプロジェクトに組み込んだコードはリスト1になります。
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」では、下記のような手順で作業を行いました。
- mdbファイルとexeファイルが同じフォルダに配置されて動作するようにmdbファイルもプロジェクトに追加して、[出力ディレクトリにコピー]プロパティを「常にコピーする」に設定。
- Windowsフォームをプロジェクトに追加するか、新しいプロジェクトの作成時に自動的に作成されていたForm1.vbを、CZ0905Bound_Form.vbにリネーム。
- クラスファイルを追加し、CZ0905Bound.vbというファイル名に。

クラスにコードを記述する
CZ0905Boundクラスには、mdbファイルからデータを取得してDataSetを作成するコードを記述しています。Windowsフォームファイルとは別のファイルにしているのは、UI部分とデータアクセス部分を分離しておいた方がコードの見通しがよく、データソースをSQL ServerやOracleなどに切り替える時も変更範囲が明確化するためです。
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)。
DataSetに加えた変更はmdbファイルに反映してないため、mdbファイルの内容が変わるような事はありません。
Windowsフォームにコードを記述する
Windowsフォームの画面デザインはActiveReportsのViewerコントロールを貼り付け、Dockプロパティを「Fill」にすれば完成です。そして、DataSetと帳票定義体の2つをViewerコントロールに渡して、プレビュー表示するコードを記述しています。
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
実行
実行時には、請求書NO「WS-DF502」のデータを増やし、2ページに渡って印字されるようにしています。このように複数ページに渡るテストデータを用意しておく事で、同一グループ複数ページの挙動が調べられます。テストデータ作成時のちょっとした工夫ですが、後から予期せぬ問題が起きないようにするためには、非常に重要な事です。
レポートを印刷する
最近の傾向として、紙資源の有効活用やセキュリティの面から、業務アプリケーションを利用する際も、プレビュー画面で確認したら、印刷をせずPDF出力などで済ませてしまうことも多くなってきたように思います。しかしながら、夜間に締め処理をしてから自動的に印刷するようなバッチ処理や、データ入力後は自動的に印刷するような画面が必要な仕様のアプリケーションもたくさんあります。
ActiveReportsでは、WindowsフォームにViewerコントロールを張り付けてプレビュー表示から印刷するだけではなく、自動的に印刷・PDF出力する機能を追加することもできます。
「CZ0905Bound」サンプルに上記機能を追加したのが、「CZ0905PDF」サンプルプロジェクトです。「CZ0905Bound」は、データアクセス部分と帳票定義体とWindowsフォーム部分からできています。このため、Windowsフォーム部分だけを置き換え、他の2つの部分は流用するだけで、自動的にPDF出力する機能を追加できました。
Windowsフォームにコードを記述する前に、まず次の作業を行いました。
- 新しくWindowsフォームのプロジェクトを作成します。
- WindowsフォームにButtonコントロールを1つ配置して、「Pdf_Button」という名前にします。
- [既存の項目の追加]で、CZ0905BoundサンプルからSeikyu_Reports.vb、CZ0905Bound.vb、Bill.mdbの3つをプロジェクトにコピーし、追加します。
Windowsフォームにコードを記述する
「CZ0905PDF」サンプルプロジェクトには、Viewerを使わずに、仮想プリンタ定義に基づきパスワード付きPDFファイルを出力するコードを記述しています。
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ファイルが出力されます。

PDFファイルを開こうとすると、パスワードが要求されます。「CodeZine」と入力することで、PDFの内容が表示できます(大文字小文字の区別あり)。
まとめ
ここまで見てきたように、ActiveReportsはいくつかの点を押さえることで、Windowsアプリに帳票機能を効率的に追加できます。
次回は、Webアプリケーションの作成方法を紹介していきます。
実際にシステム構築で使ってみると、1番時間がかかるのは帳票定義体で罫線の位置を合わせる作業だったりします。
定義はコードとして*.Designer.vbに記述されているので、微妙な位置合わせを行う場合、設定箇所をコードから探し出し、プロパティの設定値を微調整すると、1発で決まります。テキストファイルなので、高機能なテキストエディタやVisual Studioの検索・置換機能を駆使すれば、効率的に定義できます。
Windowsフォームと同じように、帳票定義体のコントロール名などにも命名規約を適用して、コードでも見やすいように工夫するとさらに効率があがるでしょう(今回は製品添付サンプルを改造したので、命名規約などの適用は行っていません)。