dポイントプレゼントキャンペーン実施中!

<プログラム環境>
Windows XP
VC++6.0
MFC AppWizard(exe)
ダイアログベース

<目的>
1.ダイアログにボタン1を配置する
2.処理A(無限ループ)を開始する
3.処理Aの先頭でボタン1が押されたか判断する
4.ボタン1が押された場合処理Aを終了し、処理Bを行う
というプログラムを作成する。

<質問>
目的のプログラムを作成するには、ボタン1が押された事を検知する
必要があると思うのですが、その方法が分かりません。
ボタンが押された事を検知するにはどうしたら良いのでしょうか?

宜しければご指摘お願い致します。

A 回答 (6件)

> while(i != 1){//無限ループ


の次の行あたりに メッセージポンプを挿入してみましょう
    • good
    • 1
この回答へのお礼

redfox63様
有難うございます。

ご指摘頂いた通りにコーディングすると、目的の処理ができました!

まだ何をコーディングしたのか、よく理解できていませんが、
ネットや本で勉強して理解します。
有難うございました。

お礼日時:2008/06/19 12:50

> ボタン2を押して無限ループを実行している最中にダイアログの


> ボタン1を押すと、砂時計のアイコンが出て、フリーズしました。
当然でしょう

ループで待っている部分にメッセージポンプが無いからです
WaitForSingleObjectの返り値が時間切れの場合に
MSG msg;
while( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) {
  AfxGetApp()->PumpMessage();
}

といった具合でメッセージポンプを組みましょう

MFCアプリで CreateThradなど使うのは避けたほうがいいようです
MFCでマルチスレッドをしたいなら CWinThreadクラスを使いましょう

この回答への補足

redfox63様、有難うございます。

ご指摘頂いた通りに、コーディングしたのですが、
症状に変化はありませんでした・・。

データをPCに送信する機器の故障が無い限り、
データは延々と連続して送られてくるので、
WaitForSingleObjectの戻り値はWAIT_OBJECT_0になります。
もしくは、ReadFileの戻り値が0以外となって、受信成功です。
(この場合はWaitForSingleObjectは実行されない)

WaitForSingleObjectの戻り値が時間切れになる事は、まず無いので、
MSG msg;
while( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) {
  AfxGetApp()->PumpMessage();
}
という処理には入らないと思います。

シングルスレッドでは不可能なのでしょうか?

宜しければ、ご指摘お願い致します。

補足日時:2008/06/18 11:16
    • good
    • 0

うーん、申し訳ありません。

チョッと判りませんが、こんな感じ?

//グローバルハンドル
static HANDLE g_hEvent = 0;

//スレッド関数
DWORD WINAPI ThreadProcA(void* p)
{
HANDLE hCom;//COMポートのハンドル
unsigned char Buf[4];//受信バッファ
DWORD dwOldTime = ::timeGetTime();

for( ; ; )
{
//一秒経過
if(::timeGetTime() - dwOldTime > 1000)
{
dwOldTime = 0;
return;
}

if(::ReadFile(hCom,Buf,1,NULL,&old) == 0)
{
return;
}
}
}

void ボタン1関数()
{
//スレッドは既に停止していた
if(g_hEvent == 0)return;

//スレッドの停止
::CloseHandle(g_hEvent);
g_hEvent = 0;

//B処理
}

void 起点()
{
DWORD dw;
g_hEvent = ::CreateThread(NULL, 0, &::ThreadProcA, NULL, 0, &dw);
}

この回答への補足

machongola様、有難うございます。

スレッド関数を使った事が無いので良く理解できていないのですが、
void 起点()
というのが、ボタン2関数の事ですよね?

g_hEvent = ::CreateThread(NULL, 0, &::ThreadProcA, NULL, 0, &dw);
というコードで、スレッド関数が実行されるということですか?

スレッド関数のコードでは
1秒経過すると受信が終わってしまうのではないでしょうか?

延々と受信を行い、任意にボタン1を押して、そのタイミングで
受信を止めたいと考えております。

if(::ReadFile(hCom,Buf,1,NULL,&old) == 0)
{
return;
}
というのは、受信が失敗した場合にスレッドを終了する、という
事ですよね?
データがPCに送られてくるのが遅れて、
少し(数ms)待たないと受信完了しない場合があるので、
ReadFileの戻り値が0の場合でも、WaitForSingleObjectなどで
受信完了まで少し待った方がいいと思うのですが、いかがでしょうか?

宜しければご指摘お願い致します。

補足日時:2008/06/17 16:24
    • good
    • 0

挙げられたソースだけではなんとも判断できませんが、



・処理Bは無限ループ?それともAに戻ってくる?
 Aに戻ってこないなら、Bの中でもイベント処理をしないと応答無しになってしまいます。

・Flagは0に戻してますか?
 無限ループ処理内で Flag==1であることを関知したら、Flag=0に戻しましょう。
 そうしないと、一度クリックしたら、いつまでもクリック時の処理を行うことになっていしまいます。

この回答への補足

mtaka2様、有難うございます。

ソースが未完全で申し訳ありませんでした。
処理Bは
Flag = 0;
break;
です。
よってAには戻りません。
Bの中でもイベント処理をする必要があるとの事ですが、
どのようにコーディングしてイベント処理をするのでしょうか?

宜しければご指摘お願い致します。

補足日時:2008/06/17 15:42
    • good
    • 0

マルチスレッドにして、通常のメッセージループと無限ループ処理を別スレッドにするのがいいと思います。



あとは、「ボタン1がクリックされたかどうか」を表す変数を用意しておいて、
ボタン1のクリックイベントで変数に代入
無限ループ処理内では、その変数の内容チェック
を行えばいいでしょう。

あるいは、シングルスレッドでも、
無限ループ内でメッセージ処理してもいいでしょう。
http://msdn.microsoft.com/ja-jp/library/3dy7kd92 …
シングルスレッド方式の場合、無限ループ処理内で定期的にメッセージ処理を行う必要があります。
変数を介してクリック情報を取得するのは同じ。

この回答への補足

mtaka2様、有難うございます。

マルチスレッドの知識がまだ無いので、シングルスレッド方式で
メッセージ処理するようにコーディングしました。

ボタン2を押すと無限ループの処理(ボタン2関数)に入ります。

ボタン2関数では延々とデータを受信するように
なっています。(簡略に記述してます)

BYTE Flag = 0;//グローバル変数

ボタン2関数(){
HANDLE hCom;//COMポートのハンドル
unsigned char Buf[4];//受信バッファ
OVERLAPPED old;//オーバーラップ構造体
int i =0;
old.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
while(i != 1){//無限ループ
if(Flag == 1)処理B;
if(ReadFile(hCom,Buf,1,NULL,&old) == 0){
if(WaitForSingleObject(old.hEvent,1000) == WAIT_TIMEOUT){
return;
} } } }

ボタン1関数(){
Flag = 1;
}

ボタン2を押して無限ループを実行している最中にダイアログの
ボタン1を押すと、砂時計のアイコンが出て、フリーズしました。

なぜでしょうか?

宜しければご指摘お願い致します。

補足日時:2008/06/17 14:31
    • good
    • 0

Windowsプログラミングするのであれば 無限ループによる処理は避けましょう



待ちを期待する処理ならWaitForSingleObjectなど使ってメッセージポンプを止めないような処理が必要です

無限ループなどの処理をした場合 コントロールで起きたイベントは
独自のメッセージポンプを実装しない限り 永遠に取得できません

ボタンが押された場合は BN_CLICKEDメッセージを処理するようにします
ダイアログエディタで ボタンをダブルクリックすればイベントハンドラを作成してくれます

この回答への補足

redfox63様、有難うございます。

無限ループはご指摘頂いた通りWaitForSingleObjectを使っています。
非同期でCOMポートからデータ受信を行い、1秒でタイムアウトする
設定です。タイムアウトしない限り延々とデータを受信します。

ダイアログエディタでイベントハンドラを作成すると、
Onから始まる名前の関数が作成されますが、
この関数では何も処理を行わないつもりです。
BN_CLICKEDメッセージを処理したいのですが、どのようにコーディング
するのでしょうか?
if(BN_CLICKED == TRUE){
処理
}
という感じでしょうか?

また、BN_CLICKEDだけでは、どのボタンが押されたか分からないのでは
ないでしょうか?

宜しければご指摘お願い致します。

補足日時:2008/06/17 13:34
    • good
    • 0

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

このQ&Aを見た人はこんなQ&Aも見ています