Windowsアプリケーション ソフトウェアを作る場合、作成するウィンドウの大まかなイメージを描く必要があります。最近、Raman散乱用の分光器の制御用に作成したウィンドウを以下に示します。クライアント領域には、水銀ランプのスペクトルが描かれています(横軸は波長:nmで、縦軸は:強度 )。
ソフトウェアの中身は無視して、見かけだけ同じものを作ってみましょう。ウィンドウ事始めで説明した方法で、プロジェクト名をspec25として、新規にプロジェクトを作ります。これをカスタマイズして行きます。
ウィンドウの大きさ
CMainFrame::CMainFrame() { Create(((Cspec25App*)AfxGetApp())->mainclass, "spec25 Program", WS_OVERLAPPEDWINDOW, rectDefault,NULL,NULL); }
という部分を見つけてください。Create関数はウィンドウを作成(create)する関数ですが、その引数でrectDefaultがウィンドウの大きさの初期値を指定しているところです。rectDefaultは、デフォルト値(default:初期設定 いろいろな変数に対して、我々が意識して設定しないときには、Visual C++が設定している値を初期値とします。これをデフォルト値と言います)を表しています。ここを、適当な値に変えます。以下のように変えてください。詳しくは説明しませんが、これで縦700、横1000の大きさのウィンドウになります。
CMainFrame::CMainFrame() { CRect rectWin=rectDefault; rectWin.right=rectWin.left+1000; rectWin.bottom=rectWin.top+700; Create(((Cspec25App*)AfxGetApp())->mainclass, "spec25 Program", WS_OVERLAPPEDWINDOW, rectWin,NULL,NULL); }
ここで、プログラムを実行して画面の大きさを確認してください。縦横の大きさを変えてみるのも良いと思います。また、興味があれば、"spec25 Program"のコーテーションで囲まれた文字を変えた時、どこが変わるのかを確かめるのも良いと思います。
クライアント領域の色
Raman散乱は通常暗い部屋の中で行います。そのとき、クライアント領域の色の明度が高いと目によくありません。そこで、クライアント領域を、暗い色に変えます。 spec25.cppの中に関数Cspec25App::InitInstance()を見つけ、そしてその中に
HBRUSH hbrush = (HBRUSH)::GetStockObject(WHITE_BRUSH);
という行を見つけます。これを以下のように変えます。
HBRUSH hbrush = CreateSolidBrush(RGB(0,0,90));
これで、クライアント領域の色は、赤(R)、緑(G)、青(B)の3原色の値(それぞれは0から255までの値をとれます)で指定します。今の場合、青色で値が小さい90ですから、暗い青になります。RGBの値を適当に設定すれば、好きな色にすることができます。(注)
ここで、プログラムを実行してクライアント領域の色を確認してください。
注:Windowsにはペイントというソフトウェアがありますので、それを起動して、メニューの色->色の編集を選択すると色の編集のためのダイアログ ボックスが現れます。そこで、色の作成ボタンを押すと、ダイアログ ボックスが右手に広がり、その右端に赤、緑、青を指定するところがありますので、そこに適当な値を入れると、その値に対応する色が現れます。
メニューの作成
Visual C++のメニューで、挿入->リソースを選択すると、以下の様なリソースの挿入というダイアログ ボックスが現れます。そこで、マウスでMenuを選択して、新規作成ボタンを押すと、
次の図の様に、ワークスペース ウィンドウの中にIDR_MENU1という名前が、また、このウィンドウの右隣にメニュー作成ウィンドウが現れます。
次に、メニュー作成ウィンドウに2重に点線で囲まれた部分を、マウスで右クリックすると、
の様な、メニューアイテム プロパティというダイアログ ボックスが現れます。そこで、次のように、ポップアップについているチェックをクリックで外し、ID欄にID_FILE(半角で入力)、キャプション欄にファイルと書き込んでください。
すると、メニュー作成ウィンドウは以下の様になります。
これで、ファイルという項目を持つメニューができました。
メニュー項目を増やします。ファイルという項目の右に2重に点線で囲まれた部分を、マウスで右クリックします。あとは上記と同じ方法で、 ID欄とキャプション欄に、ID_ORIGIN、基点設定と書き込みます。さらに、ID欄とキャプション欄に、ID_START、測定開始とID_STOP、測定中止とするメニュー項目を2つ増やします。次のようになります。
メニューの表示
まず、メニューの名前を変えます。上図で、ワークスペース・ウィンドウの中のIDR_MENU1という名前を右クリックすると、下図、左のようなウィンドウが現れるので、一番下にあるプロパティーを左クリックで選択します。すると、下図、右のダイアログボックスが現れるので、ID欄をIDR_MENU1から"MENU"(適当な名前で結構ですが、半角のコーテーションで囲むこと)へに変えます。これで、メニューの名前が"MENU"となります。
次に、ワークスペース・ウィンドウの下方にある、File Viewタブをクリックし、Source Filesにあるspec25.cppなる文字をダブルクリックして、spec25.cppの中身を表示させます。関数CMainFrame::CMainFrame()の中のCreate関数の引数を再び変えます。Create関数の引数の一番最後にあるNULLのところを、次のように"MENU"としてください。これで、先ほど作った"MENU"という名前のメニューを持つウィンドウができあがります。
Create(((Cspec25App*)AfxGetApp())->mainclass, "spec25 Program", WS_OVERLAPPEDWINDOW, rectWin,NULL,"MENU");
ここで、プログラムを実行して、メニュー付きのウィンドウとなっていることを確認してください。
メニュー項目に対応するハンドラー関数
作ってきたプログラムを実行してみると分かると思いますが、メニューのファイル等の項目を選択しても何もおこりません。クリックしたということは、イベントを発生させたわけですが、このイベントに対するハンドラー関数を作っていないからです。ここでは、測定開始というメニュー項目に対するハンドラー関数だけを追加します。ハンドラー関数を追加する方法は、すでにメッセージのところで説明しています。Visual C++のメニューから表示->ClassWizardを選択すると、次のようなMFC ClassWizardというダイアログボックスが現れます。
このダイアログボックスで、オブジェクトIDでID_STARTを、またメッセージでCOMMANDをマウスで選択し、関数の追加ボタンを押します。すると
のようなダイアログ ボックスが現れ、ここでハンドラー関数の名前を決めます。デフォルトでOnStart()という名前になっています。ここでは、このままの名前としますので、OKボタンを押します。すると、spec25.cppの一番下に、関数OnStart()が
void CMainFrame::OnStart() { // TODO: この位置にコマンド ハンドラ用のコードを追加してください }
のように追加されています。
さて、ここで、この関数がきちんと働いていることを確認します。まず、//TODOの位置にマウス カーソルを持ってきてクリックすることにより、カーソル(縦棒で、文字を入力する位置を示す点滅する縦棒)を、ここにもって来ます。Visual C++メニューで、ビルド->デバックの開始->カーソルの前まで実行を、マウスで選択して行くと、ダイアログ ボックスが現れ、ビルドを行いますかと聞かれますので、OKボタンを押します。これで、プログラムが実行されます。メニューのファイル項目をクリックすると、先ほど設定したカーソル位置でプログラムが止まれば、正常です。それを確認したら、デバックを終えます。具体的には、Visual C++メニューのデバック->デバックの中止を選択します。なお、デバックは虫取り(debug)を意味し、プログラムに潜む間違い(害虫に例えられます)を取り除くことを意味します。
実際のプログラミングでは、この、//TODOの位置に、Raman散乱スペクトルのデータを収集する作業をプログラミングするのですが、ここでは、なにもしません。
ステータス バーの追加
通常ウィンドウの最下位に表示するものが、下図のようなステータス バーです。 プログラムのなかで示したい情報を表示したりします。例えば、測定の何%が終了しているのかを実時間的にステータス バーに表示します。ウィンドウにステータス バーをつけるのには、少々手間が掛かります。次のようにします。
1. spec25.cppの中に、IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)という所を見つけます。その上に
static UINT indicators[] = { ID_SEPARATOR, ID_SEPARATOR // ステータス ライン インジケータ }; IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
の様に、indicators変数を追加します。これで、ステータスバーが2区画(ペイン:pane)で構成されることになります。さらに区画を増やす場合は、ID_SEPARATORをカンマで区切って追加します。
2. 関数CMainFrame::CMainFrame()に、関数status.Create等を以下のようにつけ加えます。
CMainFrame::CMainFrame() { CRect rectWin=rectDefault; rectWin.right=rectWin.left+1000; rectWin.bottom=rectWin.top+700; Create(((Cspec25App*)AfxGetApp())->mainclass, "spec25", WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, rectWin,NULL,"MENU"); status.Create(this,WS_CHILD|WS_VISIBLE|CBRS_BOTTOM,IDR_STATUS); status.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)); status.SetPaneInfo(0,0,0,200);status.SetPaneInfo(1,0,0,900); status.SetPaneText(0,"測定状況"); }
ここで、SetPaneInfo(0,0,0,200)で第0区画の幅を200とし、SetPaneInfo(1,0,0,900)で第1区画に幅を900としています。またSetPaneText(0,"測定状況")で、第0区画に初期設定として"測定状況"なる文字列を表示しています。第1区画にも何か表示したければ、status.SetPaneText(1,"何か");を追加します。
3. ワークスペース ウィンドウで、Heder File(フォルダの様になっています)をダブルクリックして、現れるspec25.hをダブルクリックします。すると、spec25.hの内容が表示されます。その中で、以下のように、クラスの定義であるclass CMainFrame : public CFrameWndの一番下に、privated:とCStatusBar status;の2行を追加します。これで、CStatusBar(ステータスバーを扱う専門家と思ってください)のstatusさんを登場(生成)させることができます。前項でのstatus.Createなどは、このstatusさんにステータス ウィンドウ(ステータスもウィンドウの1種です)の作成などを、お願いしていることになります。
DECLARE_MESSAGE_MAP() private: CStatusBar status; };
なお、クラス内だけで使う変数はクラス変数(今の場合はクラスの実体です)と言いますが、これは原則としてprivate:とします。記憶願います。クラス外から変数を変えることも(public:)、またこのクラスから派生させるクラスから変数を変えることも(protect:)できますが、できるということは、意図しないで変えてしまうという危険性を伴います。できるだけ、変えるということに制限をもうけた方が安全なので、private:にします。
4. 最後に、ワークスペース ウィンドウでResource.hをダブルクリックして、その内容を表示させます。そこで、IDR_STATUS [status.Create(this,WS_CHILD|WS_VISIBLE|CBRS_BOTTOM,IDR_STATUS);の最後の引数に対応します。] を定義(define)します。下の例ではIDR_STATUSを130なる数値とします。#define _APS_NEXT_RESOURCE_VALUEに書かれている数値です。
#define IDR_MAINFRAME 128 #define IDR_STATUS 130 以下略
4. 130という数値は使ったので、#define _APS_NEXT_RESOURCE_VALUEの値を1つ増やします。
#define _APS_NEXT_RESOURCE_VALUE 131
ここで、プログラムを実行して、ステータス付きのウィンドウとなっていることを確認してください。
注:プログラムを実行してみると分かるのですが、"測定状況"と書かれたところがへこんでいるように見え、少々見栄えがよくありません。これを解消するには、ClassWizerdダイアログを表示させ(メニューで表示->ClassWizerdを選択)、そのメッセージ欄で、PreCreateWindowをマウスで選択して、関数の追加ボタンを押すと、spec25.cppの最後に関数PreCreateWindowが追加されます。その関数の内容を
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { // 3D枠を書かない様にする if(!CFrameWnd::PreCreateWindow(cs)) return(TRUE); cs.dwExStyle &= ~WS_EX_CLIENTEDGE; return(TRUE); }のように書き換えます。
アイコンの変更