• ベストアンサー

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

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

質問者が選んだベストアンサー

  • ベストアンサー
  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.3

>OnTimer()時には簡単にメッセージが受け取れないのですね。 というか、OnTimerも、WM_TIMERというメッセージのハンドラです。 メッセージ処理の間には、他のメッセージは通常受け取れません。 メッセージキューの中に該当のメッセージが存在するかどうかを調べるのがPeekMessageになります。 なので、実は最初に上げられたソースのように、中身の 処理がほとんどないような状態だとPeekMessageでは 取れないと思ってください。 OnTimerがすぐに終了してしまいますから。 なので、#2の方のフラグを使う方法になります。 PeekMessage自体の使い方としては、メッセージキューに該当メッセージの有無のチェックです。 MSG msg; PeekMessage( &msg, *this, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE ); みたいにすれば、WM_LBUTTONDOWNがメッセージキューにあるかどうかを確認できます。

VitaminBB
質問者

お礼

回答ありがとうございます。 SDKでダブルクリックとシングルクリックを区別する方法として、質問のようなコードがあったのが質問のきっかけです。 http://www.hidecnet.ne.jp/~sinzan/tips/win/win_tip1d.htm 思っていたより難しかったので、今回はPeekMessage関数というものの存在を知るに留めたいと思います。 whileでの長い時間がかかる処理中にメッセージを受け取るために使ったりするようですね。 #3の関数の使い方は、1例として大変良く分かりました。

その他の回答 (4)

  • BILLY-J
  • ベストアンサー率57% (60/105)
回答No.5

こんにちは。 なるほど、1回目のクリックから一定時間内に2回目のクリックが 来たら「ダブルクリック」として扱うという事ですね。 最近GUI周りのコード書いてないので実装思い出せないのですが、 WM_LBUTTONDBLCLK でハンドリングするのではダメなのでしょうか。 その部分を自作したいという意図で有れば的はずれですね…

VitaminBB
質問者

お礼

回答ありがとうございます。 今回は特に緊急の必要性がないので今後の参考にさせて頂きます。

  • BILLY-J
  • ベストアンサー率57% (60/105)
回答No.4

こんばんは。 #3さんが仰るように PeekMessage を使う方法だと、OnTimer を 処理している僅かなタイミングの間にキューに溜まったメッセージ、 或いは大量にメッセージが発生した状態でキューが渋滞し、偶然に WM_TIMER より後に積まれていたクリックしか検知できません。 私が挙げた方法だと、OnTimer が来るまでの間に処理された物に なり、どちらの時系列が欲しいのかによってロジックも変わって くると思います。 例えばタイマーを2周回す構造にして、1周目~2周目間で発生した クリックかどうかを2周目の OnTimer でチェックする、または1周目 の OnTimer でフラグを立て2周目 OnTimer ではフラグリセット、 OnClick 側で1周目のフラグをチェックして処理分岐… とすれば、2周目で処理するメッセージは過去のメッセージですが 1周目から見れば未来のクリックを処理する訳で…って詭弁ですね。 しかも結局フラグ制御だなぁ(苦笑) フラグ制御以外となると、少々強引ですが、一定間隔でループする スレッドを作りタイマーに見立てるのは如何? CWinThread で作ればメッセージキューを持っているので、OnClick でスレッドに対して PostThreadMessage すれば似たような動きを 実装できるかも知れません。

VitaminBB
質問者

お礼

回答有難うございます。 #3のお礼欄に書いたことが今回の質問のきっかけです。 元々そう難しくないと思って質問しましたが、私にとっては思ったより厄介でした。

  • BILLY-J
  • ベストアンサー率57% (60/105)
回答No.2

タイマー周期の間に、クリックが発生したか、と言う事でしょうか? でしたら OnClick でフラグを立てておくようにし、OnTimer で そのフラグをチェック&クリア、という方法はどうでしょう。

VitaminBB
質問者

お礼

回答ありがとうございます。 フラグの方法に付いては問題無く出来ました。 今回は、フラグを使わないで実現する方法が知りたくて質問しました。 でも、私が思っていたより面倒そうですね。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1
VitaminBB
質問者

お礼

回答有難うございます。 OnTimer()時には簡単にメッセージが受け取れないのですね。 そんなことも知らずに質問してしまいました。 PeekMessage()について調べましたが、いつものように良く分かりませんでした。 とりあえず、すぐに知りたい訳ではないのでおいおい調べていきます。

関連するQ&A

  • OnTimerの使い方

    <環境> WIN98 VC++6.0 MFC  こんな感じで3秒経過するとメッセージボックスを表示していますが、 メッセージボックスのOKボタンを何度も押さないとメッセージボックスが 閉じない時が有ります。 (どうやらメッセージボックスが何個も作られている) どうしてなのでしょうか? BOOL CAbcDlg::OnInitDialog() { // TODO: 特別な初期化を行う時はこの場所に追加してください。 SetTimer(1, 1000, NULL); m_cnttime = 0; 略 void CAbcDlg::OnTimer(UINT nIDEvent) { m_cnttime++; if ( m_cnttime >= 3 ) { AfxMessageBox(""); KillTimer(nIDEvent); } CDialog::OnTimer(nIDEvent); }

  • VC++のOnTimer()について

    超初歩的な話でお恥ずかしいのですが、 VC++6.0 MFC でアプリを作っていて、 //////////////// xxx::OnInitialUpdate(...) { m_nIDEntry = SetTimer(m_nIDEvent); } /////////////// xxx:OnTimer(UINT nIDEvent) { if (nIDEvent == ?) { なんかの処理 } } /////////////// xxx:OnDestroy(...) { KillTimer(?); } /////////////// このようなコードの際に、if (nIDEvent == ?) には SetTimer() の値を入れますが、? は 上で言うところの m_nIDEvent それとも m_nIDEntry を入れます? KillTimer() の ? も同様にです。 MSDN ライブラリを見ると ? は m_nIDEvent が入るように 読み取れます(今までもずーとそのようにしています)。 これが正しければ SetTimer() の戻値って何の意味が 有るのかが不明です。

  • if文の判定について

    <環境> WIN98 VC++6.0 MFC  ダイアログベースにて 以下コードにて、タイマーによる変数nの変化に伴い絵1と絵2が切り替わっています。 int n; void CxxxDlg::OnPaint() { 略 m_p9[0].LoadBitmap(IDB_BITMAP1); m_p9[1].LoadBitmap(IDB_BITMAP2); tempDC9.SelectObject(&m_p9[n]); 略 } void CxxxDlg::OnTimer(UINT nIDEvent) { n=n+1; if(n>=2){ n=0; } Invalidate();   CDialog::OnTimer(nIDEvent); } ところがコードの一部を以下のように変更すると、 if文で正しく判定できなくなります。 どうしてなのでしょうか? if (n=0){ m_p9[0].LoadBitmap(IDB_BITMAP1); } m_p9[1].LoadBitmap(IDB_BITMAP2);

  • 左ボタンアップを作動するようにするには

    環境 VC++6.0 MFC 久々にさわってほとんど忘れてしまってるので、 教えて下さい。 タイトルバー無しのウィンドウを動かせるように、左ボタンダウン時に以下のように、PostMessageを追加しました。 そうすると、左ボタンアップが動かなくなったのですが、どうすれば動くようになるのですか? void CABCView::OnLButtonDown(UINT nFlags, CPoint point) { PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y)); CView::OnLButtonDown(nFlags, point); } void CABCView::OnLButtonUp(UINT nFlags, CPoint point) { AfxMessageBox("9"); CView::OnLButtonUp(nFlags, point); }

  • MFC Timerについて

    MFCのTimerの利用方法をいろいろ調べたのですが。 理解できずに困っています。 MFCのダイアログベースで作成し、ボタンを押したら Timer(1秒ごと)でエディットボックスに表示させるというものです。 ・ベースのウィンドウにボタンとエディットボックスを作成しました。 ・次に ボタンをダブルクリックし以下のように書きました。 void CtestDlg::OnBnClickedButton() {     int x=0; char buf[10000]; x++; sprintf(buf,"%d",x); (labelの変数名)_edit.SetWindowText(buf); } ・SetTimer(1, 1000, NULL);を用いて ボタンがクリックされたら1秒ごとにxの値をエディットボックスに表示させるようにしたいのですが。 OnTimer(UINT nIDEvent) Close()やKillTimer(1);をもちいらなければならないことはわかったのですが。 作業手順がわかりません。 詳しい 作業手順をおしえてください。 プログラム完成まで 教えていただけるととてもうれしいです。 プログラマーの方よろしくお願いします。

  • [MFC] SetTimer関数の扱い方について

    [MFC] SetTimer関数の扱い方について MFCを扱い始めた初心者です。Settimerを用いて1秒間隔でOnTimer関数を呼び出そうと思い試行錯誤していたのですが、どのように記述してよいのかを教えてください。 実装したい機能は、ボタン1によりタイマを開始し、OnTimer関数を1秒間隔で呼び出し、ボタン2によりその動作を停止させたいのです。以下のコードを記述しますので、ご説明をよろしくお願いします。 NForm(){  btnの定義; btn2の定義; Picutureboxのpboxの定義; } int __stdcall WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { Application::Run(new NForm()); return 0; } void NForm::btn_Click(Object *sender, System::EventArgs *e) { if(sender->Equals(btn)){ setTimer(1, 1000, NULL); } else if(sender->Equals(btn2)){ setTimer(1, 1000, NULL); } } void NForm::onTimer(UINT nIDEvent) { if(nIDEvent == 1){ HDC hDC; hDC = GetDC(NULL);//Full screen capture HDC hMemDC = CreateCompatibleDC(hDC); RECT r; SIZE size; size.cx = GetSystemMetrics(SM_CXSCREEN); size.cy = GetSystemMetrics(SM_CYSCREEN); HBITMAP hBitmap = CreateCompatibleBitmap(hDC, size.cx, size.cy); if (hBitmap) { HBITMAP hOld = (HBITMAP) SelectObject(hMemDC, hBitmap); BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, SRCCOPY); SelectObject(hMemDC, hOld); DeleteDC(hMemDC); ReleaseDC(NULL, hDC); pbox->Image = Image::FromHbitmap(hBitmap); DeleteObject(hBitmap); } capture_cnt++; char name[80]; sprintf(name, "capture_%d.jpg", capture_cnt); pbox->Image->Save(name,Drawing::Imaging::ImageFormat::Jpeg); NForm::onTimer(1); } else if(nIDEvent == 0){ NForm::onTimer(0); } } 上記のコードにおいて、Ontimer関数を単体で動作させた場合はきちんと動作します。 どうか、よろしくお願いします。

  • MFCプログラミング

    MFCのダブルバッファリングを用いて画面を切り替えるプログラムを作ったのですが 画面がちらついてしまいます、どう修正すればよいか教えてください // CgraphView 描画 void CgraphView::OnDraw(CDC* pDC) { CgraphDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: この場所にネイティブ データ用の描画コードを追加します。 CRect myRect; GetClientRect(myRect); if(background_color == 0) pDC->FillSolidRect(myRect, RGB(255, 255, 255)); else if(background_color == 1) pDC->FillSolidRect(myRect, RGB(153, 204, 255)); else pDC->FillSolidRect(myRect, RGB(255, 153, 204)); //ダブルバッファに関するコード CRect rc; GetClientRect(&rc); bkDC.CreateCompatibleDC(pDC); bkBMP.CreateCompatibleBitmap(pDC, rc.right, rc.bottom); CBitmap Bitmap, *pOldBitmap; pOldBitmap = bkDC.SelectObject(&bkBMP); //これから、すべての描画は、裏画面bkDCにおいて行う bkDC.FillSolidRect(rc, RGB(255, 255, 255)); int x, y, sx, sy; if(draw_state == 0) { bkDC.SetTextColor(RGB(0, 0, 0)); bkDC.TextOut(400, 500, _T("Start")); sx = 128;//表示するビットマップの横の大きさ sy = 128;//表示するビットマップの縦の大きさ y = 300;//表示するビットマップの左上の頂点のy座標 x = 50; draw_school(x, y, sx, sy); x = 200; draw_health(x, y, sx, sy); x = 350; draw_environment(x, y, sx, sy); } else if(draw_state == 1) { CRect myRect; GetClientRect(myRect); pDC->FillSolidRect(myRect, RGB(255, 255, 255)); } //裏画面bkDCにおいて、すべての描画を行った後 //裏画面を表画面に送る pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); bkDC.SelectObject(pOldBitmap); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC(); void CgraphView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。 bitmap[0].LoadBitmap(IDB_BITMAP1); bitmap[1].LoadBitmap(IDB_BITMAP2); bitmap[2].LoadBitmap(IDB_BITMAP3); bitmap[3].LoadBitmap(IDB_BITMAP4); bitmap[4].LoadBitmap(IDB_BITMAP5); bitmap[5].LoadBitmap(IDB_BITMAP6); Bmp_ID = 0; //タイマーをスタート SetTimer(ID_BITMAP, TIMER_MS_BITMAP, NULL); //画面再描画のタイマーをスタートする SetTimer(ID_REDRAW, TIMER_MS_FPS, NULL); Bmp_ID = 0; } void CgraphView::OnTimer(UINT_PTR nIDEvent) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 if(nIDEvent == ID_BITMAP) Bmp_ID = (Bmp_ID+1) % 2; if(nIDEvent == ID_REDRAW) InvalidateRect(NULL, FALSE); CView::OnTimer(nIDEvent); } void CgraphView::OnDestroy() { CView::OnDestroy(); // TODO: ここにメッセージ ハンドラ コードを追加します。 KillTimer(ID_BITMAP); KillTimer(ID_REDRAW); } void CgraphView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 mouse_x = point.x; mouse_y = point.y; if(draw_state == 0) { if(mouse_x > 400 && mouse_y > 500) { draw_state = 1; } } CView::OnLButtonDown(nFlags, point); } BOOL CgraphView::OnEraseBkgnd(CDC* pDC) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 return TRUE; //return CView::OnEraseBkgnd(pDC); }

  • TimerProc コールバック関数を利用する方法

    タイマを使いたくてメッセージマップでOnTimerを追加しましたが、 CWnd::SetTimerの第3パラメタに何を設定したらよいかわかりません。 lpfnTimer WM_TIMER メッセージを処理するためのアプリケーションが用意した、 TimerProc コールバック関数のアドレスを指定します。 このパラメータが NULL の場合は、WM_TIMER メッセージはアプリケーションの メッセージ キューに置かれ、CWnd オブジェクトによって処理されます。 とあり、NULL指定のサンプルはあるのですが、 「TimerProcコールバック関数のアドレスを指定する法」を試したいのです。 関数のアドレスというのが何をいっているのか理解できないのですが 試しに void CXXXCtrl::method1() { SetTimer(timerID, 10000, &OnTimer); } void CXXXCtrl::OnTimer(UINT nIDEvent) { // 処理 COleControl::OnTimer(nIDEvent); } としたところ error C2276: '&' : 仮想関数のアドレスを取ろうとしました。 のエラーになってしまいます。

  • SendMessage();の使い方

    よろしくお願いします。 <環境> WIN98 VC++6.0 MFC SDIにてウィンドウをクリックすると、モードレスダイアログ1とモーダルダイア ログ2が開くようにしました。 void CMy222View::OnLButtonDown(UINT nFlags, CPoint point) { CDlg1 *dlg; dlg = new CDlg1; dlg->Create(IDD_DIALOG1); dlg->ShowWindow(SW_SHOW); CDlg2 dlg2; dlg2.DoModal(); CView::OnLButtonDown(nFlags, point); } ダイアログ2のボタン押し下げにてダイアログ1のボタン1を押し下げたいのですが 、どのようにすれば実現できるのでしょうか? void CDlg2::OnButton2() { SendMessage(); //■ここの書き方が分かりません CDialog::OnOK(); } 宜しくお願いいたします。

  • ローカル関数についてお願いします

    VC++プログラムです ボタン1,2は正常に動いたので割愛させていただきます この文をビルドしたらエラーがでました void CparaparaDlg::OnBnClickedButton3(){ { CPaintDC dc (this); CRect sikaku; GetClientRect (sikaku); int n; CBitmap gazou[2]; int CparaparaDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { gazou[0].LoadBitmap(IDB_BITMAP1); gazou[1].LoadBitmap(IDB_BITMAP2); n = 1; SetTimer(1, 200, NULL); return 0; } void CparaparaDlg::OnTimer(UINT nIDEvent) { n = n + 1; if(n >= 3){ n = 1; } Invalidate(); if(n == 1){ OnBnClickedButton1(); } else if (n == 2){ OnBnClickedButton2(); } } } error C2601: 'CWnd::OnCreate' : ローカル関数の定義が正しくありません。 c:\Documents and Settings\mizuno\My Documents\Visual Studio error C2601: 'CWnd::OnTimer' : ローカル関数の定義が正しくありません。 というエラーが出ました・・・ どこをどう手直しすればよいのか教えていただける方、お願いします 関数についても教えていただけると幸いです