Version 14.32
スレッドからダイアログに表示する、の続き
「前回はソースコードだけでした」
『あれだけで、しかもまだ書いちゃダメってゆーし……』
「うん、エディットボックスとか用意してなかったから」
『え、ダイアログの方になんかしなきゃいけないの?』
「結果とか検索中のフォルダとか表示するでしょ」
『そういえば……』
「というわけで、まずはダイアログにコントロールを追加します。
【ファイル検索】ダイアログ、つまり IDD_SEARCHDLG_DIALOG を開いて」
『ダイアログエディタでだよね』
「もちろん。そこにエディットボックスを貼り付けて、 ID は
【IDC_E_MATCH_NUM】、スタイルの【境界線】をオフ、【読み取り専用】を
オンにして」
『? これってなんの意味があるの?』
「やってみるとわかるけど、見た目がスタティックコントロールみたいにな
るでしょ」
『ほんとだ、文字だけみたい』
「でもエディットボックスだから、文字列をセットできるんです」
『なるほど、見た目はスタティックコントロールだけど、使い勝手は
エディットボックス、みたいな?』
「そういうこと。ここには検索結果、つまり一致した数をセットします」
『ほい』
「というわけで、 ClassWizard でこのエディットボックスの変数を作って」
『うわ、懐かしい作業を……メニューの【表示】−【ClassWizard】で、
【メンバ変数】のページで IDC_E_MATCH_NUM を選んで【変数の追加】っと』
「変数名は m_cMatchNumStr 、あとはそのまま【値】の【CString】で」
『ほいほい』
「次に、【検索中】ダイアログに【今検索しているフォルダ】を表示する欄
を作ります。【検索中】ダイアログ開いて」
『ほい』
「同じようにエディットボックスを貼り付けて、 ID は IDC_E_FOLDER 、
スタイルはさっきと同じ」
『ん、スタティックコントロールみたくなった』
「ただ、こっちは変数は作りません」
『え、どうして?』
「これはソースコードの説明の時に。それと、このダイアログの
WM_INITDIALOG のイベントハンドラを作って」
『ダイアログが表示するときに送られるメッセージだね。メニューの
【表示】−【ClassWizard】開いて、【MFC ClassWizard】ダイアログの
【メッセージマップ】のとこで……』
「【オブジェクト ID】を【CSearchingDlg】にして、右の【メッセージ】で
【WM_INITDIALOG】を選んだら【関数の追加】押して【コード編集】」
『ん、 CSearchingDlg::OnInitDialog() できた』
「ここの段階で、 SearchingDlg.cpp には CSearchingDlg::OnCancel() と
CSearchingDlg::OnInitDialog() のふたつのイベントハンドラが作られたこ
とになってると思います」
『うんなってる』
「この状態で前回のソースを見返してみて。 SearchDlgDlg.cpp のソースに
このふたつの関数があるでしょ」
『あ、ほんとだ』
「このふたつの関数の上に StartCountMatchFile() と CountMatchFile() 、
その他諸々を入れる、っていう形にしてください」
『それにしても長い……』
「って言っても、基本的にはこの前の検索と変わらないけどね。追加した機
能ひとつひとつ見ていこうか」
・検索対象フォルダの表示
『これはさっきの IDC_E_FOLDER に表示するんだね』
「そう。さっき説明したように、変数を使わず、直接ウィンドウハンドルを
使ってセットします。まず、そのための変数を用意します」
// エディットボックスのウィンドウハンドル。
HWND g_hEditFolderWnd = NULL;
「次に、ダイアログの表示時に IDC_E_FOLDER のウィンドウハンドルをセッ
トします」
BOOL CSearchingDlg::OnInitDialog()
{
// 略...
// エディットボックスのウィンドウハンドルをセットします。
g_hEditFolderWnd = ::GetDlgItem( GetSafeHwnd(), IDC_E_FOLDER );
// 略...
}
「 Version 5.26 ( No.091 ) で説明した方法で取得します」
『本当に API つかって直接セットしてるんだね』
「セットするのも API を使います」
int CountMatchFile
( const char * const p_pchFolderPath
, const char * const p_pchFileName
)
{
// 略...
// フォルダが存在するのでウィンドウタイトルをセットします。
if( ::IsWindow( g_hEditFolderWnd ) )
{
// ウィンドウが存在するので表示します。
::SetWindowText( g_hEditFolderWnd, p_pchFolderPath );
}
// 略...
}
『? IsWindow() って?』
「これはウィンドウが存在してるかどうかチェックする API 。
CountMatchFile() って別スレッドで動いてるから、いつの間にかダイアログ
がなくなってる可能性があるから」
『げ、そういうのもチェックしなきゃいけないんだ……』
「 SetWindowText() はエディットボックスに文字列をセットする API 」
『さっきの Version 5.26 ( No.091 ) にも出てたのだね』
「具体例なら Version 5.27 ( No.092 ) の方がいいかな」
『で、なんで変数使ってセットしないの?』
「変数を使ってセットする方法だと、 MFC を使うことになります」
『そなの?』
「 CWnd::UpdateData() とか使うでしょ」
『そういえば、あれとかって API にはないよね……』
「結局が MFC が SetWindowText() とかしてるんだけどね。変数とか使って
分かりやすくしてるだけ。で、実は MFC は、マルチスレッドが苦手なんで
す」
『あ、そういえば前にそう言ってたね』
「 MFC の、特にウィンドウ関係はマルチスレッドを逆に複雑に使っている
から、別スレッドからの操作がうまくできないんです」
『げ……だから直接 API で?』
「そういうこと。次に説明する」
・検索終了時にキャンセルダイアログを閉じる機能
「も、同じように MFC の問題があるんです」
『げ”』
「基本的に、方法は同じ。ダイアログが作られるときにウィンドウハンドル
を取っておいて、検索が終わったらそれを使ってダイアログを閉じるだけ。
まずは取っておく変数」
// ダイアログのウィンドウハンドル。
HWND g_hSearchingDlgWnd = NULL;
「ここに、ダイアログが表示されるときにセットします」
BOOL CSearchingDlg::OnInitDialog()
{
// 略...
// ダイアログのウィンドウハンドルをセットします。
g_hSearchingDlgWnd = GetSafeHwnd();
// 略...
}
「そして、検索終了時にこれを使ってダイアログを閉じます」
void StartCountMatchFile( void *p_p )
{
// 略...
// ダイアログを閉じます。
if( ::IsWindow( g_hSearchingDlgWnd ) )
{
// ウィンドウが存在するので閉じます。
::SendMessage
( g_hSearchingDlgWnd
, WM_COMMAND
, MAKEWPARAM( IDCANCEL, 0 )
, 0
);
}
}
『あれ? ダイアログ閉じるのって EndDialog() じゃなかったっけ』
「 Version 8.09 ( No.151 ) でそう教えたけど、ここではダメ」
『これも MFC の関係?』
「そういうこと。 EndDialog() だと API で直接ダイアログ閉じちゃうか
ら。そうじゃなく、 MFC を通してダイアログを閉じてもらう必要があるん
です」
『それがこの SendMessage() ? えっと、 WM_COMMAND って……そっか、
ボタン押したとき、ってメッセージ送ってるんだ』
「そういうこと。これも Version 8.09 ( No.151 ) で説明したね。あの時
は受け取る時だったけど、今回は送る場合」
『こうやって送ると…… IDCANCEL ボタンが押されたってなるんだ』
「そういうこと。そうすれば MFC の方、つまり CSearchingDlg クラスで処
理してくれるから大丈夫」
『……って、それってかなり難しいかも……知らなきゃわかんないよ』
「僕も知らなかったよ」
『え”?』
「試してうまくいかなかったから調べただけ……こういうところもマルチ
スレッドの難しいところかも」
『ううう……』
「最後に」
・検索結果の表示
「これは前回と同じような感じ」
// 一致数。
int g_iMatchNum = 0;
// 一致数を取得します。
int GetMatchNum()
{
return g_iMatchNum;
}
「という形で変数と関数を用意して」
// SearchDlgDlg.h
// 略...
int GetMatchNum();
「というふうにして呼べるようにして」
// SearchDlgDlg.cpp
// 略 ...
void CSearchDlgDlg::OnSearchStart()
{
// 【検索中】ダイアログを表示します。
CSearchingDlg cDlg;
cDlg.DoModal();
// 結果を出力します。
m_cMatchNumStr.Format( "%d", GetMatchNum() );
UpdateData( FALSE );
}
「ここで出力」
『 CString::Format() 使って文字列に変換して、あ、 m_cMatchNumStr が
さっき変数作った IDC_E_MATCH_NUM だね』
「これでダイアログに一致結果が表示されるから」
/*
Preview Next Story!
*/
「次回はマルチスレッド編最終回!」
『長かった……って感じもしないかな』
「マルチスレッドだけ見ると少ないからね」
『そういえば前半は同期オブジェクトだった……』
「というわけで次回」
< Version 14.33 マルチスレッドのまとめ >
『につづく!』
「もちろん Version 15 の話や、さらにその先の話も!」
『つかいつまで続くのー! もう6年だよー!!』