FC2ブログ

まったり開発日誌

embossの工具箱(J2EE Java2 Linux Zaurus C++)

2008年11月

  1. スポンサーサイト(--/--)
  2. 019:モードレスダイアログを作る (11/20)
  3. コーディング規約でヘボン式を使用するならこの関数(11/18)

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

019:モードレスダイアログを作る

モードレスダイアログを作る 

ダイアログボックスの場合も、考え方は今まで作ってきたウィンドウのプログラムと同じです。

今まではウインドウに発生した色々な処理をウィンドウプロシージャに記述し処理していました。 ダイアログボックスの場合も同じです。ダイアログプロシージャを作成し、ダイアログに発生したいろいろな処理をダイアログプロシージャで受け取り、適切に処理します。

ではサンプルを見てみましょう。
 
 

// 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
;



}


動作イメージは次のようになります。
起動するとメインウィンドウが表示されます。
ボタンをクリックするとダイアログが表示されます。
OKを押すと、入力した内容がメインウィンドウに反映されます。
キャンセルでダイアログを閉じます。
 
今回は、メインウィンドウを作成後、ダイアログウィンドウを作成します。
メインウィンドウにはウィンドウプロシージャ、ダイアログにはダイアログプロシージャをそれぞれ用意しています。
メインウィンドウの作成は今までと全く同じですので問題ないでしょう。
ウィンドウプロシージャを見てください。
ウィンドウを作成するときの初期化処理として、WM_CREATEメッセージがきたら、ウィンドウにボタンを表示しています。
よく見てください。ボタンの生成にCreateWindowを使っています。メインウィンドウと同じですよね。実はボタンやエディットコントロール、ラジオボタンといったよく使われるコントロールは皆、特殊なウィンドウなのです。ウィンドウですから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        // ウィンドウ作成データ
);
 

いままではCreateWindow関数の第1引数lpClassNameにはウィンドウクラス名を定義していました。ここに定義済みのウィンドウクラス名を指定することが出来ます。
今回の例ではウィンドウクラス名に_T("BUTTON")を指定して、ボタンのコントロールを生成しています。
第3引数dwStyleに、BS_PUSHBUTTONを指定していますので、いわゆるコマンドボタンになります。この第3引数にBS_CHECKBOXを指定するとチェックボックス、BS_GROUPBOXを指定するとグループボックスになります。チェックボックスもグループボックスも「ボタン」の一種ってのがちょっと不思議に感じられるかも知れません。
dwStyleに指定できるスタイルはウィンドウクラスによって異なってきます。詳しくはMSDNを参照してください。
また第8引数hWndParentに親ウィンドウのハンドルを指定します。メインウィンドウのハンドルを指定しましたので、作成するボタンは、メインウィンドウの子ウィンドウになります。
第9引数hMenuのメニューハンドルには、このボタンを識別するコードを設定します。あとでこのボタンからのメッセージであることを識別するのに使います。
今回は識別用に
#define ID_BUTTON1 (0)             // ボタンのID
を作りました。
 
ボタンが押されたときの処理は、ウィンドウプロシージャにWM_COMMANDメッセージが届いたときの処理に記述します。LOWORD(wp)がID_BUTTON1であれば、ボタンが押されたということです。
このときにモードレスダイアログを開くようにします。
モードレスダイアログはCreateDialogマクロで作成し、DestroyWindow関数でダイアログを破棄します。
 
CreateDialogマクロ
ダイアログボックステンプレートリソースから、モードレスダイアログボックスを作成します。
HWND CreateDialog(
  HINSTANCE hInstance,  // モジュールのハンドル
  LPCTSTR lpTemplate,   // ダイアログボックステンプレートの名前
  HWND hWndParent,      // オーナーウィンドウのハンドル
  DLGPROC lpDialogFunc  // ダイアログボックスプロシージャ
);
hInstance にはアプリケーションハンドルを指定します。
lpTemplate にはダイアログボックステンプレートを指定します。指定にはMAKEINTRESOURCEマクロを使用します。
hWndParent には親ウィンドウのハンドルを指定します。
lpDialogFunc にはダイアログボックスプロシージャを指定します。
 
DestroyWindow関数
指定されたウィンドウを破棄します。
BOOL DestroyWindow(
  HWND hWnd   // 破棄するウィンドウのハンドル
);
 
DlgProc関数がモードレスダイアログボックスのプロシージャです。
プロシージャ内で最初に呼ばれるのはWM_INITDIALOGメッセージです。ダイアログが初期化されるときにWM_INITDIALOGメッセージが送られてきます。このメッセージが来たら、ダイアログボックスで必要な初期化処理を記述しておけばよいわけです。
ここでは、親ウィンドウの再描画処理のために親ウィンドウのハンドルが必要となりますので取得しておきます。
親ウィンドウハンドルの取得にはGetParent関数を使います。
 
GetParent関数
親ウィンドウハンドルを返します。
HWND GetParent(
  HWND hWnd   // 子ウィンドウのハンドル
);
 
ダイアログのボタンが押されると、WM_COMMANDメッセージが送られてきます。どのボタンが押されたのか判定するにはWPARAMの下位バイトを見ればよかったですよね。

OKボタン(IDOK)が押されたらエディットコントロールに入力された値を取得して、グローバル変数に格納します。
エディットコントロールから文字列を取得するにはGetDlgItemText関数を使います。

 
GetDlgItemText関数
ダイアログボックス内の指定されたコントロールに関連付けられているタイトルまたはテキストを取得します。
UINT GetDlgItemText(
  HWND hDlg,       // ダイアログボックスのハンドル
  int nIDDlgItem,  // コントロールの識別子
  LPTSTR lpString, // テキストを受け取るバッファへのポインタ
  int nMaxCount    // 文字列の最大サイズ
);
hDlg にダイアログボックスのハンドルを指定します。
nIDDlgItem には取得したいコントロールの識別子を指定します。
lpString には文字列格納用の領域を指定します。ここでは親ウィンドウに文字列を渡したいのでグローバル変数を指定しています。
nMaxCount  には文字列の長さをTCHAR単位で指定します。 
格納したら親ウィンドウに再描画を指示します。すると親ウィンドウはグローバル変数に格納された文字列を、自分のウィンドウ内に描画します。 再描画にはInvalidateRect関数を使います。

 

InvalidateRect関数
指定されたウィンドウの更新リージョン(再描画しなければならない部分)に 1 個の長方形を追加します。 
BOOL InvalidateRect(
  HWND hWnd,           // ウィンドウのハンドル
  CONST RECT *lpRect,  // 長方形の座標
  BOOL bErase          // 消去するかどうかの状態
);
 
InvalidateRect関数を使って無効領域(更新領域)を発生させます。
無効領域とは、画面が他のウィンドウなどで隠れてしまうことです。通常は、無効領域が発生するとWM_PAINTが発生して、再描画する仕組みになっています。
しかし、プログラムの中で状態を変化させ、それを画面に反映したい場合もあると思います。
そのような場合に、InvalidateRect関数を実行して無効領域を発生させるわけです。
意図的に無効領域を発生させると、WM_PAINTが発生します。
つまり結果的に、親ウィドウに再描画を指示することが出来るというわけです。
 
ダイアログプロシージャの中に、NKDbgPrintfW関数という見慣れないものがありますね。これはデバッグ出力ストリーム(出力ウィンドウ)に文字列を出力できる関数です。デバッグには重宝します。

NKDbgPrintfW関数
デバッグ出力ストリームに文字列を出力します。
void WINAPIV NKDbgPrintfW(
  LPCWSTR lpszFmt,
);
引数lpszFmtにはprintfスタイルの書式を指定します。デバッグには結構便利な関数です。 
 
関数がたくさん出てきましたね。 
今日はここまでです。
 

 

スポンサーサイト

テーマ:Windows Mobile - ジャンル:コンピュータ

  1. 2008/11/20(木) 23:28:42|
  2. WindowsMobileではじめるWin32APIプログラミング入門
  3. | トラックバック:0
  4. | コメント:0

コーディング規約でヘボン式を使用するならこの関数

コーディング規約などで、日本語からアルファベットへの変換は「ヘボン式」を使うことと規定されていることがある。

そんなときは、Excelマクロで一気に変換すると楽だ。使い方はこんな感じ。

=hebooon(PHONETIC(A1))

 

[コーディング規約でヘボン式を使用するならこの関数]の続きを読む
  1. 2008/11/18(火) 22:51:46|
  2. 便利なツール類
  3. | トラックバック:0
  4. | コメント:0

RSSフィード

カレンダー

10 | 2008/11 | 12
- - - - - - 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 - - - - - -

カテゴリー

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

リンク

このブログをリンクに追加する

メールフォーム

名前:
メール:
件名:
本文:

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。