はじめに
前回は、「PowerTools ComponentOne Studio 2012J」の「C1Chart(2D)」コントロールと「C1FlexGrid」コントロールを使用して、データを直接グリッドに入力しリアルタイムにデータをバブルチャートで表示するアプリケーションを作成しました。
そこで、C1FlexGridコントロールがデータベースと連結してデータを直接読み込んで表示できる機能を利用し、このアプリケーションをいろいろなデータベースからデータを読み込んでバブルチャートを作れるように改良してみました(今回はAccessデータベースファイルを使用しています)。
対象読者
Visual Basic 2005/2008/2010、またはVisual C# 2005/2008/2010を使ってプログラムを作ったことがある人。
必要な環境
Visual Basic 2005/2008/2010、Visual C# 2005/2008/2010、Visual Studio 2005/2008/2010のいずれかでプログラムが作れる環境。
なお、本プログラムはWindows 7上で動作するVisual Studio 2010を使用して作成し、動作確認を行っています。
プログラム実行時の注意事項
「PowerTools ComponentOne Studio 2012J」を使って作成したアプリケーションを配布する場合、「PowerTools ComponentOne Studio 2012J」のアセンブリファイルを添付する必要があります。これは、Common Language RuntimeのDLLをアプリケーションと一緒に配布するのと同じです。
本記事のサンプルアプリケーションを正常に動作させるためには、次のファイルをインストールする必要があります。
ファイル名 | 説明 |
C1.C1FlexGrid.2.dll | 本体アセンブリ |
C1.C1FlexGrid.4.dll | 本体アセンブリ(※) |
C1.Win.C1Chart.2.dll | C1Chart本体アセンブリ |
C1.Win.C1Chart.4.dll | C1Chart本体アセンブリ(※) |
このファイルを、プログラムを実行するフォルダに格納します。
.NET Framework 2.0から追加されたクラスやメンバを使用しているので、.NET Framework 2.0以上のバージョンの.NET Frameworkがインストールされていることが必須条件です。
コンポーネントのインストール
「PowerTools ComponentOne Studio 2012J」を使用するには、開発環境(Visual Studio/Visual Basic/Visual C#)に、「PowerTools ComponentOne Studio 2012J」をインストールする必要があります。
インストーラは、グレープシティのWebページからダウンロードできます。
ダウンロードしたい製品にチェックを付け[申込フォーム]ボタンを押すと、「トライアル版申込フォーム」ページに移動しますので、「個人情報の収集および使用に同意する」にチェックを入れ「同意する」ボタンをクリックします。
トライアル申込フォームが表示されますので、必要情報を登録すると添付トライアルライセンスキーファイルとダウンロードサイトを記載したE-Mailが送られてきます。ここからダウンロードします。ダウンロードファイルは圧縮ファイルになっていますので、解凍してインストーラを起動します。
制限事項などの詳細については、インストーラに同梱されているリリースノートを参照ください。
コントロールの追加
「PowerTools ComponentOne Studio 2012J」をインストールしたら、プロジェクトにコントロールを追加します。
ツールボックスに専用のタブを作成し、使用するコンポーネントを追加します。追加するコンポーネントはアセンブリ名が「C1.Win.C1FlexGrid.4」の「C1FlexGrid」コントロールと、アセンブリ名が「C1.Win.C1Chart.4」の「C1Chart」コントロールです。
コントロール | アセンブリ |
C1FlexGrid | C1.Win.C1FlexGrid.4 |
C1Chart | C1.Win.C1Chart.4 |
データベースの連結方法
C1FlexGridコントロールは、ADO.NETデータソースオブジェクト(DataTable、DataView、DataSet、DataViewManagerなど)へのデータ連結をサポートします。
グリッドをデータソースに連結するには、データソースオブジェクトを作成し、グリッドのDataSourceプロパティに設定します。データソースオブジェクトが複数のテーブルを持っている場合は、使用テーブルを指定する文字列をDataMemberプロパティに設定します。また、SetDataBindingメソッドを使うと、両方のプロパティを同時に設定することもできます。
新しいデータソースをグリッドに割り当てると、グリッドは自動的にその列を更新してデータソース内で使用可能な列に連結します。
データソースを連結する方法
データソースをグリッドに連結する方法は2通りあります。
1つは、Visual Studioのデータソース構成ウィザードを使用してC1FlexGridコントロールにデータソースを連結する方法です。この方法を使うと、ウィザードの質問に答えていくだけで、簡単にデータベースをグリッドに連結できます。ただし、この方法はアプリケーションに1つのデータベースファイルを固定してしまいますので、複数のデータベースを切り替えてグリッドにデータを表示するのには向いていません。
もう一つの方法は、コードからデータベースオブジェクトを作成し、グリッドに連結する方法です。この方法だと、例えばダイアログボックスでデータベースファイルを選んでグリッドに表示する機能を組み込むことができます。しかし、データを取り出すクエリを入力する機能も持たせないと、データベースからデータを抽出することができません。
それぞれ、データベースを使用する目的に応じて使い分けることになります。
今回は、ダイアログボックスでAccessのデータベースファイルを選んでグリッドに表示するようにしますので、コードからデータベース連結を行います。
データベース連結の手順
コードからデータベースファイルをグリッドに連結するには、以下の手順をとります。
- (1)接続文字列を作成する
- (2)開くデータベースファイルを指定する
- (3)クエリ文字列を作成する
- (4)接続文字列とクエリ文字列を使用してOleDbDataAdapterオブジェクトを作成する
- (5)OleDbDataAdapterクラスのFillメソッドでDataSetオブジェクトにクエリの結果セットを格納する
- (6)C1FlexGridコントロールのDataSourceプロパティに、DataSetオブジェクトのテーブルを設定する
(1)から(5)までの処理は、ADO.NETのデータベース接続処理です。これは、ウィザードを使用したデータベース連結も同じで、ウィザードがコードを書く代りをやってくれているだけです。
(6)のコードが、クエリの結果セットをグリッドに表示するための連結処理です。C1FlexGridコントロールは、DataSourceプロパティの値が変わると、自動的にグリッドの行列を作成してセルにデータを格納し、データベースの列見出しをグリッドの列ヘッダに設定してくれるので、データベースの連結処理はたったこの1行で済みます。
プログラマがやることは、開くデータベースファイルを指定し、データを取り出すクエリ文(SQL文)を作成するだけです。
あとは、お好みでグリッドの各種装飾やフィルタリング、小計処理などのオプション機能を操作するコードを書いていきます。
GUIのデザイン
今回は、前回作成したフォームに手を加え、データベースファイルの選択とクエリ文の入力機能を追加します。追加するコントロールは、ButtonコントロールとOpenFileDialogコントロールの2つです。クエリ文の入力は、コードからInputBoxを表示して入力してもらうようにします。
フォームのデザイン
Buttonコントロールを1つ追加し、Clickイベントハンドラを作成します。
OpenFileDialogコントロールは、Filterプロパティを設定しAccessデータベースファイルを選べるようにします。
プロパティ | 設定値 |
FileName | (空白) |
Filter | Accessファイル(*.mdb)|*.mdb |
データベース連結処理の実装
まずは、グリッドをデータベースに連結する処理を作成します。この処理は、ボタン「データベースの読み込み」のClickイベントハンドラで行います。
なお、System.Data.OleDb名前空間への参照を追加しておいてください。
また、クエリ文の入力にインプットボックスを使用します。これは、Visual BasicのInputBoxメソッドを使用しますので、C#で使う場合はプロジェクトの参照設定に「Microsoft.VisualBasic」を追加しておいてください。
(1)最初に、DBファイル名の取得と接続文字を作成します。データベースファイル名は、OpenFileDialogコントロールを使用して取得します。また、接続文字列は変数connに作成します。Accessデータベースは、Microsoft.Jet.OLEDB.4.0データベースプロバイダを使用します。
(2)次に、クエリ文(SQL文)の入力を受け付けます。ここでは処理を簡単にするために、インプットボックスに直接クエリ文を入力してもらうことにしました。入力するクエリ文は、データベース側で事前に抽出用クエリを作成し、そのSQL文を入力するだけ済みます。
インプットボックスは、InteractionクラスのInputBoxメソッドを使用し、ユーザーに1行入力ができるダイアログを表示します。引数にプロンプトとタイトル、表示位置などを指定し、ユーザーが入力してOKボタンを押すと入力文字列を返してきます。キャンセルボタンが押されると空白の文字列を返してきますのでこれを判断し、文字列が入力された場合のみ文字列を変数に格納します。キャンセルボタンが押されれば処理を中止します。
なお、InputBoxメソッドは、Visual Basicでは簡単に使用でき引数を省略しても大丈夫なのですが、C#の場合は引数を省略してしまうとエラーになりますので引数の個数が一致するように記述します。
(3)クエリを実行しDataSetにデータを取り込みます。接続文字列とクエリ文が作成できたら、OleDbDataAdapterクラスのインスタンスを作成します。コンストラクタの引数には、作成した接続文字列とクエリ文を指定します。
そして、Fillメソッドを実行します。引数にはDataSetオブジェクトを作成し指定します。Fillメソッドは、指定したデータテーブルからクエリを実行してデータを抽出し、DataSetオブジェクト内にクエリの結果セットをテーブルとして作成します。
(4)作成した結果セットのテーブルを、C1FlexGridコントロールのDataSourceプロパティにセットします。これで、グリッドにクエリの結果が格納されます。
Accessデータベースのテーブルデータは、先頭列にインデックス番号が主キーとして付加されている場合が多いので(今回のサンプルデータも先頭列が主キーのインデックスになっています)、これをグリッドから削除しておきます。
以上で、C1FlexGridコントロールのデータ連結処理はでき上がりです。
'★ 名前空間を追加 Imports System.Data.OleDb '★ 新規追加処理-グリッドのデータ接続 Private Sub Button5_Click(sender As System.Object, e As System.EventArgs) Handles Button5.Click '(1)DBファイル名の取得と接続文字の作成 Dim dbname As String = "" If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then dbname = OpenFileDialog1.FileName else Exit Sub End If Dim conn As String = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & dbname 'サンプルデータベース用クエリ文字列 'SELECT chart_data.* FROM chart_data 'SELECT 台風発生個数の推移.* FROM 台風発生個数の推移 '(2)SQL文の入力 Dim sqlstr As String = InputBox("クエリのSQL文字列を入力してください", "テーブルの取り込み") If sqlstr = "" Then Exit Sub End If '(3)クエリを実行しDataSetにデータを取り込む Dim data_adap As OleDbDataAdapter = New OleDbDataAdapter(sqlstr, conn) Dim data_sset As DataSet = New DataSet() data_adap.Fill(data_sset) '(4)グリッドにデータを接続 C1FlexGrid1.DataSource = data_sset.Tables(0) C1FlexGrid1.Cols.Remove(1) 'キー列を削除 End Sub
// ★ 名前空間を追加 using System.Data.OleDb; // ★ 新規追加処理-グリッドのデータ接続 private void button5_Click(object sender, EventArgs e) { // (1)DBファイル名の取得と接続文字の作成 string dbname = ""; if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { dbname = openFileDialog1.FileName; } else { return; } string conn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + dbname; // サンプルデータベース用クエリ文字列 // SELECT chart_data.* FROM chart_data // SELECT 台風発生個数の推移.* FROM 台風発生個数の推移 //(2)SQL文の入力 string sqlstr = Microsoft.VisualBasic.Interaction.InputBox("クエリのSQL文字列を入力してください", "テーブルの取り込み", "", 200, 100); if(sqlstr == "") { return; } //(3)クエリを実行しDataSetにデータを取り込む OleDbDataAdapter data_adap = new OleDbDataAdapter(sqlstr, conn); DataSet data_sset = new DataSet(); data_adap.Fill(data_sset); //(4)グリッドにデータを接続 c1FlexGrid1.DataSource = data_sset.Tables[0]; c1FlexGrid1.Cols.Remove(1); //キー列を削除 }
public static string InputBox( string Prompt, string Title, string DefaultResponse, int XPos, int YPos )
Prompt
必須。ダイアログボックスにメッセージとして表示するString式です。Promptの最大長は、約1024文字です。使用される文字の幅によって変わります。Promptが複数の行で構成される場合、復帰文字(Chr(13))、ラインフィード文字(Chr(10))、または復帰とラインフィードの組み合わせ(Chr(13)およびChr(10))を各行の間で使用して、行を分割できます。
Title
省略可能。ダイアログボックスのタイトルバーに表示されるString型の式。Titleを省略した場合、タイトルバーにはアプリケーションの名前が表示されます。
DefaultResponse
省略可能。他に入力がない場合に、テキストボックスに既定値として表示されるString型の式。DefaultResponseを省略すると、表示されるテキストボックスは空になります。
XPos
省略可能。ダイアログボックスの左端から画面の左端までの距離をtwip単位で指定する数式です。XPosを省略すると、ダイアログボックスの水平位置が中央になります。
YPos
省略可能。ダイアログボックスの上端から画面の上端までの距離をtwip単位で指定する数式です。YPosを省略すると、ダイアログボックスは垂直方向に対して画面の上端から約1/3の位置に配置されます。
バブルチャート作成処理
グリッドのデータが更新されたので、これに基づくバブルチャート作成処理も修正を加えます。修正点は、グリッドの行列数と列見出しの数がデータベースごとに変わりますので、これをグリッドの変化に対応できるようにする部分です。
データ用配列の要素数をデータ数に合わせるように修正
まずは、チャート作成用データがグリッドのデータ数によって変化しますので、これに合わせてデータを格納する配列の要素数も変えられるようにします。前回のアプリケーションでは、要素数を7個に固定していましたので、これを変数に変えます。
チャート化するデータ数は、グリッドの行数で把握できます。これは、C1FlexGridコントロールのRowsコレクションオブジェクトのCountプロパティで取得できます。要素数のインデックスは0から始まりますから、Countプロパティの値から1を差し引きます。
要素数の確保は、Visual BasicではReDimステートメントで、C#では配列の宣言時に行います。配列が確保できたら、C1FlexGridコントロールのGetDataDisplayメソッドでデータを取得していきます。
'----------------------- グラフ作成 ---------------------------------------------------- Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click 'Dim xp(6) As Integer 'Dim yp(6) As Integer 'Dim vol(6) As Integer 'Dim i As Integer 'グリッドからデータを取得 'For i = 0 To 6 ' xp(i) = Convert.ToInt16(C1FlexGrid1.GetDataDisplay(i + 1, 2)) ' yp(i) = Convert.ToInt16(C1FlexGrid1.GetDataDisplay(i + 1, 3)) ' vol(i) = Convert.ToInt16(C1FlexGrid1.GetDataDisplay(i + 1, 4)) 'Next i '★ 配列数の確保をデータ数に合わせるように修正 Dim rownum As Integer = C1FlexGrid1.Rows.Count - 2 Dim xp() As Integer Dim yp() As Integer Dim vol() As Integer Dim i As Integer ReDim xp(rownum) ReDim yp(rownum) ReDim vol(rownum) For i = 0 To C1FlexGrid1.Rows.Count - 2 xp(i) = Convert.ToInt16(C1FlexGrid1.GetDataDisplay(i + 1, 2)) yp(i) = Convert.ToInt16(C1FlexGrid1.GetDataDisplay(i + 1, 3)) vol(i) = Convert.ToInt16(C1FlexGrid1.GetDataDisplay(i + 1, 4)) Next i
//----------------------- グラフ作成 ---------------------------------------------------- private void button2_Click(object sender, EventArgs e) { //int[] xp = new int[7]; //int[] yp = new int[7]; //int[] vol = new int[7]; //int i; ////FlexGridからデータを取得 //for(i=0; i<=6; i++) //{ // xp[i] = Convert.ToInt16(c1FlexGrid1.GetDataDisplay(i + 1, 2)); // yp[i] = Convert.ToInt16(c1FlexGrid1.GetDataDisplay(i + 1, 3)); // vol[i] = Convert.ToInt16(c1FlexGrid1.GetDataDisplay(i + 1, 4)); //} // ★ 配列数の確保をデータ数に合わせるように修正 int rownum = c1FlexGrid1.Rows.Count - 1; int[] xp = new int[rownum]; int[] yp = new int[rownum]; int[] vol = new int[rownum]; int i; //FlexGridからデータを取得 for (i = 0; i <= c1FlexGrid1.Rows.Count-2; i++) { xp[i] = Convert.ToInt16(c1FlexGrid1.GetDataDisplay(i + 1, 2)); yp[i] = Convert.ToInt16(c1FlexGrid1.GetDataDisplay(i + 1, 3)); vol[i] = Convert.ToInt16(c1FlexGrid1.GetDataDisplay(i + 1, 4)); }
データラベルの修正と表示範囲の自動設定を追加
チャートデータが設定できたら、データラベルを更新する処理を作成します。
また、チャートデータが入れ替わりますので、データの表示範囲も一度リセットするために、最大値と最小値を自動的に設定できるようにします。
(1)新しいチャートデータに合わせてラベルを新しく作り直します。ラベルデータの作成は前回と同じですが、Forループの繰り返し回数をチャートデータ数に合わせます。
(2)そして、ChartAreaクラスのAxisX、AxisYオブジェクトの「AutoMax」「AutoMin」プロパティをTrue設定し、チャートの表示範囲をデータに合わせる自動設定に切り替えておきます。この処理をしておかないと、チャートデータが切り替わってもXY軸の軸目盛は変わらない、という状態になってしまいます。
以上ででき上がりです。
'ラベルの作成 Dim lab As C1.Win.C1Chart.Label ' 一度ラベルを削除 If C1Chart1.ChartLabels.LabelsCollection.Count > 0 Then C1Chart1.ChartLabels.LabelsCollection.RemoveAll() End If '(1)★ ラベルの個数を修正しデータ数に自動設定 'For i = 0 To 6 For i = 0 To C1FlexGrid1.Rows.Count - 2 lab = C1Chart1.ChartLabels.LabelsCollection.AddNewLabel() lab.Text = C1FlexGrid1.GetDataDisplay(i + 1, 1) lab.Compass = LabelCompassEnum.East lab.AttachMethod = AttachMethodEnum.DataIndex lab.AttachMethodData.GroupIndex = 0 lab.AttachMethodData.SeriesIndex = 0 lab.AttachMethodData.PointIndex = i lab.Style.BackColor = Color.Transparent lab.Visible = True Next '(2)★ 一度表示範囲を自動にリセット C1Chart1.ChartArea.AxisX.AutoMax = True C1Chart1.ChartArea.AxisX.AutoMin = True C1Chart1.ChartArea.AxisY.AutoMax = True C1Chart1.ChartArea.AxisY.AutoMin = True End Sub
//ラベルの作成 C1.Win.C1Chart.Label lab ; // 一度ラベルを削除 if(c1Chart1.ChartLabels.LabelsCollection.Count>0) { c1Chart1.ChartLabels.LabelsCollection.RemoveAll(); } //(1)★ ラベルの個数を修正しデータ数に自動設定 // for (i = 0; i <= 6; i++) for (i = 0; i <= c1FlexGrid1.Rows.Count-2; i++) { lab = c1Chart1.ChartLabels.LabelsCollection.AddNewLabel(); lab.Text = c1FlexGrid1.GetDataDisplay(i + 1, 1); lab.Compass = LabelCompassEnum.East; lab.AttachMethod = AttachMethodEnum.DataIndex; lab.AttachMethodData.GroupIndex = 0; lab.AttachMethodData.SeriesIndex = 0; lab.AttachMethodData.PointIndex = i; lab.Style.BackColor = Color.Transparent; lab.Visible = true; } //(2)★ 一度表示範囲を自動にリセット c1Chart1.ChartArea.AxisX.AutoMax = true; c1Chart1.ChartArea.AxisX.AutoMin = true; c1Chart1.ChartArea.AxisY.AutoMax = true; c1Chart1.ChartArea.AxisY.AutoMin = true; }
まとめ
チャートデータにデータベースが使えるようになると、アプリケーションの利用範囲も広がります。
サンプルアプリケーションなので、チャートデータの抽出に直接クエリ文を入力するようにしましたが、ユーザーフレンドリーなアプリケーションに仕上げるのであれば、このクエリの入力処理も簡単にできるように作成しておくと良いですね。
また、バブルチャートもChartAreaクラスのメンバを使用すればより細かな装飾ができますし、元データの列数から棒グラフや折れ線グラフも表示できるような機能を実装すれば、より使い勝手のあるチャート作成アプリケーションに仕上げることができます。
今回は、Accessのデータベースファイルを使用しましたが、ADO.NETで使用できるデータベースであればどのようなデータベースでもデータを抽出してグラフ化できます。