C#で作る、あなただけのメモ帳 ~検索機能の実装~
はじめに
このブログでは、"Windows アプリケーションってどう作るのかよくわからない" といったプログラマ向けに Visual C# 2008 Express Edition (無償) を使用した Windows アプリケーションに作り方について説明しています。
Visual C# 2008 Express Edition (無償)(※) の入手方法については この記事 を、プロジェクトのコンパイル方法については この記事を参照してください。
(※)大学生、専門学校生の方は DreamSpark で、商用の Visual Studio を無償で入手することもできます。
ずいぶん御無沙汰してしまいたがお元気でしょうか?
tech・Days Japan 2009 後、HOSTING-PRO 2009(※) の準備その他があり、ばたばたしているうちに風邪をひいて寝込み、こんなに時間が経ってしまいました。
(※本職では Web 開発と、IIS、Windows Server についての啓発活動をしております。)
ちなみに tech・Days Japan 2009 フォローアップはここ(http://blogs.msdn.com/osamum/)でやってますので興味のある方はご覧ください。
さて、今回は先回の予告通り、作成中のメモ帳に検索機能を実装していきます。
多くの人が既に御存じのとおり、多くの情報を扱う状況では、検索機能は "あれば便利" という域を越え必須とも言える機能です。
もし、検索機能の無いアプリケーションをユーザーが使用したらどうなるか?、あらためて考えるまでもないでしょう。
答えは明らかです。"ものすごくイラつく" のです。
これでは素晴らしいエクスペリエンスを得られないばかりか、精神衛生上もよろしくありません。なにより必要な情報を探すのに時間がかかってしょうがありません。
"データを扱う"という自覚のあるアプリケーションであれば検索機能は搭載すべき機能です。これはコンピューターがユーザーに返す出力が、演算結果か検索の結果であるということからも明らかです。(※もっとも広義ではすべては"演算結果"なわけですが。)
今回実装する機能について
今回使用する文字列の検索ロジックは難しくありません。
実際のところ、この機能はは String クラスの持っている IndexOf メソッドに GUI を紐付ければ良いだけです。
機能実現の具体的な処理の流れとしてはこんなとこでしょう。
- 検索用ダイアログボックスを表示
↓ - テキストボックス内の文字列の IndexOf 関数に検索する文字列、開始位置を設定して検索する
↓ - テキストボックスのカーソルを検索対象文字の出現位置まで移動し、該当している文字列を選択状態とする
↓ - [次を検索] 機能を使用する場合に備え、検索の開始位置を "検索対象文字の出現位置 + 検索対象文字の文字数" に設定しておく
↓ - ②に戻る
この処理は [置換] 機能の実装にも使用することができます。
[置換] というと Replace 関数の方がふさわしいのでは? と考える人もあるでしょうが、Replace 関数は一度に全ての置換処理を行ってしまううえ、条件に該当したものがいくつあったか等も返さないため、インタラクティブ性を考えるとあまりお勧めできません。
ちなみに置換処理の実際の処理の流れはこんなとこでしょう。
- 置換用ダイアログボックスを表示
↓ - 検索対象となる文字列をユーザーの入力から取得
↓ - テキストボックス内の文字列の IndexOf 関数に検索する文字列、開始位置を設定して検索する
↓ - テキストボックスのカーソルを検索対象文字の出現位置まで移動し、該当している文字列を選択状態とする
↓ - [置換] ボタンがクリックされたら選択状態となっている文字列を置換後の文字列と入れ替える
↓ - [次を検索] 機能を使用する場合に備え、検索の開始位置を "検索対象文字の出現位置 + 検索対象文字の文字数" に設定しておく
↓ - ②に戻る
それでは実際に実装してみたいと思いますが、検索ダイアログの作成手順まで書くのは非常に大変なので、今回はあらかじめ作成しておいた検索用ダイアログをダウンロードして使用します。
前回の記事まで作業を行っていた方は以下のリンクから検索ダイアログボックス用のフォームをダウンロードしてください。
今回、初めて作業される方は、上記のファイルと以下のプロジェクトファイルをダウンロードして解凍してください。
ダウンロードした以降の作業は以下のとおりです。
プロジェクトへの検索ダイアログボックス用フォームの追加
- メモ帳のプロジェクト(※ダウンロードしたものを使用する場合は EditerWrk プロジェクト) を Visual Studio 2008 でオープン
- 画面右に表示されている [ソリューション エクスプローラ] 内でプロジェクト名を選択して右クリックし、表示されたコンテキストメニューから [追加] - [既存の項目] を選択
- ファイル選択ダイアログボックスが表示されるで、ダウンロードした以下の検索ダイアログボックス用のファイルを全て選択(※ドラッグすることで複数選択が可能)
- [追加] ボタンをクリック
[ソリューションエクスプローラ] にファイルが追加されていることを確認してください。 - [ソリューションエクスプローラ] で追加されたファイル findDialog.cs を右クリックし、表示されたコンテキストメニューより [コードの表示] を選択
- コードエディタで、ネームスペースがメモ帳用に作成したプロジェクトと同じであるか確認し、違っている場合は同じ名前に書き換える
以上の手順でプロジェクトへの既存フォームの追加は完了です。
ここからは作成しているメモ帳のメニューに検索ダイアログボックスを呼びだすコードを記述していきます。
なお、今回ダウンロードしていただいたフォームの中には、検索ダイアログボックスを制御するコード、検索、置換処理のコードを記述してありますので、メモ帳のイベントハンドラへの呼び出しの記述を行えばすぐに使用することができます。
また、このダイアログボックス用のフォームは、今回のプロジェクト中のテキストボックスのみならず、他のプロジェクトにあるテキストボックスにも使いまわすことができます。
ダイアログボックスの呼び出し
作成中のメモ帳から検索用ダイアログボックス (フォーム) を呼び出すには、以下の手順でコードを実装してください。
- [ソリューションエクスプローラ] で Form1.cs (メモ帳用のフォーム) を右クリックし、表示されたコンテキストメニューより [コードの表示] を選択
- クラスの直下に以下の変数を定義
findDialog findDlg = null;
これは 検索ダイアログボックスのインスタンスを保持するための変数です。クラス全体にスコープをもつように宣言します。 - [ソリューションエクスプローラ] で Form1.cs (メモ帳用のフォーム) を右クリックし、表示されたコンテキストメニューより [デザイナの表示]を選択
- Form1 がフォームデザイナ内に表示されるので、Form1 のメニュー [編集] - [検索] をダブルクリック
- イベントハンドラ menuFind_Click が定義されるので、以下のようにコードを記述
private void menuFind_Click(object sender, EventArgs e)
{
//二重起動を防止
if (findDlg == null || findDlg.IsDisposed)
{
//検索ダイアログボックス用フォームのインスタンスを生成
findDlg = new findDialog(dialogMode.Find, textBox1);
//検索ダイアログボックスを表示
findDlg.Show(this);
}
} - Form1 がフォームデザイナ内に表示されるので、Form1 のメニュー [編集] - [置換] をダブルクリック
- イベントハンドラ menuReplace_Click が定義されるので、以下のようにコード記述
private void menuReplace_Click(object sender, EventArgs e)
{
//二重起動を防止
if (findDlg == null || findDlg.IsDisposed)
{
//検索ダイアログボックス用フォームのインスタンスを生成
findDlg = new findDialog(dialogMode.Replace, textBox1);
findDlg.Show(this);
}
}※"検索" と "置換"のコードの違いは、インスタンスを生成するメソッドの第二引数のみですので、"同じようなコードを書きたくない" という方は以下のメソッドを [検索]、[置換] メニューの共通のイベントハンドラとして割り当ててもいいでしょう。
private void menuFindReplace(object sender, EventArgs e)
{
//二重起動を防止
if (findDlg == null || findDlg.IsDisposed)
{
//検索ダイアログボックス用フォームのインスタンスを生成
findDlg = new findDialog((((ToolStripMenuItem)sender).Name == "menuFind") ? dialogMode.Find : dialogMode.Replace, textBox1);
findDlg.Show(this);
}
}
以上で実装は完了です。[F5] キーを押下してプロジェクトを実行し、検索機能が正しく動作するか確認してみてください。
うまくいかない場合は以下から検索機能の実装を済んだサンプルをダウンロードしてお試しください。
以降、簡単にコードの説明を行います。
別フォームの表示について
menuFind_Click ハンドラ、menuReplace_Click ハンドラの内容を見てください。
フォームのインスタンスを格納する変数の内容が有効であるかどうか調べ、二重表示を防止しています。
//二重表示を防止 if (findDlg == null || findDlg.IsDisposed) |
インスタンスが有効でなければ(検索ダイアログボックスが表示されていなければ) フォームのインスタンスを生成し、変数に格納します。
今回のサンプルではコンストラクタの引数として検索対象とする TextBox と、"検索用のダイアログボックスを表示するのか"、"置換用のダイアログボックスを表示するのか"の列挙型(※)の引数を渡しています。
//検索ダイアログボックス用フォームのインスタンスを生成 findDlg = new findDialog(dialogMode.Replace, textBox1); |
インスタンスの生成後、TextBox クラスが持っている Show メソッドで検索ダイアログボックス用のフォームを表示します。
//検索ダイアログボックス用フォームを表示 |
検索用ダイアログボックスは、合致する文字列が存在した場合に、その文字列を選択状態にする必要があるため Show メソッドを使用してモーダレスな表示としていますが、一般的なダイアログボックスのように、作業中にその他のフォームに対して操作を行えないようにするには ShowDialog メソッドを使用します。
※列挙型を使用すると、指定される引数を限定することができます。今回のサンプルでは、ダイアログボックスの種別を指定するためのフラグは列挙型で、findDialog.cs の内で定義しています。
真(True)/偽(False)では賄えない二つ以上の状態を指定するのに使用すると便利です。
//[検索]用、[置換]用の列挙型(フラグ用) public enum dialogMode { Find, Replace } |
検索ダイアログ用 フォームについて
サンプルの検索ダイアログ フォームは、置換用と検索用 UI を兼ねています。
フォームの上には置換用 UI が配置されており、その上に検索用の UI 配置した Panel コントロールを重ねてあり、その Panel コントロールの表示を切り替えることによりフォームの用途を分けています。
Panel コントロールのように他のコントロールを包含できる機能を "コンテナ属性" と呼びます。
コンテナ属性をもったコントロールを使用すると、複数のコントロールを機能単位に整理して使用することができます。
その他、フォームに設定されている属性は以下のとおりです。これらはプロパティウィンドウで設定することができます。
属性 | 値 | 説明 |
AcceptBotton | findButton | ユーザーが [Enter] キーを押下した際に割り当てられるボタン |
CancelBotton | cancelBotton | ユーザーが [Esc] キーを押下した際に割り当てられるボタン |
FormBorderStyle | FixedToolWindow | フォームの外観と動作 |
StartPosition | CenterParent | 初めて表示されたときのフォームのポジション |
検索のロジックについて
文字列の検索は String クラスが持っている IndexOf メソッドを使用しています。
検査用フォームに書かれているコードを簡略化すると以下のようになります。
//検索の開始位置 private void ExecFind() findPoint = "検索対象の文書".IndexOf("検索する文字列",findStartIndex); //見つかった文字を選択状態に //TextBox が選択された文字列を表示するようキャレットを移動 //[次を検索] ボタンをクリックされた際の検索開始位置を設定 //テキストボックスにフォーカスをあてる |
親フォームの操作について
フォーム内のコントロールのスコープはフォーム内で閉じており、異なるフォームから参照式を書いて直接制御することはできません。
このサンプルでは、操作する親フォーム内の TextBox のインスタンスを受けるように TextBox 型のコンストラクタの引数とプロパティを設けています。
//処理対象となる TextBox のインスタンスを保持 //[検索]用のダイアログボックスを表示するか、[置換]用のダイアログボックスを表示するかのフラグ //コンストラクタ //処理対象となる TextBox のインスタンス設定するためのプロパティ |
次回はアプリケーションの状態の保存について書きたいと思います。 (ほんというと、もう web アプリの開発ネタに行きたいのですが。。)
ではまた。
- 9件のコメント
コメントありがとうございます。
>最初のダイアログのダウンロードの中身だと対応していない部分があります。
すみません、古い方をアップロードしてしまったみたいです。
>次回記事でウィンドウサイズの保存を自前のXMLのファイルに書き出せるような
はい。実は .NET には設定値の各型を自動的にシリアライズして XML 形式で保存するという機能があります。
次回はこれについて書きますね。
ちなみに明日、ポストの予定です。
のリンクをクリックしたところ
このアイテムは存在しないか,使用できなくなっています
と表示されるのですがどうすればいいですか?
[検索ダイアログボックス用フォーム]
のリンクをクリックしたところ、存在しなくなっているようです。
再度アップして頂けますでしょうか?
せっかくこのようなサイトが存在するので、ここでギブアップするのは勿体ありません。
もう一度アップすることを希望します
再配布していただけないでしょうか?
シンプルなメモ帳 Wiki - OSDN
https://ja.osdn.net/users/takkii/pf/UKEditor/wiki/FrontPage
こちらからダウンロードしたら、手に入るよ。
https://github.com/1018/memo/tree/master/EditerWrk/EditerWrk
- 帝国の野望ブログ 最新エントリ
- 新着記事
- 特集
- ブログ
- 企画特集
-
明日からではもう遅い?!
-
Kubernetesの認定制度が開始
-
利便性とセキュリティの両立
-
セキュリティの今を知る
-
モバイルデバイスもターゲットに!
-
ゼロトラストに不可欠なID管理
-
連載!プロが語るストレージ戦略
-
話題のセキュリティ事故体験ゲーム
-
いままさに社会にとっての転換点
-
企業DXのキモはクラウドにあり
-
ビッグデータ最前線!
-
さあ、クラウドで解決しよう。
-
連載!プロが語るストレージ戦略
-
連載!プロが語るストレージ戦略
-
中小企業でのひとり情シスIT運用術
-
次の一手はこれだ!
-
講演の見どころを紹介
-
特集:IT最適化への道
-
デジタルを当たり前と言えるか?
-
DXができない企業が滅びる理由
-
常識を疑え!
-
現場主導の業務変革のポイント
-
漫画で解説!運用管理のコツ
-
幸せ?不幸?ひとり情シス座談会
-
内部不正や不注意をどう防ぐ?
フルセット版の中身に入っているのを使わないと検索と置換の機能が使えません。
LINQのライブラリを外したり(VS2005用)、必要なプログラムのnamespaceに変えて
あげれば別のアプリケーションでも使い回しが出来るようですね。
次回記事でウィンドウサイズの保存を自前のXMLのファイルに書き出せるような
ことをやってもらえるとプログラムの開発に役立ちそうです。