• ベストアンサー

初心者です。 ~時間差で再描画~

まだまだ初心者ですが、フリーのBCCを使ってCプログラミングしているものです。 最近、トランプのゲームを作り始めて、時間差で再描画する必要が出たので InvalidateRect(hWnd, NULL, TRUE); Sleep(3000); InvalidateRect(hWnd, NULL, TRUE); と書いたのですが、うまく動作しません。 そこで、 InvalidateRect(hWnd, NULL, TRUE); Sleep(3000); と書いてみると、3秒間のブランクがあった後で、描き直されているようでした。 これはどういうことなのでしょうか。 そして、どうすれば正しく動作させられるのでしょうか。 出来れば、初心者でもわかりやすいような回答お待ちしています。

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

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★Sleep 関数ってのは処理を一時停止させます。 ・よって、InvalidateRect 関数で再描画の信号を送っても Sleep 関数で 3 秒間の  停止状態なので時間差の再描画には上手くなりません。 ・時間差で再描画を行いたいのならばタイマーを使います。  下にそのサンプルです。 サンプル: SetTimer( hWnd, タイマーID, 3000, NULL ); ←再描画させる指定 WM_TIMER:  InvalidateRect( hWnd, NULL, TRUE );  KillTimer( hWnd, タイマーID ); ←タイマー破棄  break; 解説: ・時間差で再描画を行う信号は、SetTimer 関数を実行します。  これで 3 秒後に WM_TIMER より、再描画の信号が発生するため、WM_PAINT で再描画  されます。 ・また、常に 3 秒おきに再描画させたい場合は、WM_TIMER で KillTimer しないで良い。  つまり、ゲームを開始したときに1回だけ SetTimer を実行して一時停止や、ゲームの  終了時に KillTimer でタイマーを破棄すればよい。 ・WM_PAINT でウェイト(Sleep)を入れるのはおかしいです。注意! ・以上。参考に。

参考URL:
http://yokohama.cool.ne.jp/chokuto/advanced/function/SetTimer.html
mumei_
質問者

お礼

成る程、そもそもSleepを使うのがおかしいということですか。 SetTimerですね。 やってみます。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.4

> InvalidateRect(hWnd, NULL, TRUE); > Sleep(3000); > InvalidateRect(hWnd, NULL, TRUE); これでは時間差で再描画されるわけがありません. なぜならば,InvalidateRect は再描画を行うのではなく, 後で再描画が行われるように「予約する」だけだからです. 実際の再描画は,メッセージループから WM_PAINT が ディスパッチされたときの処理として行われます.

mumei_
質問者

お礼

成る程、↑では2回再描画を「予約」しただけですか。 何分初心者なもので、"InvalidateRect = 再描画" としか理解していなかったため、このような間違いをおかしました。 詳しい解説、ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★追記。 >InvalidateRect(hWnd, NULL, TRUE); >Sleep(3000); >InvalidateRect(hWnd, NULL, TRUE); の3行はどこで実行していますか?

mumei_
質問者

補足

↓でも書きましたが、ウィンドウプロシージャ内ではなく、呼び出した自作関数の中です。 説明不足ですみません。

全文を見る
すると、全ての回答が全文表示されます。
  • t_nojiri
  • ベストアンサー率28% (595/2071)
回答No.1

http://www.geocities.jp/ky_webid/win32c/014.html なんだか、自力で描画用プロシジャ内にsleep書くのはおかしいというか、3秒経ったらWM_PAINTメッセージ発生するようにクリッピング領域書き直すと思うんですけどね?

mumei_
質問者

お礼

素早い回答ありがとうございます。 こちらの説明不足でご迷惑おかけしましたが、上のコードを書いた場所は、描画用プロシジャ内ではなく、プロシジャ以外の自作関数の中です。 すみません。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • クライアント領域を再描画させない方法

    クライアント領域で左クリックを押したままマウスを移動させた時の処理 (WM_MOUSMOVE)として、マウスの位置情報を、 InvalidateRect(hWnd, NULL, FALSE); でWM_PAINTに送り、WM_PAINTで描画処理をさせます。 右クリックでの処理として、 case WM_RBUTTONDOWN:    InvalidateRect(NULL, NULL, TRUE);    return 0; とした時、WM_PAINTでは 右クリックによるWM_PAINTでは、クライアント領域を 再描画させない様にしたいのですが、 どのようにしたら良いのでしょうか? クライアント領域に描画されたのを再描画させないことで、 消したいのです。 MS VC++ & Win98 の環境で作成しています。

  • InvalidateRectがうまくいかない

    ボールがあったとしてWM_TIMERによって 一定の速度でy方向に動いていたとします。 ある条件(例えば5回に1度とか)で y方向に行くのを一旦やめて x方向に一定の間隔で5マス移動するとします。 while(aaa() > 0){ x++; Sleep(100); InvalidateRect(hWnd, NULL, TRUE); } このようなプログラムです。 aaa()は5回呼ばれると0を返します。 これでx==0から始まったとすれば x==1,x==2,x==3,・・・・とボールが移動する様子が表示されると 思っていたのですが、 実際には5回Sleep(100)したくらいの時間が経ってから 一気にx==5の位置まで移動して表示されました。 デバッグして追ってみたら while文は5回ループして InvalidateRect(hWnd, NULL, TRUE)もちゃんと 5回行われているようでした。 どういうことなんでしょうか?

  • InvalidateRect Windowsアプリ

    初歩的な質問すみません。 現在、Windowsアプリケーションでプログラミングをしています。 cppファイルを複数使ってプロジェクトを作成したいので、 【下記ソース】のような感じで、ウィンドウハンドルhWnd を グローバル変数hParentに格納し、 他のcppファイルからでもウィンドウハンドルを使った記述ができるようにしたつもりです。 ここからが本題なのですが、 他のcppファイルで hParentを用いてInvalidateRectを使用したところ、 WM_PAINTにメッセージが送られることなく、そのまま処理を続けてしまっています。 他のcppファイルの記述ですが、グローバル変数 HWND hParentを用いて  InvalidateRect(hParent, NULL, FALSE); と書いています。 戻り値には1が入っていたので失敗はしていないようです。 私としては、WM_PAINTにとんで、そこで描画処理をしてほしかったのですが・・・ アドバイスお願いします。 <環境> Microsoft Windows XP Professional Version 2002 Service Pack 3 Microsoft Visual Studio Academic Edition 2005 【下記ソース】 ----------------------------- // グローバル変数 extern HWND hParent // インスタンスハンドルを保存し、メインウィンドウを作成 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // グローバル変数にインスタンス処理を格納します。 hWnd = CreateWindow(szWindowClass, TEXT("練習"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hParent = hWnd; // グローバル変数にウィンドウハンドルを格納 return TRUE; } ----------------------------- ※上記関数のほかにも、こちらのcppファイル(ファイル(1))には、   APIENTRY _TWinMain関数や、CALLBACK WndProc関数などの大元が含まれています。   InvalidateRect関数を使っているのは、他のcppファイル(ファイル(2))ということです。

  • 画面を強制的に再描画させる方法

    MFCでプログラミングをしています。 SDIプログラムで、 メニューを選択すると「ある操作」をするように 作っています。 「ある操作」の中でループを回しており、 各ループ終了毎に更新結果を逐次描画させたいのですが、 うまく行きません。 ループの最後に Invalidate(TRUE) を書いてだめだったので、 pView->SetRedraw(TRUE); pView->RedrawWindow(); pDoc->UpdateAllViews(NULL); なども併用してみたのですが、 通過するだけで何もされません。 どなたかご教示よろしくお願いします。

  • Win32APIにて、簡易タイピングソフトを作成したのですが、うまく実行されません。

    いつもお世話になっております。 小生、只今、WinXPSP3上でC言語とWin32APIを使用し、BCC5.5.1でコンパイルしながらWindowsプログラミングを勉強しています。 今回、質問させて頂きたいのは、「猫でもわかるWindowsプログラミング第2版」の第5章簡易タイピングソフトを作るの回で、掲載されてあったコードを自分なりに改造して、実行してみたのですが、ウィンドウが起動しても、真っ白の状態でタイピングの問題が出題されないようになってしまいました。 以下にコードを掲載致します。 ※文字数制限にひっかかったので、改造した部分だけを掲載させて頂きます。 #include <windows.h> #include <time.h> #pragma comment(lib, "winmm.lib") LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE, LPCSTR); BOOL InitInstance(HINSTANCE, int, LPCSTR); DWORD TypeStart(HWND, char*); //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow, LPCSTR szClassName) { HWND hWnd; hWnd = CreateWindow( szClassName, "EasyTyping", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, hInst, NULL); if(!hWnd){ return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } //ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; MMTIME mm; char szMondai[32] = {0}; char szInput[32] = {0}; char szCheck[32] = {0}; DWORD dwStart, dwEnd; BOOL bStart = FALSE, bSeikai = TRUE; switch(msg){ case WM_CREATE: srand((unsigned)time(NULL)); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 0, 0, szMondai, (int)strlen(szMondai)); TextOut(hdc, 0, 40, szInput, (int)strlen(szInput)); if(bSeikai == TRUE){ SetTextColor(hdc, RGB(0, 0, 0)); } else{ SetTextColor(hdc, RGB(255, 0, 0)); } TextOut(hdc, 0, 80, szCheck, (int)strlen(szCheck)); EndPaint(hWnd, &ps); break; case WM_CHAR: if(wp == VK_SPACE && !bStart){ bStart = TRUE; dwStart = TypeStart(hWnd, szMondai); break; } if(bStart == FALSE){ return DefWindowProc(hWnd, msg, wp, lp); } if(wp == VK_ESCAPE){ strcpy(szMondai, ""); strcpy(szInput, ""); strcpy(szCheck, ""); InvalidateRect(hWnd, NULL, TRUE); bStart = FALSE; break; } wsprintf(szInput, "あなたの入力 = \"%c\"", (int)wp); if(szMondai[6] == szInput[14]){ bSeikai = TRUE; mm.wType = TIME_MS; timeGetSystemTime(&mm, sizeof(MMTIME)); dwEnd = mm.u.ms; wsprintf(szCheck, "反応時間[%dミリ秒]", dwEnd - dwStart); dwStart = TypeStart(hWnd, szMondai); } else{ bSeikai = FALSE; MessageBeep(MB_OK); strcpy(szCheck, "タイプミス!"); } InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wp, lp); } return 0; } DWORD TypeStart(HWND hWnd, char *p_szMondai) { int n; MMTIME mm; n = rand() % 26; wsprintf(p_szMondai, "問題 = \"%c\"", 'a' + n); mm.wType = TIME_MS; timeGetSystemTime(&mm, sizeof(MMTIME)); InvalidateRect(hWnd, NULL, TRUE); return mm.u.ms; } #endif 以上です。 掲載されているコードは余りにもグローバル変数が多く、 自分自身余り、グローバル変数は好きではないので、関数内で収まるようにと改造したのですが。。。 お忙しい中、申し訳ございませんが、先輩方、アドバイス宜しくお願い致します。

  • InvalidateRgn()について

    ボールが右下に動いていくだけのプログラムです。 はじめはInvalidateRect(hWnd,NULL,.TRUE)を使っていたのですが画面がちらつくので InvalidateRgnを使ってみました。そこで円の部分をリージョンで指定して背面消去したら 図1のようになってしまったので、 ペンの太さを考慮してなかったのが問題だと思って円の周辺に余裕を持ってリージョンを 設定して以下のようなプログラムになったのですが(スレッドの中身です) 図2のように進行方向の部分が欠けてしまいます。 その後余白の3の部分を7以上にしたら元の円のまま動きました。 ペンの太さは3なので十分だと思ったのですが6以下でなぜ欠けてしまうんでしょうか? while(1){ hRgn = CreateEllipticRgn(x - hankei - 3, y - hankei - 3, x + hankei + 3, y + hankei + 3); x = x + 4; y = y + 2; InvalidateRgn(hWnd,hRgn,TRUE); Sleep(100); }

  • 猫でもわかるWindowsプログラミングの5.2タイピングソフトのプログラムについて

    猫でもわかるWindowsプログラミング第3版の5.2タイピングソフトのプログラムなのですが、 本のプログラムをそのまま書くと、タイプミス!の分岐にはいらないんですが、これは本が間違ってるんでしょうか? 付属のCD-ROMのプログラム(本の方とは少し違う)は正しく動いているようですが、 本に書いてある方がなぜ上手くいかないのかが理解できません。 もし本が間違えているなら、どこが間違っているのか教えていただけると助かります。 下のコードは本に書いてあった方のウィンドウプロージャ部を写したものです。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; MMTIME mm; switch (msg) { case WM_CREATE: srand((unsigned)time(NULL)); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 0, 0, szMondai, lstrlen(szMondai)); TextOut(hdc, 0, 40, szInput, lstrlen(szInput)); if(bSeikai) SetTextColor(hdc, RGB(0,0,0)); else SetTextColor(hdc, RGB(255,0,0)); TextOut(hdc,0,80,szCheck,lstrlen(szCheck)); EndPaint(hWnd, &ps); break; case WM_CHAR: if(wp == VK_SPACE && !bStart) { bStart = TRUE; TypeStart(hWnd); break; } if(bStart == FALSE) return DefWindowProc(hWnd, msg, wp, lp); if(wp == VK_ESCAPE) { lstrcpy(szMondai, TEXT("")); lstrcpy(szInput, TEXT("")); lstrcpy(szCheck, TEXT("")); InvalidateRect(hWnd, NULL, TRUE); bStart = FALSE; break; } wsprintf(szInput, TEXT("あなたの入力=\"%c\""), (int)wp); if(szMondai[6] == szInput[14]) { bSeikai = TRUE; mm.wType = TIME_MS; timeGetSystemTime(&mm, sizeof(MMTIME)); dwEnd = mm.u.ms; wsprintf(szCheck, TEXT("反応時間[%dミリ秒]"), dwEnd - dwStart); TypeStart(hWnd); } else { bSeikai = FALSE; MessageBeep(MB_OK); lstrcpy(szCheck, TEXT("タイプミス!")); } InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp,lp)); } return 0; } int TypeStart(HWND hWnd) { int n; MMTIME mm; n = rand() % 26; wsprintf(szMondai, TEXT("問題=\"%c\""), 'a' + n); mm.wType = TIME_MS; timeGetSystemTime(&mm, sizeof(MMTIME)); dwStart = mm.u.ms; InvalidateRect(hWnd, NULL, TRUE); return 0; }

  • お絵かきソフトにUNDO、REDOを実装したい

    始めまして、TKOZといいます。 今、WIN32APIの勉強の一環として、お絵かきソフトを作っています。 しかし、アンドゥ、リドゥをどうやって実装すればいいのか分からないです。 描画クラスは、基本的にはCreateDIBSectionを使って描画しています。 LPDWORD lpPixel;←が画像バッファです。 LPDWORD UNDOTABLE[100];これがUNDOバッファーのつもりです。 case WM_LBUTTONUP: で UNDOTABLE[CD.DrawCount]=lpPixel; CD.DrawCount++; として、 case IDM_UNDO: {//SendMessage(hWnd,EM_CANUNDO,0,0); CD.DrawCount--; if(CD.DrawCount==0)break; lpPixel=UNDOTABLE[CD.DrawCount]; InvalidateRect(hWnd,NULL,NULL); } としています。しかし、全然UNDOにならず、困っています。 誰か分かる方いましたら、よろしくお願いします。

  • GDI+で高速な描画

    GDI+を利用してお絵かきツールのようなものを作成しようと思っています。 しかしdrawImage()での画面への描画が非常に遅いようで、描いてみると線がカクカクしてしまいます。 アンチエイリアスやアルファブレンドが必要なのでGDI+を利用したいのですが、どうにか高速に描画させる方法はないでしょうか? 下記は現在のソースの一部です。 static Bitmap *offscreenBitmap //描画処理はこっちに static Graphics *offscreen; static Graphics *onscreen; //画面表示用 static RECT rect; //クライアント領域 static POINTS posPts,pts; //一つ前と現在のマウス座標 static BOOL bLButtonDown; Pen nomalPen(Color(100,0,0,0), 1); //描画用ペン switch(msg){  case WM_CREATE:   GetClientRect(hWnd,&rect);   offscreenBitmap = new Bitmap(rect.right, rect.bottom); //ビットマップ生成   offscreen = new Graphics(offscreenBitmap);   offscreen->SetCompositingMode(Gdiplus::CompositingModeSourceOver);   offscreen->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);//アンチエイリアス有効化   offscreen->Clear(Color(255,255,255)); //初期化   onscreen = new Graphics(hWnd); //ウインドウ表示用   onscreen->SetCompositingMode(CompositingModeSourceCopy);   break;  case WM_LBTTONDOWN:   bLButtonDown = TRUE;   posPts=MAKEPOINTS(lp)   break;  case WM_MOVE:   pts=MAKEPOINTS(lp)   if(bLButtonDown){    offscreen->DrawLine(&nomalPen, posPts.x, posPts.y, pts.x, pts.y);//線描画    posPts.x=pts.x;    posPts.y=pts.y;   }   InvalidateRect(hWnd,&rect,0);//ウインドウを更新   break;  case WM_PAINT:   onscreen->DrawImage(offscreenBitmap,0,0);//画面に書き出し   break; }

  • WinAPI「MsgWaitForMultipleObjectsについて」

    Windowsプログラミング初心者です。 MsgWaitForMultipleObjectsを使ってメッセージ待ちの処理をウェイトさせることでCPUの付加を抑えたいと考えて、以下のような処理を作りました。 4行目のPeekMessageで自分のウィンドウにユーザ定義のメッセージが届いたらループを抜け、届かなかった場合には8行目のMsgWaitForMultipleObjectsで次のメッセージが届くまでスリープしたいと思っています。 01 while(TRUE) 02 { 03 /* hWnd宛てのユーザ定義メッセージの有無を確認 */ 04 if(PeekMessage(msg, hWnd, WM_USER, WM_USER + 10, PM_REMOVE)){ 05 break; /* メッセージがあればwait処理終了 */ 06 } 07 08 if(MsgWaitForMultipleObjects(0, NULL, TRUE, INFINITE, QS_POSTMESSAGE) == -1){ 09 return ICCJZD_NG; 10 } 11 } これを動かすと、メッセージが届いているはずなのにMsgWaitForMultipleObjectsのスリープが解除されず、固まっているウィンドウ上をクリックするとスリープが解除されてユーザ定義のメッセージを受け取ってbreakします。 スリープ時間をINFINITEに設定していますが、これは可能な限りループを抑止したいからです。 ユーザ定義のメッセージが届いたら即MsgWaitForMultipleObjectsのスリープを解除させるにはどうしたらよいのでしょうか?

MFC-J998DN インクを検知しない
このQ&Aのポイント
  • インクをセットしても検知できませんという表示が出る。
  • お使いの環境はiOS16.1.1で無線LAN接続です。
  • 関連するアプリはiPrint&Scanで、電話回線はひかり回線です。
回答を見る

専門家に質問してみよう