はじめに
Visual Studioには、標準でたくさんのコントロールが用意されていますが、もう少し「あんなこと、こんなことができればいいのにな」と思うことがあると思います。また、ちょっと複雑なことをしようとすると、それに応じたコーディングが必要になり、手間がかかってしまいます。
ComponentOne Studio(コンポーネントワンスタジオ、以下「C1Studio」)には標準で用意されているコントロールには無い、便利で充実した機能が実装されたコンポーネントが多数収録されています。このコンポーネントは単体でも使い勝手のよいものですが、ちょっと工夫しながら組み合わせることで驚くほど簡単にアプリケーションを作り上げることができるのです。
この連載では売上管理アプリケーションを例に、誰でも手軽に「組み合わせの達人」になれる方法を紹介します。前回は第一歩としてC1Studioに収録されているFlexGridを使いながら売上データ一覧表の土台を作成しました。今回はFlexGridに実装されている便利な機能を用いて、アプリケーションをパワーアップしていきます。
前回の記事
対象者
- .NETでWindowsアプリケーションを作ったことのある方、または作りたい方
- 標準のコントロールでは物足らなくなってきた方
- DBの知識がある程度ある方
必要な環境
- Visual Studio 2005または、2008が利用できる環境
- SQL Server 2005が利用できる環境
プログラム実行時の注意事項
サンプルアプリケーションは、Visual Studio 2008で作成しています。実行する場合は、.NET Framework 3.5がインストールされていることが必須条件です。
また、最低限の値チェックや、整合性チェックしか行っていないので、一意違反等に引っかかる可能性があることをご了承ください。
カテゴリを追加してみよう
前回作成した売上管理アプリケーションでは、「売上金額」「仕入金額」を日付単位で入力できるようにしていました。しかし、実際の店舗ではさまざまな商品を扱っており、商品カテゴリごとに集計したい場合もあるはずです。そこで、日付単位でなく商品カテゴリごとに金額の管理ができるよう、カテゴリ項目を追加してみたいと思います。
まず、画面上のFlexGridに列を追加してみましょう。FlexGridに列を追加するには、列エディタを利用します。列エディタで任意の場所に列を追加・削除できるので、ここでは「日付」と「売上金額」の間に「商品カテゴリ」の列を追加します。
次に、商品カテゴリの列に表示用の値を設定します。DataMapを使用して、データ値を表示値に変換するカテゴリマスタを別に用意しておきます。このコード値を指定することで、カテゴリ名称を表示できるようになります。今回はFlexGridを編集不可にしましたが、編集可能な場合、ドロップダウンリストに値を挿入できるようにするためにDataMapを使用しています。
ListDictionary dictionary = new ListDictionary(); dictionary.Add("カテゴリコード", "カテゴリ名称"); this.c1FlexGrid1.Cols[1].DataType = typeof(int); this.c1FlexGrid1.Cols[1].DataMap = dictionary;
ListDictionaryには、キーとしてカテゴリコードを、値としてカテゴリ名称を追加します。以上で「商品カテゴリ」列の追加とDataMapの設定が完了しました。
入力用の画面を追加してみる
次にデータ入力の機能を改善します。前回は、FlexGridに直接入力することで、データを追加・変更していました。しかし、実際にアプリケーションとして使用する場合、この方法だと煩雑すぎて不便です。
そこで、入力用の専用画面を作成してみたいと思います。入力する場合は専用のポップアップ画面を表示し、データを登録するようにします。
まず、プロジェクトにポップアップ用のFormを追加します。Form上で、「日付」「カテゴリ」「売上金額」「仕入金額」を入れられるように各コントロールを配置します。
public object CategoryCode { get { return this.comboBox1.SelectedValue; } set { this.comboBox1.SelectedValue = value; } }
次に、各コントロールの入力値を呼び出し元のメイン画面で取得・設定できるように、以下のコードを追加します。
this.c1FlexGrid1.AddItem(new object[] { "日付", "カテゴリコード", "売上金額", "仕入金額" });
this.c1FlexGrid1["行番号", 0] = "日付"; this.c1FlexGrid1["行番号", 1] = "カテゴリコード"; this.c1FlexGrid1["行番号", 2] = "売上金額"; this.c1FlexGrid1["行番号", 3] = "仕入金額";
以上で入力専用画面の実装は終了です。後はポップアップ画面が閉じられたときに、自動的に入力値を取得し、FlexGrid上に値が反映されるようになります。これで数値の入力も気軽にできるようになりました。
小計行・合計行を追加してみよう
ここまで数レコードレベルでの改良を行ってきましたが、売上管理アプリケーションでは、月次での合計も必要だと思います。1ヶ月間の合計行を追加してみることにしましょう。
また今回、カテゴリも追加したため、同一日のデータが複数行になる場合も出てきました。そのため、日付単位での小計行も算出したいと思います。
小計行・合計行を追加するには、単純にそれぞれの列ごとの値を合計し、計算結果を表示する行を追加する方法があります。しかしここでは、FlexGridのデータ集計機能を利用して簡単に実現したいと思います。
集計値の計算にはSubtotalメソッドを利用します。
// 小計をクリアします。 this.c1FlexGrid1.Subtotal(AggregateEnum.Clear); // グリッドをソートします。 this.c1FlexGrid1.Sort(SortFlags.Ascending, 0, 1); // 合計行を算出します。 this.c1FlexGrid1.Subtotal(AggregateEnum.Sum, -1, -1, 2, "合計"); // 小計行を算出します。 this.c1FlexGrid1.Subtotal(AggregateEnum.Sum, 0, 0, 2, "{0:MM/dd} 小計");
まず最初に事前に設定されている集計行を削除します。次に日付順に表示し、商品カテゴリで分類するために、この2つのフィールドでソートしておきます。
合計や小計を算出する場合、SubTotalメソッドの第1引数には集計関数の種類としてSumを指定します。そして第2~第4引数でアウトラインレベル、グルーピングする列、および集計を行う列を指定します。
「グルーピングする列」は、合計では特定の列インデックスの代わりに-1を使用します。日付単位での小計の算出を行う場合は、0列(日付)を指定します。「集計を行う列」は、合計、小計とも2列(売上金額)を指定します。
最後に、合計行の見出しとして「合計」を指定します。小計行の見出しには、日付を表示するためプレースホルダを指定しています。
以上で集計行の実装は完成です。
今回は集計行の説明のため、粗利率については平均値を算出するAverageを指定します。合計値での粗利率が算出されていないことをご了承ください。
最後に集計行を目立たせるために表示を少し変えてみましょう。
CellStyle cellStyle = c1FlexGrid1.Styles[CellStyleEnum.GrandTotal]; cellStyle.BackColor = Color.Blue; cellStyle.ForeColor = Color.White; cellStyle.Font = new Font(Font, FontStyle.Bold); cellStyle = this.c1FlexGrid1.Styles[CellStyleEnum.Subtotal0]; cellStyle.BackColor = Color.Orchid; cellStyle.ForeColor = Color.White; cellStyle.Font = new Font(Font, FontStyle.Bold);
表示を切り替えるにはセルスタイルを指定します。今回は背景色を青に、文字色を白にしてみました。さらに太字に設定しています。小計行のセルスタイルも同様に変更しました。
では、実行してみましょう。FlexGridの1番下に合計行が表示されたでしょうか。また、日付単位での小計行も表示されていると思います。このように、FlexGridのメソッドを利用することで簡単に集計行を追加することができます。
利益率をビジュアル的に表現する
さらに変更を加えていきましょう。集計行と同様、利益率の列についても色を変えてみたいと思います。利益率については、どれだけ利益率が高いのかをビジュアル的に捉えられるように、利益率に見合う割合でセルを塗り潰してみましょう。
まず、FlexGridのDrawModeプロパティをNormalからOwnerDrawに変更します。これにより、セルの描画が発生するタイミングでOwnerDrawCellイベントを発生させることができます。
OwnerDrawCellイベント発生時のソースは以下のようになります。
// 横幅を計算する。 Rectangle rc = this.c1FlexGrid1.GetCellRect(e.Row, "列インデックス"); rc.Width = (int)(this.c1FlexGrid1.Cols[e.Col].WidthDisplay * "利益率"); // 背景を描画する。 e.DrawCell(DrawCellFlags.Background | DrawCellFlags.Border); // 棒グラフを描画する。 rc.Inflate(-2, -2); e.Graphics.FillRectangle(Brushes.LimeGreen, rc); rc.Inflate(-1, -1); e.Graphics.FillRectangle(Brushes.PaleGreen, rc); // セルの内容を描画する。 e.DrawCell(DrawCellFlags.Content);
まず、対象になるセル(利益率を表示しているセル)の大きさを取得します。
次に、実際の利益率の割合で横幅を算出します。算出結果からセルの背景、境界線を描画し、境界線部分と内側部分の色を付けて、横向きの棒グラフを描画します。最後にセルの内容(利益率)を描画します。
これだけで、横向きに棒グラフの様なイメージが完成します。後は、描画する棒グラフの色を、好みの色に調整してみてください。
グリッドのデータを印刷してみよう
売上管理アプリケーションでは、売上票を印刷できる機能も必要だと思います。FlexGridでは、これらの機能も簡単に実装することができます。
FlexGridの内容を印刷するにはPrintGridメソッドを利用します。以下のコーディングだけで印刷が可能になります。
this.c1FlexGrid1.PrintGrid("ドキュメント名称", 印刷オプション, "ヘッダー", "フッター");
また、印刷オプションを設定することにより、用紙1枚に調整して印刷したり、プレビューダイアログを表示したりできます。今回の場合、ヘッダー部分に「○○月度」と設定し、フッター部分にページ番号を表示してみましょう。
string title = string.Format("{0}月度売上表", this.dateTimePicker1.Value.Month); this.c1FlexGrid1.PrintGrid(title, PrintGridFlags.FitToPage| PrintGridFlags.ShowPreviewDialog, title, (char)(9) + "" + (char)(9) + "Page {0}/{1}");
ヘッダー文字列、フッター文字列は、タブ区切りで3つのセクションに分けられています。今回のサンプルでは、ヘッダーは左詰、フッターは右詰のため、フッター部分にタブを2つ追加してあります。
ページ番号を指定している部分の「{0}」「{1}」は、それぞれ現在のページ番号とページ総数のプレースホルダになっています。
まとめ
今回は、FlexGridに実装されている機能を使用して「合計行の追加」「セルの描画」「グリッドデータの印刷」を行いました。簡単なメソッドの呼び出しを行うだけで、集計計算やビジュアルの変更、印刷処理を行うことができたかと思います。
次回からは、FlexGridと他のコントロールとを連携したり、PDFファイルを出力したりし、さらなるバージョンアップを図っていこうと思います。