いつもお世話になります。
わからないことがでてきたので質問させてください。
開発環境↓
Windows XP Professional Version 2002 Service Pack2
Microsoft Visual Studio .NET 2003
MFC Application
やりたいこととしては、Buttonを押下すると一定時間(次の例でいうと、sleep(3000)で3秒間)ダイアログを出力させ、
その時間はメインダイアログのボタンクリックを受け付けない。一定時間経過すればクリックを受け付ける。
という構成を考えています。
そこで、次のようなプログラムを組んでみて、完成だと思ったのですが、おかしな動きをすることに気づきました。
ダイアログが出力されている間にクリックは受け付けないのですが、そのクリック情報が残っているようで、
ダイアログが消滅したあと、そのクリックの動作をしてしまいます。
何かわかる方いらっしゃいましたら、ご指導のほど宜しくお願いします。
---TestView.cpp---
void CTestView::OnBnClickedButton()
{
CWnd* pWndParent = GetParent();
pWndParent ->EnableWindow(FALSE);
CExclusionDlg::getInstance()->dispDialog();
Sleep(3000);
CExclusionDlg::getInstance()->destroyDialog();
pWndParent ->EnableWindow(TRUE);
pWndParent ->ActivateTopParent();
}
---ExclusionDlg.cpp---
void CExclusionDlg::dispDialog(){
instance->Create( IDD_EXCLUSION );
instance->EnableWindow( FALSE );
}
void CExclusionDlg::destroyDialog(){
instance->DestroyWindow();
}
CExclusionDlg* CExclusionDlg::getInstance(){
if(instance == NULL){
instance = new CExclusionDlg();
}
return instance;
}
MFC じゃないけど。
API で BlockInput 関数があるよ。
この関数は
>キーボードおよびマウス入力イベントをブロックし、
>アプリケーションに到達しないようにします。
とあるのでこれ使えばマウスのクリックを無効に出来ると思う。
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_blockinput.asp
EnableWindow の代わりに BlockInput を使う。
じゃあね。
>夏みかんさん
レスありがとうございます。
ただ、BlockInputを使ったのですが、
pWndParent ->EnableWindow(FALSE);
↓
pWndParent->BlockInput(TRUE);
としてもコンパイルが通りません。
error C3861: 'BlockInput': 識別子は、引数依存の照合を使用しても見つかりません。
と出力されてしまいます。
Microsoft Visual Studio .NET 2003
では使えない関数なのでしょうか。。
何かわかりましたら、ご教授宜しくお願いします。
>pWndParent ->EnableWindow(FALSE);
> ↓
>pWndParent->BlockInput(TRUE);
pWindParent-> が要らないのではないでしょうか?
>>MFC じゃないけど。
>>API で BlockInput 関数があるよ。
とアドバイス頂いてますよね。
MSDNで調べてみてください。
>keichanさん
ありがとうございます。
>pWindParent-> が要らないのではないでしょうか?
すいません、書き間違えましたm(__)m
BlockInput(TRUE);
の間違いです。
「pWindParent->」を削除してもコンパイルが通りません。
MSDNを調べてもわからなかったのですが、何か手がかりはありませんでしょうか?
なんか話が難しい方向に行ってる気がする
俺なら 時間で勝手に閉じるモーダルダイアログ を作って DoModal するだろうな。
void CTestView::OnBnClickedButton() {
CSelfCloseDlg dlg(3000); // 3000msec=3sec
dlg.DoModal();
}
class CSelfCloseDlg の実装はお任せする
>tetrapodさん
ご意見ありがとうございます。
なるほど、確かにいい方法だと思います。
ですが、申し訳ありません。
私の最初の投稿に表現が足りませんでした。
一番伝わりやすいであろうと思ってあのような表現にしました。
実際にやりたいことを補足します。
ボタンクリックでやりたいことは******までです。
void CTestView::OnBnClickedButton()
{
CWnd* pWndParent = GetParent();
pWndParent ->EnableWindow(FALSE);
CExclusionDlg::getInstance()->dispDialog();
***********************************************************
Sleep(3000);
CExclusionDlg::getInstance()->destroyDialog();
pWndParent ->EnableWindow(TRUE);
pWndParent ->ActivateTopParent();
}
Sleep()以下の処理は非同期で発生するイベントがあって、その関数内から実行されます。
つまり、ボタンをクリックした段階では、destroyDialog()は非同期で発生するため、何秒後に実行されるかわかりません。
誤解を招いてすいませんでしたm(__)m
やりたいこと伝わりましたでしょうか。。
やりたいことと書いてることがまったく違うぢゃん・・・時間の無駄ね。
・たとえばファイルのコピーとか、何らかのやりたい処理があって
・ボタンを押すとそれが開始され
・処理中は自分自身が触れないようにしたい
・処理はいつ終わるかわからない
ということでOK?
俺は以下のような仕様にした。
・[開始]ボタンを押すと処理開始する
・[開始]ボタンは、押すと[中断]ボタンに変わる(触れるままにしておく)
処理終了時点で[開始]に戻る
・[設定]ボタン等、[開始]以外のボタンはすべて、
処理開始時点でEnableWindow(FALSE)終了時点でEnableWindow(TRUE)
これで何か困ることがあるかな?
UIスレッドと、実処理するワーカスレッドは別にあるのが前提。
> tatrapodさん
ご指摘と仕様のご提案ありがとうございます。
仕様に関して細かい点ですが、[開始]ボタンを押した際は[中断]に変わるのではなく、ダイアログが出力されるという仕様で考えたいと思います。
その他はtatrapodさんの書かれた通りです。
よい考えはありますでしょうか?
DoModalでダイアログを開き
ダイアログの中で計算し
ダイアログは、処理が終わったら自分を閉じる。
処理しながらプログレスバーなんかも出しやすい
>rinさん
ありがとうございます。
問題点がうまく伝わってないかもしれないので、改めて書きますと、
「ダイアログが出力されている間にメイン画面のボタンをクリックすると受け付けないのが、そのクリック情報が残っているようで、ダイアログが消滅したあと、そのクリックの動作をしてしまいます。」
というのが問題点です。
いかがでしょうか。。
OnButton() {
CWorkerDlg d;
d.DoModal();
}
としておき実処理はすべて CWorkerDlg 内部で完結させればいいぢゃん
プログレスバーも CWorkerDlg に出しやすいしとっても楽ぢゃん
というのがrin氏の主張だと思うのだが、まったく伝わっていないような希ガス
DoModal() すると自動的に親画面が触れなくなるので万事解決
ちなみにBlockInputのコンパイルが通らなかったのは
#include <winable.h>
がなかったのでは?
(※BlockInputでぐぐってここへ来た人へのフォロー補足)
>tetrapodさん
ありがとうございます。
イメージは沸きました。
ただ、こちらの都合で今日は実行環境が閉じられたため、
今試せないので、明日試してみてまた返事いたします。
>みいさん
ありがとうございます。
#include <winable.h>
でコンパイルは通りました。
ただ、これ初めて使ってみたんですけど、ダイアログ出力中はマウスも
使えなくなって、ちょっと使いにくいんですね。。(汗)
やりたいことと少し離れているので、今回は使わないでおこうと思います。
勉強になりました。ありがとうございました。
解決しました。
みなさんが言ってくださったように、
ダイアログの出力はDoModalで行い、
ダイアログを消すときは、DoModalするクラス内にdestroyDialog()の処理を書いてやって、
消すタイミングでこの関数を呼んでやるようにしました。
void CExclusionDlg::destroyDialog(){
CDialog::OnCancel();
}
皆さん、的確な指摘と助言ありがとうございました。
終了方法は EndDialog にしてくれよ、頼むから
修正しました(汗)
ツイート | ![]() |