うらで何か動作しているとき、キャンセルボタンを押せるようにしたいのですが、
(例えば、Sleep()の間にキャンセルする)
イネーブルにしていても、ボタンが黒く表示されるだけで、押せません。
押せるようにするにはどうしたらいいのでしょうか。
OnTimer()を使っているのですが、それが原因なのでしょうか。

A 回答 (4件)

こんにちは。

itohhといいます。

裏で動いているのは、サーバ通信になる予定なのですね。

わたしの勘違いでした、モーダレス・ダイアログでは、ちょっと対応できない
と思います。

なぜかというと、
モーダレス・ダイアログを使った場合、ダイアログボックスを呼び出す側で
ループによって、ダイアログボックスでボタンが押されたかを監視するのと
裏の処理を行うのを交互に行います。
この場合、裏の処理は、ある程度、細切れに処理を行います。
(例えば、10個のファイルをコピーするとき、1個コピーするたびに
ダイアログボックスのボタンが押下されたかをチェックします。)

今回の場合、サーバ通信は一定時間(Sleep関数のように)制御が
戻ってこないのですよね、同一スレッドでは、どうしてもサーバ通信を
呼び出したところで止まってしまいます。
(実際は、サーバ通信内で動いていますが)
このままだと、ダイアログボックスのボタンが押下することは出来ません。

対策としては、
1.toysmithさんが回答しているように、別スレッドにする。
2.サーバ通信内でたまに制御を戻すようにする。
です。

別スレッドにするメリットですが、中止するためのダイアログボックスと
実際の処理(裏で動いている)を完全に分離できるため制御が
シンプルになります。

対策2で行った場合、スレッドの制御はなくなりますが、
サーバ通信を一定間隔で呼び出し元に制御を戻さなくてはいけないため、
サーバ通信のロジックが難しくなります。

残念ながら、わたしの勘違いです、ごめんなさい。(モーダレス・ダイアログを使うこと)
王道は、対策1がベストだと思います。
    • good
    • 0
この回答へのお礼

早速試してみたのですが、(モーダレスの場合)
うまくいかなかったので、今、「別スレッドで立ち上げる」に挑戦中です。
回答ありがとうございました。

お礼日時:2001/07/02 14:48

「OnTimer()を使っている」というと…


・ダイアログでキャンセルボタン表示
・OnTimer()で呼び出される関数で別の処理を行っている
という状況でしょうか?

この状況ならボタンは有効に動作するはずです(経験済み)。

より、実際的には
1.モーダルダイアログボックスでキャンセルボタンを表示
2.別スレッドで“裏”の処理を行う
3.キャンセルされたら“裏”処理のスレッド殺す
という手順の方が確実に動作します。

この回答への補足

上記の通りです。
OnTimer()内で呼び出される関数が同クラス内にあっても、上記のように動くのでしょうか。
スレッドの使い方がわからないのと、時間がないことで、
スレッドを使わずに作りたいのですが、
補足などありましたらお願いします。

補足日時:2001/07/02 11:46
    • good
    • 0
この回答へのお礼

別スレッドで裏の処理を行うようにしました。
結構、難しいでしたが、なんとか動くようになりました。
ありがとうございました。

お礼日時:2001/07/02 18:30

こんにちは。

itohhといいます。

ちょっと、状況があいまいなので。
1.裏で処理を行っている。(Sleep関数、なんのために??)
2.裏で行っている処理を途中で中断できるようにキャンセルボタン付きの
  ダイアログボックスを表示している。
3.ダイアログボックスのキャンセルボタンが押下できない。
4.裏で処理といっても別プロセス、別スレッドではない。
5.ダイアログボックスを表示したあと、裏の処理が動き出す。
  (OnInitDialog関数内で実行している)
6.MS VC++である。

状況は、これでよいでしょうか?違っていたら、補足願います。
とりあえず、これだと解釈して回答します。

ダイアログボックスの作成方法はどうしていますか?
CDialogクラスのDoModal関数を使っている場合、裏で処理を行っていると
ダイアログボックスの動きは止まりますよ。

基本は、モーダレスでダイアログボックスを作成してください。
そして、キャンセルボタンが押下されたら、裏の処理を中断するように
プログラムを作成してください。

モーダル・ダイアログボックス:CDialogクラスのDoModal関数
モーダレス・ダイアログボックス:CDialogクラスのCreate関数

この回答への補足

ありがとうございます。
Sleep関数の部分は本来ならば、サーバと通信の部分ですが、ダミーでSleepを使っているだけです。

他の部分はおっしゃる通りの状況です。
Create関数を使ってみたいと思うのですが、使い方がいまいちわかりません。
詳しく教えていただけませんでしょうか。

補足日時:2001/07/02 11:32
    • good
    • 1

言語はCですか?C++ですか?それともVC++?



VC++ならSleepExという関数があるのは知っていますが
C++とかCとかだったらどうだったかな?
#ご存じの方、フォローよろしく。

ではでは☆
    • good
    • 0
この回答へのお礼

VC++でした。
回答ありがとうございました。

お礼日時:2001/07/02 11:46

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q「キャンセル」ボタン付きの処理中ダイアログ

Windowsアプリで、ある時間のかかる処理を
キャンセルボタン付処理中ダイアログを表示し、途中で処理をキャンセル可能にしたいと考えています。

ここの過去ログから上記はマルチスレッドにする必要があると拝見しました。http://oshiete1.goo.ne.jp/kotaeru.php3?q=96951

<メイン画面の開始ボタン処理> ------------------
void C_SampleDlg::OnStart(){
 CWinThread *cwt;
 C_CancelDlg dlgCancel(this);
 cwt = AfxBeginThread(Sample_Proc, &InputParams);
 cwt->m_bAutoDelete = FALSE;
 cwt->ResumeThread();
 EnableWindow(FALSE);
 dlgCancel.Create();
 dlgCancel.ShowWindow(SW_SHOW);
 while(TRUE){
  if(dlgCancel.CheckCancel() == TRUE){
   // キャンセルが押された時
   EnableWindow(TRUE);
   dRcd = WaitForSingleObject(cwt->m_hThread, INFINITE);
   if(dRcd == WAIT_OBJECT_0)
    return;
  }
  dRcd = WaitForSingleObject(cwt->m_hThread, 0);
  if(dRcd == WAIT_OBJECT_0){
   dlgCancel.DestroyWindow();
   EnableWindow(TRUE);
   break;
  }
 }
 return;
}

<プロシージャ> ----------------------------------
UINT Sample_Proc(LPVOID pParam){
 C_SampleDlg->やりたい処理関数呼び出し
 ::AfxEndThread(0);
 return 0;
}

以降別ソース ==================================
<C_SampleDlg::やりたい処理関数>

↑ここでdlgCancel.CheckCancel() == TRUEかどうか
判定したい場合、グローバル関数を使うか、または呼出し元で作成したインスタンスをパラメタとして渡して使うべきなのでしょうか。文字数の関係で分かりにくいところもありますが、よろしくお願いします。
※dlgCancel.CheckCancel()はC_CancelDlgクラスのプロテクト変数を内部で操作しています。

Windowsアプリで、ある時間のかかる処理を
キャンセルボタン付処理中ダイアログを表示し、途中で処理をキャンセル可能にしたいと考えています。

ここの過去ログから上記はマルチスレッドにする必要があると拝見しました。http://oshiete1.goo.ne.jp/kotaeru.php3?q=96951

<メイン画面の開始ボタン処理> ------------------
void C_SampleDlg::OnStart(){
 CWinThread *cwt;
 C_CancelDlg dlgCancel(this);
 cwt = AfxBeginThread(Sample_Proc, &InputParams);
 cwt->m_bAutoDelete = FALSE;
 cw...続きを読む

Aベストアンサー

時間のかかる処理というのがループして実行するようなタイプの処理だと、マルチスレッド使わなくても以下のような方法で簡単にできます。時間のかかる処理の中で、キャンセルボタンは普通押せません。それは1メッセージの処理の中で長~い処理を行っているからです。それならば、メッセージ処理中にも別のメッセージを処理できる仕組みを作ってやればいいのです。

○ Before
for(int loop=0; loop < 1000000; loop ++) {
 // ここで時間のかかる処理実行
}

この場合だとループがすべて終了するまで待たされます。


○ After
for(int loop=0; loop < 1000000; loop ++) {

 // ここで時間のかかる処理

 MSG msg;
 while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
 if(!AfxGetApp()->PumpMessage())
 {
  ::PostQuitMessage(0);
  break;
 }
}

ループ1回に付きメッセージ処理を行うため、処理中であっても例えば中断ボタン操作などが普通に処理できます。

時間のかかる処理というのがループして実行するようなタイプの処理だと、マルチスレッド使わなくても以下のような方法で簡単にできます。時間のかかる処理の中で、キャンセルボタンは普通押せません。それは1メッセージの処理の中で長~い処理を行っているからです。それならば、メッセージ処理中にも別のメッセージを処理できる仕組みを作ってやればいいのです。

○ Before
for(int loop=0; loop < 1000000; loop ++) {
 // ここで時間のかかる処理実行
}

この場合だとループがすべて終了するまで待た...続きを読む

QOnTimer()時にクリックされたことを知るには?

環境 WIN98 VC++6.0 MFC にて

OnTimer()時にクリックされたことを知るにはどうすれば良いですか?


void CAbcdView::OnTimer(UINT nIDEvent)
{
KillTimer( 1 );
if ( どのように記述すれば良いですか?) //左クリックされたことを知りたい
MessageBox( "クリックされました。", "左", MB_OK );
CView::OnTimer(nIDEvent);
}

Aベストアンサー

>OnTimer()時には簡単にメッセージが受け取れないのですね。

というか、OnTimerも、WM_TIMERというメッセージのハンドラです。

メッセージ処理の間には、他のメッセージは通常受け取れません。

メッセージキューの中に該当のメッセージが存在するかどうかを調べるのがPeekMessageになります。

なので、実は最初に上げられたソースのように、中身の
処理がほとんどないような状態だとPeekMessageでは
取れないと思ってください。
OnTimerがすぐに終了してしまいますから。
なので、#2の方のフラグを使う方法になります。


PeekMessage自体の使い方としては、メッセージキューに該当メッセージの有無のチェックです。

MSG msg;
PeekMessage( &msg, *this, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE);

みたいにすれば、WM_LBUTTONDOWNがメッセージキューにあるかどうかを確認できます。

>OnTimer()時には簡単にメッセージが受け取れないのですね。

というか、OnTimerも、WM_TIMERというメッセージのハンドラです。

メッセージ処理の間には、他のメッセージは通常受け取れません。

メッセージキューの中に該当のメッセージが存在するかどうかを調べるのがPeekMessageになります。

なので、実は最初に上げられたソースのように、中身の
処理がほとんどないような状態だとPeekMessageでは
取れないと思ってください。
OnTimerがすぐに終了してしまいますから。
なので、#2の方のフラグ...続きを読む

Q[OK]/[キャンセル]ボタンがついたダイアログの作り方。

すごく基本的なことですが、[OK]/[キャンセル]ボタンがついたダイアログで、ドキュメントとビューでのデータのやり取りが自信がないので教えてください。

たとえば、顧客データベースのアプリケーションがあって、ある顧客のデータを修正するためのダイアログを考えます。(顧客リストから顧客Aを選択して、編集ボタンを押すと、その修正のためのダイアログがでるとします。)

この手のダイアログにはよく[OK][キャンセル]ボタンがついていますよね。
私が考えた方法は以下のとおりです。

まず、顧客Aのデータ(Documentオブジェクト)としては

(1)データベースの中にある「顧客Aのデータ」(本データ)
(2)ダイアログで編集中の「顧客Aのデータ」(一時データ)

の2つを用意します。そして、

・ダイアログ(Viewオブジェクト)を起動するとき、(1)をコピーして(2)を作ります。
・ダイアログで編集するのは(2)です。
・ダイアログで [OK]を押すと(2)を(1)にコピーします。
・[キャンセル]を押すと、単に(2)を破棄して終わりです。

このように、[OK]/[キャンセル]ボタンがついた編集ダイアログなどでは、2つ同じデータのオブジェクトを作るものなのでしょうか。他に方法が思いつきません。

すごく基本的なことですが、[OK]/[キャンセル]ボタンがついたダイアログで、ドキュメントとビューでのデータのやり取りが自信がないので教えてください。

たとえば、顧客データベースのアプリケーションがあって、ある顧客のデータを修正するためのダイアログを考えます。(顧客リストから顧客Aを選択して、編集ボタンを押すと、その修正のためのダイアログがでるとします。)

この手のダイアログにはよく[OK][キャンセル]ボタンがついていますよね。
私が考えた方法は以下のとおりです。

まず、顧客...続きを読む

Aベストアンサー

もし、
(1)データベースの中にある「顧客Aのデータ」(本データ)
(2)ダイアログで編集中の「顧客Aのデータ」(一時データ)
がどちらもリストであれば、ダイアログを表示する時に、(1)のリストをダイアログに貼り付ける(親ウインドウをダイアログにする)と、(2)が必要なくなります。

Qダイアログにあるボタンを指定した順番どおりに、キーボードの矢印ボタンやタブボタンで移動したい

お世話になります。

C++6.0 MFCで開発しております。

現在、ダイアログの上に(1)~(5)のボタンがあるのですが、
キーボードの矢印ボタンやタブボタンで移動すると
(2)→(1)→(5)→(4)→(3)
のように、意図しない順番でボタンがアクティブになってしまいます。
それをきちんと
(1)→(2)→(3)→(4)→(5)
と順番どおりに移動するようにしたいのですが、どのようにすれば
いいのでしょうか?

お手数ですが何卒よろしくお願いします。

Aベストアンサー

VC6の場合 ダイアログエディタを起動して
Ctrl+Dまたはメニューから レイアウト > タブオーダーを実行します

コントロールの左肩に現在のタブ順が表示されるので
1番から順に指定したいコントロールをクリックしてみましょう
その後実行ファイルの更新(ビルドまたはリビルド)実行すれば
希望通りのタブ順になっているはずですよ ・・・

QC(C++) コントロール(ボタン)の制御 ボタン1押したらボタン2が使用不可に・・・その逆も。。。

はじめまして。

回りに聞ける人がいなくて困ってます。

C(C++)でフォームにボタンを設置し、任意のボタンを押したら、他のボタンが押せなくなるように、
もう1回押したら、他のボタンが押せるように戻るっていう感じの制御をしたいのですが、書き方が分かりません。

分かる方、記述例をつけて教えて頂けると助かります。お願いします。

Aベストアンサー

こんんちは

ボタン1を押したらボタン2の有効/無効を最クリックに切り替えると言ううことでよね?
ボタン1が押されたときのハンドラのみ記述します。
参考にしてみてください。

有効=ボタンが押せる状態
無効=ボタンが押せない状態

void CMyDlg::OnButton1()
{
CButton*pBtn = (CButton*)GetDlgItem(IDC_BUTTON2);

// ボタン2が有効か無効かをチェック
if( pBtn->IsWindowEnabled() ){
// 有効なら無効にする
pBtn->EnableWindow(FALSE);
} else {
// 無効なら有効にする
pBtn->EnableWindow(TRUE);
}

}


人気Q&Aランキング

おすすめ情報