ファイルの検索処理を行っている間、処理中を表示するダイアログを表示しようと思っています。
検索処理を呼び出す前に、処理中ダイアログを
Createで作成し、ShowWindowで表示しています。
処理中ダイアログには、マーキーを配置していて、マーキーを動かすことで処理中をアピールしたいのですが、
現在表示された画面ではマーキーが固まっていて動きません。
処理中画面のOnInitDialogでは、
CProgressCtrl m_nProg;
::SetWindowLong(m_nProg.GetSafeHwnd(), GWL_STYLE, WS_CHILD | WS_VISIBLE | PBS_MARQUEE);
m_nProg.SendMessage(PBM_SETMARQUEE, TRUE, 50);
としているのですが、CreateしてShowWindowするだけでは何かが足りないのでしょうか?
よろしくお願いします。
お約束ですが……
その「ファイルの検索処理」はどのように実行していますか?
「OnInitDialog()などから処理を呼び出していて完了するまで戻ってこない。」
とかいうことはありませんか?
瀬戸っぷ さん、コメントありがとうございます。
説明不足ですみません。
ファイルの検索処理は、画面の検索ボタン押下時に開始します。
検索ボタン押下イベント関数の中で、
処理中画面表示→検索開始→検索終了→処理中画面閉じる
の流れで処理を行っています。
処理中画面をShowWindowで表示しているので、呼び出し元の画面が処理中でも処理中画面は動作すると思っているのですが、
そういうものではないのでしょうか?
これ(VBだとDoEvents)のことかな?
for(;;) {
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
!AfxGetThread()->PreTranslateMessage(&msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
: 何かの処理
}
もしくは
m_nProg.SendMessage(PBM_SETMARQUEE, TRUE, 50);
のあとに
m_nProg.UpdateWindow();
前回もそうですけど定番なので覚えておくといいですよ。
補足とです。全力で仕事しているので
息抜きするか、強制的に割り込みを入れるかです。
メッセージについて勉強してみて下さい。
そに さん、ありがとうございます。
そうです、。VBでいうところのDoEvents状態を作りたいと思っています。
マーキーは処理中画面のOnInitDialogで設定しています。
処理中画面のマーキー設定の後に入れてみましたが動きませんでした。
いくつかの処理を行う間処理中画面を表示したいので、
ところどころでDoEventsの代わりになるものを呼んでやればいいということですね。
処理の前後に入れてみて、試してみます。
とりあえず、ご報告です。
・処理中画面をShowWindowで表示後
・検索ファイル名取得後
・ファイル検索後
にそれぞれ教えていただいた
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
!AfxGetThread()->PreTranslateMessage(&msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
を入れてみたのですが、マーキーは動かないままでした。
どうも、まだ息抜きができていないようです。
ちなみにこの処理中画面、他のところでも使っているのですが、
他のところでは、大元のダイアログにメッセージを送り、大元のダイアログでDoModalで呼び出しを行っています。
ただし他のところでは、大元のダイアログにメッセージを送った後関数を抜けているので、自動で息抜き状態が発生しています。
一瞬でも息抜き状態が作れれば、他のところと同じ様な使い方ができるかな、とも思うのですが・・・
もし他の息抜き方法が有りましたら、情報をよろしくお願いします。
>・処理中画面をShowWindowで表示後
>・検索ファイル名取得後
>・ファイル検索後
>にそれぞれ教えていただいた
> if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
> !AfxGetThread()->PreTranslateMessage(&msg)) {
> ::TranslateMessage(&msg);
> ::DispatchMessage(&msg);
> }
>を入れてみたのですが、マーキーは動かないままでした。
それぞれの後に1回ずつ…ですか?
# 『・検索ファイル名取得後』は何度も動く…んでしょうかね?
メッセージキューにたまりまくっているんじゃないでしょうか?
私ならさっくりとワーキングスレッド作って処理しますけどね…。
瀬戸っぷ さん、コメントありがとうございます。
それぞれの後に1回ずつ入れてみました。
「検索ファイル名取得後」は呼び元の後に1回だけ入れてみました。
が、特に変化はなく、、、の状態です。
ShowWindowの後に1回だけ入れるパターンもやってみましたが、動かないままでした。
元々の作りや扱いは、処理中画面がスレッドっぽい扱いの作りになっているので、
それを生かすように作りたいとは思っているのですが、、、
またいろいろ試してみます。
一旦、ソースを提示してみてはどうでしょうか?
>それぞれの後に1回ずつ入れてみました。
>「検索ファイル名取得後」は呼び元の後に1回だけ入れてみました。
そうすると…都合3回…ですか?
実際にその処理が走るのが数回とか…回数少ない場合には全然足りていないと思いますが…。
OnInitDialog()に入ったところでブレークポイントでも張って、Spy++などでどれだけメッセージが流れるか眺めてみてはどうでしょう?
処理したメッセージが少なかったか実感できるかと。
# まぁブレークポイント設定して停めるとアクティブウィンドウの切り替えなどもあるので余計に流れますけどね。
Ryo さん、コメントありがとうございます。
処理を行っている流れは以下の様になります。
#実際のソースは長いので各処理部分は省略しています。
<処理中画面呼び出し>
CWaitDlg *n_pDlg;
n_pDlg = new CWaitDlg(this);
n_pDlg->Create(IDD_WAITDLG);
n_pDlg->CenterWindow(); // 親ダイアログの中央表示
n_pDlg->GetDlgItem(IDC_PROGRESS1)->UpdateWindow();
n_pDlg->ShowWindow(SW_SHOW); // 画面表示
n_pDlg->RedrawWindow(); // 再描画
n_pDlg->SetFocus();
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
!AfxGetThread()->PreTranslateMessage(&msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// 検索ファイル名取得
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
!AfxGetThread()->PreTranslateMessage(&msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// ファイル検索処理→再帰関数にも入れました。
// WaitDlgポインタ削除
if(n_pDlg)
{
n_pDlg->DestroyWindow();
delete n_pDlg;
}
呼び出している処理中画面は以下の様に作成しています。
BOOL CWaitDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: ここに初期化を追加してください
LOGPRINT( LOG_LV_FNC_S, __FUNCTION__, "", 0 );
// プログレスバーをマーキー表示に設定
::SetWindowLong(m_nProg.GetSafeHwnd(), GWL_STYLE, WS_CHILD | WS_VISIBLE | PBS_MARQUEE);
m_nProg.SendMessage(PBM_SETMARQUEE, TRUE, 50);
return TRUE; // return TRUE unless you set the focus to a control
// 例外 : OCX プロパティ ページは必ず FALSE を返します。
}
何か設定抜けがありますでしょうか?
よろしくお願いします。
何箇所にも同じ内容をコピペするってのは下策中の下策。
コピペ元が間違ってたら全部バグるし、
本来やりたい・やらなきゃならない処理を分断するし、
コードを読む側の思考にも割り込んでくるし、
良いことひとつも無い。
俺個人的には、各種処理中に DoEvent するのは推奨できないので
(予期せぬ動作を引き起こす元凶となる)
使わない方向に1票
http://social.msdn.microsoft.com/forums/ja-JP/vbgeneralja/thread/ac888f05-b215-4604-9e0e-9bf5a843ce13/
> 私ならさっくりとワーキングスレッド作って処理しますけどね…。
心の底から同意
tetrapod さん、コメントありがとうございます。
元々は、1行何かを入れればよいのかと思って質問したのですが、
確かに、あちこちに入れないといけないのは面倒だなぁ、と思っていたところです。
確かに処理だけを別スレッドで処理出来ればコーディングもメンテも楽だろうと思うのですが、もう1方法、あがいてみたいと思っています。
こちらについてもアドバイスをお願いします。
元々のプロジェクトのつくりとして、処理中画面を表示する場合は、
メインダイアログにPostMessageを送り、メインダイアログのWindowProcの中で
m_WaitDlg.DoModal();
で表示しています。
今回もこの流れで処理中画面を表示させたかったのですが、メインダイアログに送ったPostMessageがWindowProcで処理されるタイミングがうまくいかず他の方法としてCreateする方法を考えました。
ファイル検索等を行う処理は、メインダイアログから呼び出したダイアログ上のボタンクリックでスタートしています。
メインダイアログに送ったメッセージを、即処理するように促すようなことはできるのでしょうか?
具体的コードが無いので想像(妄想)にしかならないんだけど
# かといってソースコードを提示されても困るんだが
> メインダイアログに送ったメッセージを、即処理するように促すようなことはできるのでしょうか?
こういう質問が出るということは、 PostMessage と SendMessage の違いに対する
理解不足を疑うことになるわけだが、何がどう違うのか理解できているかな?
同じものを何回もコピペしてはるような場合は、
別に関数をつくって、その関数を呼び出すようにすれば
入れ込むところは1行となり、ある程度は楽になります
tetrapod さん、コメントありがとうございます。
そういえばSendすれば処理完了確認できますね。
元のソースがPostで呼び出しを行っていたので、何となく流れでそれを流用しようとしていました。
Sendで問題がないか確認してみます。
Ryo さん、コメントありがとうございます。
確かに関数にまとめておけば、
変更が発生した際に変更漏れがなくなりますね。
早速組み込みたいと思います。
みなさん、いろいろとアドバイスありがとうございました。
元々のプロジェクト作成者に聞き込みを行ったところ、
他の画面描画との兼ね合いがあるので、
スレッドを作って処理を行ってください、とのことでした。
そのため、ファイル検索等の処理をスレッドで行う方針になりました。
ちなみにSendMessageをPostMessageに変更して試したところ、先に処理されることを確認しました。
このまま進めたかったのですが、スレッド作成ということになりましたので、
一応、解決とさせていただきます。
ありがとうございました。
ツイート | ![]() |