はじめに
GcListBoxコンポーネントでは、リスト内のデータを検索して、指定した条件に一致するデータを抜き出すことができます。
そこで、今回はGcListBoxコンポーネントで表示した「ノートPCカタログ2008」というAccessのデータを、リスト内で発売日を条件に検索し、一致したデータをもう1つのGcListBoxコンポーネントで表示するプログラムを作成してみました。
対象読者
Visual Basic 2005またはVisual C# 2005を使ってプログラムを作ったことのある人。
必要な環境
Visual Basic 2005またはVisual C# 2005、Visual Studio 2005でプログラムが作れる環境。
なお、本プログラムはWindows Vista上で動作するVisual Studioを使用して作成し動作確認を行っています。
プログラム実行時の注意事項
InputMan for Windows Forms 5.0Jを使って作成したアプリケーションを配布する場合、InputMan for Windows Forms 5.0Jのアセンブリファイルを添付する必要があります。これは、Common Language RuntimeのDLLをアプリケーションと一緒に配布するのと同じです。アプリケーションを正常に動作させるためには、次の4つのファイルをインストールする必要があります。
- GrapeCity.Framework.InputMan.v20.dll…フレームワークアセンブリ
- GrapeCity.Win.Editors.V50.dll…本体コンポーネント
- GrapeCity.Framework.InputMan.v20.resources.dll…フレームワークアセンブリのサテライトリソース
- GrapeCity.Win.Editors.V50.resources.dll…本体コンポーネントのサテライトリソース
これらのファイルを、プログラムを実行するBinフォルダに格納します。.NET Framework 2.0から追加されたクラスやメンバを使用しているので、.NET Framework 2.0がインストールされていることが必須条件です。
コンポーネントのインストール
はじめてInputMan for Windows Forms 5.0Jを使用する方は、プロジェクトにInputMan for Windows Forms 5.0Jをインストールする必要があります。
インストーラは、グレープシティのWebページからダウンロードできますので、ここからダウンロードしてインストールしてください。製品ページ左側の[ダウンロード]-[トライアル版]をクリックし、ダウンロード方法([FTP]または[HTTP])を選択すれば入手できます。ファイルはLZH形式で圧縮されています。
有償のコンポーネントですが、プロダクトキーを入力せずにインストールすることで、トライアル版として使用できます。制限事項などの詳細については、インストーラに同梱されているリリースノートを参照ください。
コントロールの追加
InputMan for Windows Forms 5.0Jをインストールしたら、ツールボックスに専用のタブを作成し、InputMan for Windows Forms 5.0Jコンポーネントを追加します。
今回追加するコンポーネントは、「.NET Frameworkコンポーネント」の「名前空間」が「GrapeCity.Win.Editors」で始まる名前空間のコンポーネント「GcListBox」と「GcDate」です。
GUIの作成
GUIは、2つのGcListBoxコンポーネントと[GcDate][Button]を配置します。
データベース関係のコントロールは、[GcListBox]コンポーネントにデータベースをバインドすると作成されるコントロールです。また、[GcShortcut]コンポーネントは、[GcDate]コンポーネントを配置すると自動的にフォームに追加されます。
GcListBox(GcListBox1)コンポーネントの設定
1.
GcListBoxコンポーネント(GcListBox1)は、今回はテンプレートを使ってデザインします。タスクトレイの[テンプレート]メニューを選ぶと、16種類のテンプレートからデザインを選ぶことができます。ここでは、「Gradation4」を選んでみました。
2.
タスクトレイの[データバインド項目を使用する]メニューで、データベース「ノートPCカタログ2008」をバインドします。ウィザードで設定を進めていきますが、データセット内に指定するフィールドとしては「メーカー」「機種」「発売日」の3つを選びます。
3.
プロパティウィンドウでStatusBarプロパティを展開し、Visibleプロパティを「True」にします。
GcDateコンポーネントの設定
GcDateコンポーネントは、カレンダーを使って日付を入力できるコンポーネントです。デフォルトでは、現在の日付と時刻が表示されますが、このコンポーネントは入力と表示でそれぞれ表示書式を設定できるようになっています。
今回のプログラムでは、日付だけしか使いませんので、入力・表示ともに日付だけを扱うように設定します。日付の書式も、データベースのデータに合わせておきます。
1.
タスクトレイから[入力フィールドの編集]を選びます。エディタが表示されるので、[現在設定されている項目]の[すべて削除]ボタンを押してデフォルトの設定を削除します。
2.
その横にある[書式を指定してフィールドを設定]ボタンを押し、「YYYY/MM/dd」を選びます。これで、入力書式として日付だけが設定されるようになります。
GcListBox(GcListBox2)コンポーネントの設定
もう1つのGcListBoxコンポーネントは、ヘッダーだけを追加します。タスクトレイから[カラムの編集]を選び、エディタで3つのメンバを追加します。
それぞれ、Headerプロパティを展開し、Textプロパティをそれぞれ「メーカー」「機種」「発売日」に設定します。また、AutoWidthプロパティを「True」にしておきます。
使用するデータベース
使用するAccessのデータベースは、ノートPCの一覧という簡単なデータベースで、1つのテーブルに「ID」「メーカー」「機種」「発売日」の4つのフィールドがあります。実際に使用するのは「ID」を除くフィールドで、それぞれ「テキスト型」で入力されており、発売日は「yyyy/mm/dd」という形式で保存されています。
選択されたリスト項目の取得
最初に、リストを選択したときにその項目を取得して、GcListBoxコンポーネントのステータスバーに表示する処理を作成します。ユーザーがリストをクリックすると、GcListBoxコンポーネントにはSelectedIndexChangedイベントが発生しますので、ここで処理を行います。
現在選択されている項目は、GcListBoxクラスの「SelectedItem」プロパティを使って取得できます。このプロパティは、選択されている項目をListItemオブジェクトで返してきます。プログラムでは、単一の項目しか選択できないように設定していますが、GcListBoxコンポーネントは複数選択も可能で、その場合選択項目はすべてListItemオブジェクトとして返されます。
後は、このListItemオブジェクトのSubItemsプロパティで、参照したいフィールドをインデックス番号で指定して取り出します。
Dim li As ListItem = GcListBox1.SelectedItem Me.GcListBox1.StatusBar.Text = li.SubItems(0).Value
ListItem li = gcListBox1.SelectedItem; gcListBox1.StatusBar.Text = li.SubItems[0].Value
後は、必要な列の値をSubItemsプロパティをつなげていけば、選択した行のデータを取得できます。
ただし、このSelectedIndexChangedイベントがハンドルされている時にフォームを閉じると、以下のプロパティ値でイベントハンドラが呼び出されるようになっています。
プロパティ | 値 |
SelectedIndexプロパティ | -1 |
SelectedItemプロパティ | Nothing |
このままだと、NothingとなっているSelectedItemプロパティに対してSubItemsプロパティを参照することになってしまい、フォームを閉じる際に「オブジェクトが参照されていない」というエラーメッセージが出てしまいます。
この問題を回避するために、SelectedIndexプロパティを参照しこの値が0以上だった場合のみSubItemsプロパティを参照するようにします。
Private Sub GcListBox1_SelectedIndexChanged( _ ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles GcListBox1.SelectedIndexChanged If (GcListBox1.SelectedIndex < 0) Then Return End If Dim li As ListItem = GcListBox1.SelectedItem Me.GcListBox1.StatusBar.Text = li.SubItems(0).Value & _ " : " & li.SubItems(1).Value & _ " : " & li.SubItems(2).Value End Sub
private void gcListBox1_SelectedIndexChanged(object sender, EventArgs e) { if(gcListBox1.SelectedIndex < 0){ return; } ListItem li = gcListBox1.SelectedItem; gcListBox1.StatusBar.Text = li.SubItems[0].Value + " : " + li.SubItems[1].Value + " : " + li.SubItems[2].Value; } }
リスト内を検索する処理
冒頭でも述べましたが、GcListBoxコンポーネントはリスト内を検索して、データを取り出す機能を持っています。
そこで、この機能を使い日付でリスト内のデータを検索し、一致するデータをもう1つのGcListBoxコンポーネントで表示する機能を組み込んでみます。
FindStringメソッドとMatchedListItemCollection
検索を行うには、FindStringメソッドを使用します。検索用のメソッドは3つありますが、FindStringメソッドは文字列を検索条件に設定できます。このプログラムでは、日付を文字列で入力していますから、FindStringメソッドで検索をします。
引数は2つで、最初の引数に検索条件となる文字列を、2番目の引数に検索を行う列番号を指定します。ここでは、GcDateコンポーネントで入力された日付を元に、リストの3番目の列を対象に検索を行います。GcDateコンポーネントのTextプロパティを参照すると、選択された日付を文字列で取得することができますので、これをFindStringメソッドの第1引数に設定します。
一致するデータが見つかると、FindStringメソッドはそのデータをMatchedListItemCollectionオブジェクトで返してきます。複数のデータが見つかれば、次々とこのMatchedListItemCollectionオブジェクトに追加されていくことになります。
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Dim matchedItem As MatchedListItemCollection Dim item As ListItem Dim additem As ListItem 'FindObjectメソッドを使って検索 ' 検索結果はMatchedListItemCollectionに格納される matchedItem = GcListBox1.FindString(Me.GcDate1.Text, 2)
private void button1_Click(object sender, EventArgs e) { MatchedListItemCollection matchedItem; ListItem additem; //FindObjectメソッドを使って検索 // 検索結果はMatchedListItemCollectionに格納される matchedItem = gcListBox1.FindString(gcDate1.Text, 2);
検索結果のリスト化
このMatchedListItemCollectionのCountプロパティを調べることで、検索結果があるかどうかを知ることができますので、検索結果がある場合のみ、もう1つのGcListBoxコンポーネントにリストとして組み込みます。
まず、すでにリストがある場合はこれを削除します。GcListBoxクラスのItemsコレクションのClearメソッドを使用すると、GcListBoxコンポーネントに組み込まれているリストをすべて削除します。
次に、For Eachステートメントで、MatchedListItemCollection内のオブジェクトにアクセスし、検索結果1レコード分のフィールド1つ1つをSubItemオブジェクトとして作成し、これをまとめてListItemオブジェクトにします。そして、できあがったListItemオブジェクトをGcListBoxコンポーネントに組み込みます。
この処理を、MatchedListItemCollection内のすべてのオブジェクト(すべてのレコード)に対して行い、検索結果のデータを全部リスト化していきます。
'検索結果があるかどうかを判別 If matchedItem.Count = 0 Then MessageBox.Show("一致するデータはありません", _ "検索結果", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Else 'すでにリストがある場合は一度削除する Me.GcListBox2.Items.Clear() For Each item In matchedItem 'データ1件の各列データをそれぞれSubItemオブジェクトにする Dim sbitem1 As New SubItem(item.SubItems(0).Value.ToString) Dim sbitem2 As New SubItem(item.SubItems(1).Value.ToString) Dim sbitem3 As New SubItem(item.SubItems(2).Value.ToString) 'SubItemオブジェクトをまとめてListItemオブジェクトにする additem = New ListItem(sbitem1, sbitem2, sbitem3) 'できあがったListItemオブジェクトを 'GcListBoxコンポーネントに組み込む GcListBox2.Items.Add(additem) '検索されたデータの数だけListItemオブジェクトが作られ 'GcListBoxコンポーネントに組み込まれる Next End If End Sub
//検索結果があるかどうかを判別 if(matchedItem.Count == 0){ MessageBox.Show("一致するデータはありません", "検索結果", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); }else{ //すでにリストがある場合は一度削除する gcListBox2.Items.Clear(); foreach(ListItem item in matchedItem){ //データ1件の各列データをそれぞれSubItemオブジェクトにする SubItem sbitem1 = new SubItem(item.SubItems[0].Value); SubItem sbitem2 = new SubItem(item.SubItems[1].Value); SubItem sbitem3 = new SubItem(item.SubItems[2].Value); //SubItemオブジェクトをまとめてListItemオブジェクトにする additem = new ListItem(sbitem1, sbitem2, sbitem3); //できあがったListItemオブジェクトを //GcListBoxコンポーネントに組み込む gcListBox2.Items.Add(additem); //検索されたデータの数だけListItemオブジェクトが作られ //GcListBoxコンポーネントに組み込まれる } } }
まとめ
ベースとなるリストから別のリストを作成することはよくあることですが、データベースからクエリで取得したデータに対してリスト上で検索・抽出ができるとなると、改めてデータベースに対してクエリを実行する必要がありませんから、処理速度も上がりサーバに対する負荷も少なくなります。
このような点を考えると、このGcListBoxコンポーネントはかなり使い勝手がよいコンポーネントだと思います。