親ウィンドウの中に子ウィンドウを作成してみましょう。
親ウィンドウと同じサイズの子ウィンドウを2つ作成して、表示、非表示を切り替える事で、アプリケーション内での画面遷移を実現してみましょう。
子ウィンドウの作成は、親ウィンドウと同じくCreateWindow関数を使用します。
HWND CreateWindow(
LPCTSTR lpClassName, // 登録されているクラス名
LPCTSTR lpWindowName, // ウィンドウ名
DWORD dwStyle, // ウィンドウスタイル
int x, // ウィンドウの横方向の位置
int y, // ウィンドウの縦方向の位置
int nWidth, // ウィンドウの幅
int nHeight, // ウィンドウの高さ
HWND hWndParent, // 親ウィンドウまたはオーナーウィンドウのハンドル
HMENU hMenu, // メニューハンドルまたは子ウィンドウ ID
HINSTANCE hInstance, // アプリケーションインスタンスのハンドル
LPVOID lpParam // ウィンドウ作成データ
);
子ウィンドウを作成するには、親ウィンドウのWM_CREATE時に、CreateWindow関数でウィンドウを生成します。
第3引数のdwStyleには、WS_CHILDスタイルを与えます。
このとき第8引数のhWndParentに親ウィンドウのハンドルを指定します。今までは親ウィンドウの生成でしたので、NULLにしていましたね。
GetWindowRect関数で親ウィンドウのサイズを取得して子ウィンドウにも同じサイズを指定します。
BOOL GetWindowRect(
HWND hWnd, // ウィンドウのハンドル
LPRECT lpRect // ウィンドウの座標値
);
GetWindowRect関数はウィンドウのハンドルで指定したウィンドウのサイズを、RECT構造体に格納します。この関数より取得したサイズで、子ウィンドウを作成すれば、親ウィンドウと同じサイズの子ウィンドウができます。
親ウィンドウのウィンドウプロシージャWndProc内では、ウィンドウの初期化時にWM_CREATEメッセージが送られてきます。ここで子ウィンドウA、子ウィンドウBを生成しています。
親ウィンドウの「OPEN_A」,「OPEN_B」ボタンを押すとそれぞれ子ウィンドウA、子ウィンドウBを表示します。
子ウィンドウに配置した「CLOSE」ボタンを押すと、親ウィンドウへ戻ります。これは子ウィンドウを非表示にすることで実現しています。
親ウィンドウプロシージャ内の記述としては
「OPEN_A」が押されたら子ウィンドウAを表示状態にする。
「OPEN_B」が押されたら子ウィンドウBを表示状態にする。
子ウィンドウプロシージャ内の記述としては
「CLOSE」が押されたら、自ウィンドウを非表示にする。(親ウィンドウが表示される)。
とすれば実現できますが、今回は、画面遷移の処理をすべて親ウィンドウに集めてみましょう。
親ウィンドウプロシージャ内の記述としては
「OPEN_A」が押されたら子ウィンドウAを表示状態にする。
「OPEN_B」が押されたら子ウィンドウBを表示状態にする。
「CLOSE」が押されたら、子ウィンドウAが表示状態なら、子ウィンドウAを非表示にする。
子ウィンドウBが表示状態なら、子ウィンドウBを非表示にする。
子ウィンドウプロシージャ内の記述としては
「CLOSE」ボタンが押されたら、親ウィンドウに対してメッセージを送る。
とすることで、画面遷移の処理を親ウィンドウに集めることができそうです。
// ChildWindow.cpp
//
// リージョンの結合
#include <windows.h>
#define BUTTON_ID 1000
#define CHILD_ID_A 5000
#define CHILD_ID_B 5001
#define BUTTON_ID_OPEN_A 6000
#define BUTTON_ID_OPEN_B 6001
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWindowProc(HWND , UINT , WPARAM , LPARAM );
ATOM InitApp(HINSTANCE);
HWND InitInstance(HINSTANCE, int);
HINSTANCE hInst;
TCHAR szClassName[] = _T("ParentWindow"); // ウィンドウクラス。UNICODEとしての文字列定数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd)
{
MSG msg;
BOOL bRet;
HWND hWnd;
hInst = hInstance;
if (!InitApp(hInstance))
return FALSE;
if (!(hWnd = InitInstance(hInstance,nShowCmd)))
return FALSE;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1){
break;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
// ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASS wc;
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WndProc; // プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL; // 未サポート
wc.hCursor = NULL; // 未サポート
wc.hbrBackground= (HBRUSH) COLOR_WINDOW;
wc.lpszMenuName = NULL; // 未サポート
wc.lpszClassName=(LPCTSTR) szClassName;
return (RegisterClass(&wc));
}
// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd)
{
HWND hWnd;
hWnd = CreateWindow(
szClassName,_T("ChildWindowサンプル"),
WS_CLIPCHILDREN, // ウィンドウの種類
CW_USEDEFAULT, // x座標
CW_USEDEFAULT, // y座標
CW_USEDEFAULT, // 幅
CW_USEDEFAULT, // 高さ
NULL, // 親ウィンドウのハンドル。親を作るのでNULL
NULL, // メニューハンドルまたは子ウィンドウID
hInst, // インスタンスハンドル
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
return hWnd;
}
// ウィンドウクラスの登録
void CreateWindowClass(HINSTANCE hInst, LPCTSTR szClassName, WNDCLASSW &wc)
{
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = ChildWindowProc ; // プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground= reinterpret_cast<HBRUSH>(GetStockObject(GRAY_BRUSH)); //グレーにする
wc.lpszMenuName = NULL; // 未サポート
wc.lpszClassName=(LPCWSTR) szClassName;
}
// 子ウィンドウの生成
HWND CreateChildWindow(HINSTANCE hInst, int nShowCmd,LPTSTR ClassName,HMENU hMenuChildId,HWND hParent)
{
HWND hWnd;
// 親ウィンドウのサイズを取得
RECT rect;
GetWindowRect(hParent, (LPRECT)&rect);
hWnd = CreateWindow(
ClassName,
NULL,
WS_CHILD,
0, //親ウィンドウと同じサイズ
0,
rect.right - rect.left,
rect.bottom - rect.top,
hParent, //親ウィンドウのハンドル
(HMENU)hMenuChildId, // 子ウィンドウを判別するためのID
hInst, //インスタンスハンドル
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
return hWnd;
}
// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR buf[256];
size_t size; // 文字列のサイズを格納する
WNDCLASSW wc_A;
WNDCLASSW wc_B;
static HWND hChildWnd_A;
static HWND hChildWnd_B;
static HWND hButton;
switch (msg){
case WM_CREATE:
// 子ウィンドウAの生成
CreateWindowClass(hInst,_T("ChildWindow_A"),wc_A);
RegisterClassW(&wc_A);
hChildWnd_A = CreateChildWindow(hInst,SW_HIDE,_T("ChildWindow_A"),(HMENU)CHILD_ID_A,hWnd);
// 子ウィンドウBの生成
CreateWindowClass(hInst,_T("ChildWindow_B"),wc_B);
RegisterClassW(&wc_B);
hChildWnd_B = CreateChildWindow(hInst,SW_HIDE,_T("ChildWindow_B"),(HMENU)CHILD_ID_B,hWnd);
// プッシュボタンを作成する
hButton = CreateWindow(
_T("BUTTON"), // ウィンドウクラス名
_T("OPEN A"), // キャプション
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // スタイル指定
50, 50, // 座標
60, 40, // サイズ
hWnd, // 親ウィンドウのハンドル
(HMENU)BUTTON_ID_OPEN_A, // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
// プッシュボタンを作成する
hButton = CreateWindow(
_T("BUTTON"), // ウィンドウクラス名
_T("OPEN B"), // キャプション
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // スタイル指定
50, 100, // 座標
60, 40, // サイズ
hWnd, // 親ウィンドウのハンドル
(HMENU)BUTTON_ID_OPEN_B, // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
break;
case WM_COMMAND:
GetClassName(hWnd, buf, 255);
NKDbgPrintfW(_T("%s\n"),buf);
switch(LOWORD(wp) ){
case BUTTON_ID_OPEN_A:
// 親ウィンドウの「OPEN_A」ボタン押下時の処理
// 子ウィンドウAを表示する
ShowWindow(hChildWnd_A,SW_SHOW);
UpdateWindow(hChildWnd_A);
return (DefWindowProc(hWnd, msg, wp, lp));
break;
case BUTTON_ID_OPEN_B:
// 親ウィンドウの「OPEN_B」ボタン押下時の処理
// 子ウィンドウBを表示する
ShowWindow(hChildWnd_B,SW_SHOW);
UpdateWindow(hChildWnd_B);
return (DefWindowProc(hWnd, msg, wp, lp));
break;
case BUTTON_ID:
// 子ウィンドウの「CLOSE」ボタン押下字の処理
if( IsWindowVisible(hChildWnd_A) ){
ShowWindow(hChildWnd_A,SW_HIDE);
}else{
ShowWindow(hChildWnd_B,SW_HIDE);
}
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps); // 描画処理を開始します。
SetBkMode(hdc, TRANSPARENT); // 背景を透過モードにします
GetClassName(hWnd, buf, 255); // クラス名を取得
StringCchLength(buf,255,&size); // 文字列長の取得
ExtTextOut(
hdc, // デバイスコンテキストのハンドル
0, // 開始位置(基準点)の x 座標
20, // 開始位置(基準点)の y 座標
NULL, // 長方形領域の使い方のオプション
NULL, // 長方形領域の入った構造体へのポインタ
buf, // 文字列
size, // 文字数
NULL // 文字間隔の入った配列
);
EndPaint(hWnd,&ps); // 描画処理を終了します。
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
LRESULT CALLBACK ChildWindowProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HWND hButton;
HDC hdc;
COLORREF bkColor;
TCHAR buf[256];
size_t size; // 文字列のサイズを格納する
switch (msg){
case WM_CREATE:
// プッシュボタンを作成する
hButton = CreateWindow(
_T("BUTTON"), // ウィンドウクラス名
_T("CLOSE"), // キャプション
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // スタイル指定
100, 200, // 座標
60, 40, // サイズ
hWnd, // 親ウィンドウのハンドル
(HMENU)BUTTON_ID, // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps); // 描画処理を開始します。
SetBkMode(hdc, TRANSPARENT); // 背景を透過モードにします
GetClassName(hWnd, buf, 255); // クラス名を取得
StringCchLength(buf,255,&size); // 文字列長の取得
ExtTextOut(
hdc, // デバイスコンテキストのハンドル
0, // 開始位置(基準点)の x 座標
20, // 開始位置(基準点)の y 座標
NULL, // 長方形領域の使い方のオプション
NULL, // 長方形領域の入った構造体へのポインタ
buf, // 文字列
size, // 文字数
NULL // 文字間隔の入った配列
);
EndPaint(hWnd,&ps);
break;
case WM_COMMAND:
GetClassName(hWnd, buf, 255);
NKDbgPrintfW(_T("%s\n"),buf);
switch(LOWORD(wp) ){
case BUTTON_ID:
// 親ウィンドウへメッセージ伝播。処理は親に任せる。
SendMessage(GetParent(hWnd),msg,wp,lp);
// 自ウィンドウを非表示にする
//ShowWindow(hWnd,SW_HIDE);
//UpdateWindow(hWnd);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
親ウィンドウにメッセージを送るには、SendMessage関数を使います。
子ウィンドウの「CLOSE」ボタンが押下されると、
子ウィンドウのウィンドウプロシージャChildWindowProcにWM_COMMANDメッセージが通知されます。ここでは
// 親ウィンドウへメッセージ伝播
SendMessage(GetParent(hWnd),msg,wp,lp);
としているだけです。
LRESULT SendMessage(
HWND hWnd, // 送信先ウィンドウのハンドル
UINT Msg, // メッセージ
WPARAM wParam, // メッセージの最初のパラメータ
LPARAM lParam // メッセージの 2 番目のパラメータ
);
hWnd 送信先ウィンドウハンドルには、親ウィンドウを指定します。Msg,wParam,lParamには、子ウィンドウのウィンドウプロシージャが受け取った値をそのままセットします。
これにより、親ウィンドウで一括してボタン押下時の処理を任せることができます。
親ウィンドウのウィンドウプロシージャでは、子ウィンドウAが表示されていれば、子ウィンドウAを非表示、子ウィンドウBが表示されていれば、子ウィンドウBを非表示にします。
これにより、子ウィンドウの管理を親ウィンドウに任せることができるようになりました。
テーマ:Windows Mobile - ジャンル:コンピュータ
通常のパソコンで行うような、たくさんのダイアログを切り替えて作業する、といった事は小さな携帯画面では操作もしずらく、あまり現実的ではありません。
WindowsMobileアプリケーションでは、ウインドウであれダイアログであれ、全画面表示にするのが一般的です。その方が使い勝手もよく、他のソフトウェアともインターフェースを統一できるのでお勧めです。
Windows Mobile6 Standardでは、主にナビゲーションバーにOKボタンを表示したフルスクリーンダイアログボックスが使用されます。完了ボタンは視覚的にフルスクリーンのダイアログボックスで隠されてOKボタンに置き換わるため、「ダイアログのOKボタンである」ということが理解しやすいからです。ダイアログのボタンを完了ボタン([×]ボタン)にしていると、親画面の完了ボタン([×]ボタン)なのか、ダイアログの完了ボタンなのか区別がつかず、ユーザの誤動作を招くことになります。
ではダイアログも全画面表示にしてみましょう。
前回のダイアログ「SampleDialog002」を全画面ダイアログになるように変更します。
全画面ダイアログを表示するには、WM_INITDIALOG:でSHInitDialog()を使用します。
SH~()関数と頭にSHのつく関数は、WindowsMobile特有の関数で主にUIの部分に関連する関数です。
このSHInitDialog()関数はSHINITDLGINFO構造体にパラーメータを指定することで、ダイアログボックスのサイズをSIPに合わせて変更します。
SHInitDialog()関数を使用するにはaygshell.hをインクルードします。
■SHInitDialog()
ダイアログの状態を指定するSHINITDLGINFO構造体に値をセットしてSHInitDialog()関数に渡します。
SHINITDLGINFO構造体
typedef struct tagSHINITDLGINFO
{
DWORD dwMask;
HWND hDlg;
DWORD dwFlags;
} SHINITDLGINFO, *PSHINITDLGINFO;
dwMask
SHINITDLGINFO構造でどのメンバーが有効であるかを示すビットフィールドで、SHIDIM_FLAGSを指定します。
hDlg
ダイアログへのハンドルです。必須項目です。
dwFlags
ダイアログの動作を決定するフラグです。SHIDIM_FLAGSフラグが設定されてなければ無視されます。
SHIDIF_DONEBUTTON
ナビゲーションバーにOKボタンを表示します。
SHIDIF_EMPTYMENU
下部に空のメニューを作成します。
SHIDIF_FULLSCREENNOMENUBAR
ダイアログボックスを入力パネルの位置に関係なく、フルスクリーン表示に設定します。
SHIDIF_SIPDOWN
ダイアログ初期化時に入力パネルが開いていたら閉じます。
SHIDIF_SIZEDLG
ダイアログボックスはSIPの邪魔にならないサイズで最大化されます。
SHIDIF_SIZEDLGFULLSCREEN
ダイアログボックスを入力パネルの位置に関係なく、フルスクリーン表示に設定します。
SHIDIF_CANCELBUTTON
[×]ボタン表示しダイアログを閉じると同時にキャンセル(IDCANCEL)を発行します。
SHIDIF_WANTSCROLLBAR
ダイアログが画面に収まらない場合にスクロールバーを表示します。
ソースコードは次のとおりです。
// SampleDialog003.cpp
//
// ダイアログを全画面表示にする
#include <windows.h>
#include <aygshell.h>
#include "resource1.h"
#define ID_BUTTON1 (0) // ボタンのID
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
HWND InitInstance(HINSTANCE, int);
HWND hDlg; // モードレスダイアログボックスのハンドル
HINSTANCE hInst; // アプリケーションインスタンスハンドル
TCHAR szClassName[] = _T("SampleDialog003");
// ウィンドウクラス。UNICODEとしての文字列定数
TCHAR szStr[4]; // ダイアログとのデータ受け渡し用。4文字確保(うち1つはNULLポインタ用)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd)
{
MSG msg;
BOOL bRet;
HWND hWnd;
hInst = hInstance; // アプリケーションインスタンスハンドルをグローバル変数へ格納
if (!InitApp(hInstance))
return FALSE;
if (!(hWnd = InitInstance(hInstance,nShowCmd)))
return FALSE;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1){
break;
} else {
//ダイアログからのメッセージを処理する。
if(!IsDialogMessage(hDlg,&msg)){
// ダイアログで処理されなかったメッセージは
// ウィンドウプロシージャで処理する。
TranslateMessage(&msg); // 仮想キーメッセージを文字メッセージに変換
DispatchMessage(&msg); // メッセージをウィンドウプロシージャに送る
}
}
}
return (int)msg.wParam;
}
// ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASS wc;
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WndProc; // プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL; // 未サポート
wc.hCursor = NULL; // 未サポート
wc.hbrBackground= (HBRUSH) COLOR_WINDOW;
wc.lpszMenuName = NULL; // 未サポート
wc.lpszClassName=(LPCTSTR) szClassName;
return (RegisterClass(&wc));
}
// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd)
{
HWND hWnd;
hWnd = CreateWindow(szClassName,_T("モードレス"),
WS_CLIPCHILDREN, // ウィンドウの種類
CW_USEDEFAULT, // x座標
CW_USEDEFAULT, // y座標
CW_USEDEFAULT, // 幅
CW_USEDEFAULT, // 高さ
NULL, // 親ウィンドウのハンドル。親を作るのでNULL
NULL, // メニューハンドルまたは子ウィンドウID
hInst, // インスタンスハンドル
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
return hWnd;
}
// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
size_t size; // 文字列のサイズを格納する
HWND hButton;
HWND hDlg;
switch (msg){
case WM_CREATE: // 初期化処理開始
// モードレスダイアログを開くボタン
hButton = CreateWindow(
_T("BUTTON"), // ウィンドウクラス名
_T("DIALOG"), // キャプション
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // スタイル指定
50, 50, // 座標
60, 40, // サイズ
hWnd, // 親ウィンドウのハンドル
HMENU(ID_BUTTON1), // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps); // 描画処理を開始
StringCchLength(szStr,STRSAFE_MAX_CCH,&size); // 安全な文字列長取得
ExtTextOut(
hdc, // デバイスコンテキストのハンドル
0, // 開始位置(基準点)の x 座標
20, // 開始位置(基準点)の y 座標
NULL, // 長方形領域の使い方のオプション
NULL, // 長方形領域の入った構造体へのポインタ
szStr, // 文字列
size, // 文字数
NULL // 文字間隔の入った配列
);
EndPaint(hWnd,&ps);
break;
case WM_COMMAND:
switch (LOWORD(wp)){
case ID_BUTTON1:
// モードレスダイアログウィンドウを開く
hDlg = CreateDialog(
hInst, // アプリケーションのインスタンスのハンドル
MAKEINTRESOURCE(IDD_DIALOG1),
// ダイアログボックステンプレートを指定
hWnd, // 親ウィンドウのハンドル
DlgProc // ダイアログボックスプロシージャへのポインタ
);
ShowWindow(hDlg,SW_SHOW);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
// ダイアログプロシージャ
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
static HWND hParent; // 親ウィンドウのハンドル
int copyCount;
switch(msg){
case WM_INITDIALOG: // ダイアログの初期化処理
{
SHINITDLGINFO shidi;
hParent = GetParent(hDlg); // 親ウィンドウハンドル
// Create a Done button and size it.
shidi.dwMask = SHIDIM_FLAGS; // SHINITDLGINFO構造でどのメンバーが有効であるかを示すビットフィールドです。
// SHIDIM_FLAGSを指定します。
shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN // ダイアログボックスを入力パネルの位置に関係なく、フルスクリーン表示に設定します。
| SHIDIF_EMPTYMENU // 下部に空のメニューを作成します
| SHIDIF_WANTSCROLLBAR // ダイアログが画面に収まらない場合にスクロールバーを表示します
| SHIDIF_DONEBUTTON // ナビゲーションバーにOKボタンを表示します。
;
shidi.hDlg = hDlg; // ダイアログのハンドル。必須です。
SHInitDialog(&shidi);
return TRUE;
}
case WM_COMMAND: // ダイアログのボタンが押されたときの処理
switch (LOWORD(wp)){
case IDOK:
// エディットコントロールの値を取得
copyCount = GetDlgItemText(hDlg,IDC_EDIT1,szStr,4);
// デバッグプリント
NKDbgPrintfW(_T("szStr :バイト数: %d 文字数:%d コピーした文字数:%d")
,sizeof(szStr),lstrlen(szStr),copyCount);
DestroyWindow(hDlg); // ダイアログを破棄
return TRUE;
case IDCANCEL:
DestroyWindow(hDlg); // ダイアログを破棄
return TRUE;
}
return FALSE;
}
return FALSE;
}
コンパイル時に
error LNK2019: 未解決の外部シンボル
といったエラーが出る場合、前回はpragmaを使用し、#pragma comment( lib, "aygshell.lib" ) としていたと思います。
これは.dllをリンクする必要があればリンクしなさいという命令です。今回はaygshell.libファイルをリンカ入力として追加します。
プロジェクトを右クリックし[プロパティ]からプロジェクトのプロパティウィンドウを開きます。
[構成]プルダウンリストより[すべての構成]を選択します。
[プラットフォーム]プルダウンリストより[すべてのプラットフォーム]を選択します。
[構成プロパティ]-[リンカ]-[入力]を選択します。
[追加の依存ファイル]プロパティにaygshell.libを追加します。
テーマ:Windows Mobile - ジャンル:コンピュータ
DoxyCommentでC++でもコメントを自動生成
JavaにはJavadocというコメントから自動的にドキュメントを生成する標準的な機能がありますが、Visual C++には標準ツールはありません。
お勧めなのはdoxygenというドキュメント生成ツールです。ソースファイルのコメントから文書を抜き出し、HTMLをはじめとするさまざまなフォーマットのドキュメントを生成することができます。
DoxygenはQtスタイル及びJavaDocスタイルのコメン トを認識してくれます。
私はお仕事ではJavaプログラマーなのでJavaDocスタイルのコメントに慣れていますのでJavaDoc形式のコメントは助かります。
さて、今回インストールするDoxyCommentですが、そのdoxygen形式のコメントを自動生成してくれるツールです。Visual Studioにアドイン(add-in)して使用します。
別にDoxygenでドキュメント作らないよーという場合でも、ソースにコメントは入れると思います。コメント作成の作業をちょっと楽にしてくれるお勧め便利ツールです。
インストール
プロジェクトのサイト
http://sourceforge.net/projects/doxycomment/
よりインストーラをダウンロードしてインストールしてみました。
Visual Studio2005 用と2008用があります。ご自分の環境にあったファイルをダウンロードしてください。
※現在2008用はベータバージョンのようです。
Visual Studio2005の場合
ダウンロードした、doxycomment_0_4_3_setup.msi をインストールします。
Visual Studioを起動すると画像のようなツールバーがでます。
Add Code Commentをクリックすると、コメントが生成されます。
カスタムコメントプロバイダで自分好みのコメントを生成する
さて、DoxygenのデフォルトではQt形式のタグになっており、JavaDoc形式のコメントになりません。[ツール]-[オプション]のDoxyCommentで設定すればコメントブロックだけはJavaDoc形式にできますが、\authorや\versionなどのコマンドの接頭辞は\(バックスラッシュ(¥マーク))のままです。ここはやはり@で記述してほしいところです。
DoxyCommentにはコメントプロバイダというDLLを作成することで、コメントの生成を自分好みにカスタマイズすることができます。
これを使ってJavaDoc風のコメントにしてみましょう。
[ファイル]-[新しいプロジェクト]-[Visual C#]
より、クラスライブラリを選択します。
プロジェクト名:JavaDocComment
OKを押します。
参照設定に
EnvDTE(.NETライブラリ)
Microsoft.VisualStudio.VCCodeModel(.NETライブラリ)
DoxyComment(デフォルトではC:\Program Files\SourceForge.net\DoxyComment add-in for Visual Studio 2005\DoxyComment.dllにあります。)
を追加します。
DoxyComment.ICommentProviderインターフェースを実装する新しいパブリッククラスを作成してください。
ICommentProviderインターフェースのすべての方法を実装してください。
DoxyCommentのインストールフォルダにTest Providerフォルダがあります。これを参考にすると良いでしょう。
C:\Program Files\SourceForge.net\DoxyComment add-in for Visual Studio 2005\Test Provider
using System;
using System.Collections;
using DoxyComment;
using EnvDTE;
using System.ComponentModel;
using Microsoft.VisualStudio.VCCodeModel;
namespace JavaDocComment
{
[CommentProviderFriendlyName("JavaDocComment")]
public class JavaDocComment : DoxyComment.ICommentProvider
{
[CommentProviderProperty]
private string firstLineTag = "/**";
[CommentProviderProperty]
private string normalLineTag = " * ";
[CommentProviderProperty]
private string lastLineTag = " */";
[CommentProviderProperty]
private string commandPrefix = "@";
public JavaDocComment()
{
}
[Category("コメントブロック概観"),
Description("コメントブロックの先頭行の接頭辞.")]
public string FirstLineTag
{
get
{
return firstLineTag;
}
set
{
firstLineTag = value;
}
}
[Category("コメントブロック概観"),
Description("コメントブロックの行の接頭辞.")]
public string NormalLineTag
{
get
{
return normalLineTag;
}
set
{
normalLineTag = value;
}
}
[Category("コメントブロック概観"),
Description("コメントブロックの最終行の接頭辞.")]
public string LastLineTag
{
get
{
return lastLineTag;
}
set
{
lastLineTag = value;
}
}
[Category("コマンド接頭辞"),
Description("コマンドの接頭辞です。\\や@を指定します.")]
public string CommandPrefix
{
get
{
return commandPrefix;
}
set
{
commandPrefix = value;
}
}
#region ICommentProvider implementation
private ArrayList CreateCommentHeader(VCCodeElement codeElem)
{
ArrayList rv = new ArrayList();
if (FirstLineTag.Length > 0)
{
rv.Add(FirstLineTag);
}
rv.Add(NormalLineTag + CommandPrefix +"brief ここに" + codeElem.Name + " の要約を記載.");
rv.Add(NormalLineTag);
return rv;
}
private void AppendCommentFooter(VCCodeElement codeElem, ArrayList buffer)
{
buffer.Add(NormalLineTag + "ここに " + codeElem.Name + " の詳細を記載.");
buffer.Add(NormalLineTag);
buffer.Add(NormalLineTag + CommandPrefix +"remarks ここに" + codeElem.Name + " の備考を記載.");
buffer.Add(NormalLineTag);
buffer.Add(NormalLineTag + CommandPrefix +"see ");
// Does the comment provider require a last line tag?
if (LastLineTag.Length > 0)
{
buffer.Add(LastLineTag);
}
}
public string[] CreateFileComment(Document doc)
{
ArrayList rv = new ArrayList();
DateTime now = DateTime.Now;
// Begin tag?
if (FirstLineTag.Length > 0)
{
rv.Add(FirstLineTag);
}
rv.Add(NormalLineTag + CommandPrefix +"file " + doc.Name);
rv.Add(NormalLineTag + CommandPrefix +"brief ");
rv.Add(NormalLineTag);
rv.Add(NormalLineTag + CommandPrefix +"author ");
rv.Add(NormalLineTag + CommandPrefix +"date " + now.ToString("yyyy/MM/dd"));
rv.Add(NormalLineTag + CommandPrefix +"version ");
// End tag?
if (LastLineTag.Length > 0)
{
rv.Add(LastLineTag);
}
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateTypeDefComment(VCCodeTypedef codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateUnionComment(VCCodeUnion codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateMacroComment(VCCodeMacro codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
if ((codeElem.Parameters.Count > 0))
{
foreach (VCCodeParameter curParam in codeElem.Parameters)
{
rv.Add(NormalLineTag + CommandPrefix +"param " + curParam.Name
+ " パラメータ " + curParam.Name + " の説明を記載.");
rv.Add(NormalLineTag);
}
}
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateStructComment(VCCodeStruct codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateNamespaceComment(VCCodeNamespace codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateFunctionComment(VCCodeFunction codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
// Create /param sections for each parameters in the function
if (codeElem.Parameters.Count > 0)
{
foreach (VCCodeParameter curParam in codeElem.Parameters)
{
rv.Add(NormalLineTag + CommandPrefix +"param " + curParam.Name
+ " パラメータ " + curParam.Name + " の説明を記載.");
rv.Add(NormalLineTag);
}
}
// Create /returns section
if ((codeElem.TypeString.Length > 0) &
(codeElem.TypeString.ToLower() != "void"))
{
rv.Add(NormalLineTag + CommandPrefix +"returns "
+ "ここに戻り値の説明を記載.");
rv.Add(NormalLineTag);
}
// Create /throws section
rv.Add(NormalLineTag + CommandPrefix +"throws <exception class>");
rv.Add(NormalLineTag + " この例外を投げるための基準の説明を記載.");
rv.Add(NormalLineTag);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateEnumValueComment(VCCodeVariable codeElem)
{
ArrayList rv = new ArrayList();
if (FirstLineTag.Length > 0)
{
rv.Add(FirstLineTag);
}
rv.Add(NormalLineTag + CommandPrefix +"brief ここに " + codeElem.Name + " の要約を記載.");
// End tag required?
if (LastLineTag.Length > 0)
{
rv.Add(LastLineTag);
}
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateEnumComment(VCCodeEnum codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateVariableComment(VCCodeVariable codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateClassComment(VCCodeClass codeElem)
{
ArrayList rv;
// Header
rv = CreateCommentHeader((VCCodeElement)codeElem);
// Template parameters?
if ((codeElem.IsTemplate))
{
foreach (VCCodeParameter curTemplateParam in codeElem.Templatizations)
{
string typeStr;
if ((curTemplateParam.Name.Length != 0))
{
typeStr = curTemplateParam.Name;
}
else
{
int typeIdx;
typeIdx = curTemplateParam.TypeString.LastIndexOf(" ");
typeStr = curTemplateParam.TypeString.Substring(typeIdx + 1);
}
rv.Add(NormalLineTag + CommandPrefix +"param " + typeStr);
rv.Add(NormalLineTag + "パラメータ " + typeStr + " の説明を記載.");
rv.Add(NormalLineTag);
}
}
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
using System;
using System.Collections;
using DoxyComment;
using EnvDTE;
using System.ComponentModel;
using Microsoft.VisualStudio.VCCodeModel;
namespace JavaDocComment
{
[CommentProviderFriendlyName("JavaDocComment")]
public class JavaDocComment : DoxyComment.ICommentProvider
{
[CommentProviderProperty]
private string firstLineTag = "/**";
[CommentProviderProperty]
private string normalLineTag = " * ";
[CommentProviderProperty]
private string lastLineTag = " */";
[CommentProviderProperty]
private string commandPrefix = "@";
[CommentProviderProperty]
private string author ="";
public JavaDocComment()
{
}
[Category("コメントブロック概観"),
Description("コメントブロックの先頭行の接頭辞です.")]
public string FirstLineTag
{
get
{
return firstLineTag;
}
set
{
firstLineTag = value;
}
}
[Category("コメントブロック概観"),
Description("コメントブロックの行の接頭辞です.")]
public string NormalLineTag
{
get
{
return normalLineTag;
}
set
{
normalLineTag = value;
}
}
[Category("コメントブロック概観"),
Description("コメントブロックの最終行の接頭辞です.")]
public string LastLineTag
{
get
{
return lastLineTag;
}
set
{
lastLineTag = value;
}
}
[Category("コマンド接頭辞"),
Description("コマンドの接頭辞です。\\や@を指定します.")]
public string CommandPrefix
{
get
{
return commandPrefix;
}
set
{
commandPrefix = value;
}
}
[Category("制作者"),
Description("制作者を指定します.")]
public string Author
{
get
{
return author;
}
set
{
author = value;
}
}
#region ICommentProvider implementation
private ArrayList CreateCommentHeader(VCCodeElement codeElem)
{
ArrayList rv = new ArrayList();
if (FirstLineTag.Length > 0)
{
rv.Add(FirstLineTag);
}
rv.Add(NormalLineTag + "ここに" + codeElem.Name + "の要約を記載.");
rv.Add(NormalLineTag + "ここに" + codeElem.Name + "の詳細を記載.");
return rv;
}
private void AppendCommentFooter(VCCodeElement codeElem, ArrayList buffer)
{
buffer.Add(NormalLineTag + CommandPrefix +"remarks ここに" + codeElem.Name + "の備考を記載.");
// Does the comment provider require a last line tag?
if (LastLineTag.Length > 0)
{
buffer.Add(LastLineTag);
}
}
public string[] CreateFileComment(Document doc)
{
ArrayList rv = new ArrayList();
DateTime now = DateTime.Now;
// Begin tag?
if (FirstLineTag.Length > 0)
{
rv.Add(FirstLineTag);
}
rv.Add(NormalLineTag + "ここに" + doc.Name + "の概要を記載.");
rv.Add(NormalLineTag + CommandPrefix + "file " + doc.Name);
rv.Add(NormalLineTag + CommandPrefix + "author " + Author);
rv.Add(NormalLineTag + CommandPrefix + "date " + now.ToString("yyyy/MM/dd"));
rv.Add(NormalLineTag + CommandPrefix + "version ");
// End tag?
if (LastLineTag.Length > 0)
{
rv.Add(LastLineTag);
}
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateTypeDefComment(VCCodeTypedef codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateUnionComment(VCCodeUnion codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateMacroComment(VCCodeMacro codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
if ((codeElem.Parameters.Count > 0))
{
foreach (VCCodeParameter curParam in codeElem.Parameters)
{
rv.Add(NormalLineTag + CommandPrefix +"param " + curParam.Name
+ " パラメータ" + curParam.Name + "の説明を記載.");
}
}
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateStructComment(VCCodeStruct codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateNamespaceComment(VCCodeNamespace codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateFunctionComment(VCCodeFunction codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
// Create /param sections for each parameters in the function
if (codeElem.Parameters.Count > 0)
{
foreach (VCCodeParameter curParam in codeElem.Parameters)
{
rv.Add(NormalLineTag + CommandPrefix +"param " + curParam.Name
+ " パラメータ" + curParam.Name + "の説明を記載.");
}
}
rv.Add(NormalLineTag + CommandPrefix + "see ");
// Create /returns section
if ((codeElem.TypeString.Length > 0) &
(codeElem.TypeString.ToLower() != "void"))
{
rv.Add(NormalLineTag + CommandPrefix +"return "
+ "ここに戻り値の説明を記載.");
}
// Create /throws section
rv.Add(NormalLineTag + CommandPrefix +"throws <exception class> この例外を投げるための基準の説明を記載.");
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateEnumValueComment(VCCodeVariable codeElem)
{
ArrayList rv = new ArrayList();
if (FirstLineTag.Length > 0)
{
rv.Add(FirstLineTag);
}
rv.Add(NormalLineTag + CommandPrefix +"brief ここに " + codeElem.Name + " の要約を記載.");
// End tag required?
if (LastLineTag.Length > 0)
{
rv.Add(LastLineTag);
}
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateEnumComment(VCCodeEnum codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateVariableComment(VCCodeVariable codeElem)
{
ArrayList rv;
rv = CreateCommentHeader((VCCodeElement)codeElem);
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
public string[] CreateClassComment(VCCodeClass codeElem)
{
ArrayList rv;
// Header
rv = CreateCommentHeader((VCCodeElement)codeElem);
// Template parameters?
if ((codeElem.IsTemplate))
{
foreach (VCCodeParameter curTemplateParam in codeElem.Templatizations)
{
string typeStr;
if ((curTemplateParam.Name.Length != 0))
{
typeStr = curTemplateParam.Name;
}
else
{
int typeIdx;
typeIdx = curTemplateParam.TypeString.LastIndexOf(" ");
typeStr = curTemplateParam.TypeString.Substring(typeIdx + 1);
}
rv.Add(NormalLineTag + CommandPrefix +"param " + typeStr + " パラメータ" + typeStr + "の説明を記載.");
}
}
AppendCommentFooter((VCCodeElement)codeElem, rv);
return (string[])rv.ToArray(typeof(string));
}
#endregion
}
}
#endregion
}
}
[ビルド]-[JavaDocCommentのビルド]を選択してDLLを作成します。
JavaDocComment.dll
が生成されるので、これをあなたがDoxyCommentをインストールしたフォルダに「Custom Providers」という名のサブフォルダを作ってそこへコピーしてください。
デフォルトのインストール先であれば
C:\Program Files\SourceForge.net\DoxyComment add-in for Visual Studio 2005\Custom Providers
です。
Visual Studio 2005を再度起動すればカスタムコメントプロバイダがロードされます。
JavaDocCommentプロバイダを使用するように設定します。
[ツール]-[オプション]よりオプションウィンドウを開き、ツリー内のDoxyComment-Generalを選択します。
Active comment provider:JavaDocComment を設定します。
次にDoxyComment-Providerを選択します。
Comment provider:JavaDocComment を選択し、コマンド接頭辞やコメントブロック概観を好みのスタイルに設定してください。
さらにカスタマイズすれば、自分好みのコメントを自動生成できて、便利に使えるでしょう
ダイアログボックスの場合も、考え方は今まで作ってきたウィンドウのプログラムと同じです。
今まではウインドウに発生した色々な処理をウィンドウプロシージャに記述し処理していました。 ダイアログボックスの場合も同じです。ダイアログプロシージャを作成し、ダイアログに発生したいろいろな処理をダイアログプロシージャで受け取り、適切に処理します。
// SampleDialog002.cpp
//
// モードレスダイアログを作る
#include <windows.h>
#include "resource.h"
#define ID_BUTTON1 (0) // ボタンのID
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
HWND InitInstance(HINSTANCE, int);
HWND hDlg; // モードレスダイアログボックスのハンドル
HINSTANCE hInst; // アプリケーションインスタンスハンドル
TCHAR szClassName[] = _T("SampleDialog002");
// ウィンドウクラス。UNICODEとしての文字列定数
TCHAR szStr[4]; // ダイアログとのデータ受け渡し用。4文字確保(うち1つはNULLポインタ用)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd)
{
MSG msg;
BOOL bRet;
HWND hWnd;
hInst = hInstance; // アプリケーションインスタンスハンドルをグローバル変数へ格納
if (!InitApp(hInstance))
return FALSE;
if (!(hWnd = InitInstance(hInstance,nShowCmd)))
return FALSE;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1){
break;
} else {
//ダイアログからのメッセージを処理する。
if(!IsDialogMessage(hDlg,&msg)){
// ダイアログで処理されなかったメッセージは
// ウィンドウプロシージャで処理する。
TranslateMessage(&msg); // 仮想キーメッセージを文字メッセージに変換
DispatchMessage(&msg); // メッセージをウィンドウプロシージャに送る
}
}
}
return (int)msg.wParam;
}
// ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASS wc;
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WndProc; // プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL; // 未サポート
wc.hCursor = NULL; // 未サポート
wc.hbrBackground= (HBRUSH) COLOR_WINDOW;
wc.lpszMenuName = NULL; // 未サポート
wc.lpszClassName=(LPCTSTR) szClassName;
return (RegisterClass(&wc));
}
// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd)
{
HWND hWnd;
hWnd = CreateWindow(szClassName,_T("モードレス"),
WS_CLIPCHILDREN, // ウィンドウの種類
CW_USEDEFAULT, // x座標
CW_USEDEFAULT, // y座標
CW_USEDEFAULT, // 幅
CW_USEDEFAULT, // 高さ
NULL, // 親ウィンドウのハンドル。親を作るのでNULL
NULL, // メニューハンドルまたは子ウィンドウID
hInst, // インスタンスハンドル
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
return hWnd;
}
// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
size_t size; // 文字列のサイズを格納する
HWND hButton;
HWND hDlg;
switch (msg){
case WM_CREATE: // 初期化処理開始
// モードレスダイアログを開くボタン
hButton = CreateWindow(
_T("BUTTON"), // ウィンドウクラス名
_T("DIALOG"), // キャプション
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // スタイル指定
50, 50, // 座標
60, 40, // サイズ
hWnd, // 親ウィンドウのハンドル
HMENU(ID_BUTTON1), // メニューハンドル
hInst, // インスタンスハンドル
NULL // その他の作成データ
);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps); // 描画処理を開始
StringCchLength(szStr,STRSAFE_MAX_CCH,&size); // 安全な文字列長取得
ExtTextOut(
hdc, // デバイスコンテキストのハンドル
0, // 開始位置(基準点)の x 座標
20, // 開始位置(基準点)の y 座標
NULL, // 長方形領域の使い方のオプション
NULL, // 長方形領域の入った構造体へのポインタ
szStr, // 文字列
size, // 文字数
NULL // 文字間隔の入った配列
);
EndPaint(hWnd,&ps);
break;
case WM_COMMAND:
switch (LOWORD(wp)){
case ID_BUTTON1:
// モードレスダイアログウィンドウを開く
hDlg = CreateDialog(
hInst, // アプリケーションのインスタンスのハンドル
MAKEINTRESOURCE(IDD_DIALOG1),
// ダイアログボックステンプレートを指定
hWnd, // 親ウィンドウのハンドル
DlgProc // ダイアログボックスプロシージャへのポインタ
);
ShowWindow(hDlg,SW_SHOW);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
// ダイアログプロシージャ
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
static HWND hParent; // 親ウィンドウのハンドル
int copyCount;
switch(msg){
case WM_INITDIALOG: // ダイアログの初期化処理
hParent = GetParent(hDlg); // 親ウィンドウハンドル
return TRUE;
case WM_COMMAND: // ダイアログのボタンが押されたときの処理
switch (LOWORD(wp)){
case IDOK:
// エディットコントロールの値を取得
copyCount = GetDlgItemText(hDlg,IDC_EDIT1,szStr,4);
// デバッグプリント
NKDbgPrintfW(_T("szStr :バイト数: %d 文字数:%d コピーした文字数:%d")
,sizeof(szStr),lstrlen(szStr),copyCount);
InvalidateRect(hParent,NULL,TRUE); // 親ウィドウに再描画を指示
return TRUE;
case IDCANCEL:
DestroyWindow(hDlg); // ダイアログを破棄
return TRUE;
}
return FALSE;
}
return FALSE;
}
HWND CreateWindow( LPCTSTR lpClassName, // 登録されているクラス名 LPCTSTR lpWindowName, // ウィンドウ名 DWORD dwStyle, // ウィンドウスタイル int x, // ウィンドウの横方向の位置 int y, // ウィンドウの縦方向の位置 int nWidth, // ウィンドウの幅 int nHeight, // ウィンドウの高さ HWND hWndParent, // 親ウィンドウまたはオーナーウィンドウのハンドル HMENU hMenu, // メニューハンドルまたは子ウィンドウ ID HINSTANCE hInstance, // アプリケーションインスタンスのハンドル LPVOID lpParam // ウィンドウ作成データ );
HWND CreateDialog( HINSTANCE hInstance, // モジュールのハンドル LPCTSTR lpTemplate, // ダイアログボックステンプレートの名前 HWND hWndParent, // オーナーウィンドウのハンドル DLGPROC lpDialogFunc // ダイアログボックスプロシージャ );
BOOL DestroyWindow( HWND hWnd // 破棄するウィンドウのハンドル );
HWND GetParent( HWND hWnd // 子ウィンドウのハンドル );
OKボタン(IDOK)が押されたらエディットコントロールに入力された値を取得して、グローバル変数に格納します。
エディットコントロールから文字列を取得するにはGetDlgItemText関数を使います。
UINT GetDlgItemText( HWND hDlg, // ダイアログボックスのハンドル int nIDDlgItem, // コントロールの識別子 LPTSTR lpString, // テキストを受け取るバッファへのポインタ int nMaxCount // 文字列の最大サイズ );
BOOL InvalidateRect( HWND hWnd, // ウィンドウのハンドル CONST RECT *lpRect, // 長方形の座標 BOOL bErase // 消去するかどうかの状態 );
void WINAPIV NKDbgPrintfW( LPCWSTR lpszFmt, );
テーマ:Windows Mobile - ジャンル:コンピュータ
モーダルダイアログを作る
今まで、ウィンドウを使ったプログラムを作成してきました。でもちょっとした情報の表示や設定を行いたいだけの場合には、ダイアログが便利です。
また、ダイアログの場合は、VisualC++の「リソースエディタ」を用いて、WYSIWYGにダイアログを作成することが可能ですので、ちょっとしたアプリケーションの作成に向いています。
ダイアログリソースを作成する
まずダイアログリソースの作成を行います。
[ソリューション エクスプローラ]の中の、[リソースファイル]を右クリックします。
メニューから[追加(D)]-[リソース(R)...]を選択します。
[リソースの追加]ウィンドウが開くのでDialogを選択し[新規作成(N)]ボタンをクリックします。
OKとキャンセルのボタンがデフォルトで表示されています。ここにCheck Box、Static Text、Radio Button、Edit Controlを貼り付けてみます。
実行してみましょう。ダイアログの生成方法は、Windowsの場合と同じです。
モーダルダイアログ(ダイアログボックスを閉じるまで、他の操作が出来ない)で表示するソースです。
// SampleDialog001.cpp
// モーダルダイアログを作成する
#include <windows.h>
#include "resource.h"
BOOL DlgProc(HWND hDlg,UINT uMsg, WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine,int nShowCmd)
{
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,DlgProc);
}
// ダイアログプロシージャ
BOOL DlgProc(HWND hDlg,UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch (uMsg){
case WM_COMMAND:
switch( LOWORD(wParam) ) {
case IDOK:
EndDialog(hDlg,IDOK);
break;
case IDCANCEL:
EndDialog(hDlg,IDCANCEL);
break;
}
break;
case WM_CLOSE:
DestroyWindow(hDlg);
break;
}
return FALSE;
}
リソースエディタでの表示と、WindowsMobile上での表示が異なっていますね。チェックボックスとラジオボタンの上下か切れてしまっています。
これを修正するには、ダイアログのフォントをWindowsMobileにデフォルトで導入されているフォントに変更します。
では、フォントをTahomaにかえてサイズを9ポイントに設定して実行してみましょう。
このように、正しく表示されました。
なぜダイアログではこのような事が起こるのでしょう。実はダイアログではフォントのサイズを基にして、ダイアログの幅、高さ、オブジェクトの幅、高さを決めているのです。ダイアログにデフォルトで設定されているフォント "MS Shell Dlg"がWindowsMobileには存在しないため、ダイアログやオブジェクトの幅が正しく設定されず、文字が切れたり、チェックボックスやラジオボタンの上下が切れてしまったのです。
ダイアログボックスには、今回作成したモーダルダイアログボックスの他に、モードレスダイアログボックスというものがあります。
モーダルダイアログボックス | ダイアログボックスを閉じるまで、他の操作が出来ません。通常のアプリケーションではよくこれを使いますね。 |
モードレスダイアログボックス | ダイアログボックスを開いている間にも他の操作が出来ます。ダイアログボックスを開いたまま、ブラウザを開いたり、電卓を開いたりすることができます。Excelの検索ダイアログがこれにあたりますね。Excelでは検索ダイアログを開いたまま操作ができますよね。 |
では、今回のプログラムの説明です。
モーダルダイアログを作るには、DialogBox関数を呼び出します。ダイアログボックスを閉じるときにはEndDialog関数を呼び出します。
DialogBox関数
モーダルダイアログを表示します。
int DialogBox(
HINSTANCE hInstance, // インスタンスハンドル
LPCTSTR lpTemplate, // ダイアログボックステンプレート
HWND hWndParent, // 親ウィンドウのハンドル
DLGPROC lpDialogFunc // ダイアログプロシージャのポインタ
);
EndDialog関数
モーダルダイアログボックスを破棄し、そのダイアログボックスに関係するすべての処理を終了します。
BOOL EndDialog(
HWND hDlg, // ダイアログボックスのハンドル
INT_PTR nResult // 返したい値
);
WinMain関数を見てください。今までのプログラムとは違い、メッセージループがありません。これは、DialogBox関数の処理はEndDialog関数が呼び出されるまで終了しないためです。
DialogBox関数のlpTemplateにはダイアログリソースを指定します。リソース識別子を指定する場合、上位ワードに 0 を、下位ワードに識別子を指定しなければなりません。MAKEINTRESOURCEマクロを使用すれはリソース識別子を作成できます。
lpDialogFuncにはダイアログプロシージャを指定します。
ダイアログプロシージャDlgProcを見てみましょう。ダイアログでは、ボタンが押されるなどのイベントが発生すると、WM_COMMANDメッセージが届きます。これだけでは、どのボタンが押されたのかわかりませんね。追加の情報がwParamに格納されています。どのボタンか判断するにはLOWORD(wParam)とします。これで押されたボタンのIDがわかります。
LOWORDは特定の値の下位ワードを取り出すマクロです。つまりwParamの下位ワードに押されたボタンのIDが格納されているのです。
サンプルでは、IDOKとIDCANCELの処理を別々に書いていますが、ダイアログプロシージャの中での処理が特にない場合はまとめて下のように書きます。EndDialogの第2引数にLOWORD(wParam)を指定するのがポイントです。
switch( LOWORD(wParam) ) {
case IDOK:
case IDCANCEL:
EndDialog(hDlg,LOWORD(wParam));
break;
}
今日はここまでです。
テーマ:Windows Mobile - ジャンル:コンピュータ
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |