• ベストアンサー

WM_PAINT

WM_PAINT について教えてほしいのですが、 WM_PAINTがシステムから発行されるタイミングとして、 クライアント領域に無効領域がある時 UpdateWindow()を呼び出した時 InvalidateRect()を呼び出した時があると思いますが 例えば LRESULT CALLBACK WndProc(HWND , UINT , WPARAM , LPARAM) { LPCTSTR  Str = TEXT("Kitty"); switch (msg) { case WM_CREATE:    hdc = GetDC(hwnd);    SetTextColor(hdc , RGB(255, 0 , 0));    ReleaseDC(hwnd , hdc);    return 0; case WM_PAINT:    hdc = BeginPaint(hwnd , &ps);    TextOut(hdc, 10 , 10 , Str, lstrlen(Str));    EndPaint(hwnd , &ps);    return 0; } return DefWindowProc(hwnd , msg , wp , lp); } の場合, WM_PAINTはどのタイミングでシステムから呼び出されるんですか? WinMain()でUpdateWindow()もInvalidateRect()もつかっていないのですが。 いつシステムから送られるかご教授をお願いします。

noname#168725
noname#168725

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

  • ベストアンサー
  • ninigi
  • ベストアンサー率43% (10/23)
回答No.2

たぶん、作成したウィンドウを最初に表示した時にUpdateWindow等を呼んでないのに何故WM_PAINTが送られてきているのかを知りたいのだと思って回答します。 たしか、   ・ウィンドウスタイルにWS_VISIBLEを指定している場合は、CreateWindow(Ex)を呼んだ時 ・WS_VISIBLEを指定してない場合はShowWindowでウィンドウを表示した時   に最初のWM_PAINTが送られて来たと思います。 これは「クライアント領域に無効領域がある時」に該当します。   記憶に頼って書いているので、違ってるかもしれません。自分でブレークポイントとかを張ってみて確かめてみて下さい。  

noname#168725
質問者

お礼

どうも!回答ありがとうございます。 MSDNに スタイルに WS_VISIBLE を指定した場合は、さらに、ウィンドウのアクティブ化と表示に必要となるすべてのメッセージをウィンドウに送ります。 とありました。 もしかしたらこのことを指してるのかもしれませんね。 何で詳しく書いてないんだろ(><) サンキューです。

その他の回答 (2)

noname#50176
noname#50176
回答No.3

WM_PAINTメッセージは、 1.自ウインドウのクライアント領域が可視化された時 >これは初めて表示する時や非表示から表示状態になった時です。 2.自ウインドウが能動的(自己処理として)に描画状態を変えた時 >これは最小化や最大化、移動などで“自スレッド管轄”で 自身スレッドにメッセージが送られます。 3.自ウインドウが他動的(別ウインドウによって)に自クライアント 領域に状態変化影響した時 >これは他のウインドウがアクティブである時、そのウインドウが 一方的に自ウインドウクライアント領域部分を隠した時で 再び自ウインドウがアクティブになった際、 影響を与えた他スレッド管轄から再描画メッセージが送られます。 この定義だったと思います。

noname#168725
質問者

お礼

どうも!回答ありがとうございます。 ネットいろいろ調べましたがなかなか、これに関する記述が見つからず 助かります。 どうもありがとうございました。

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

★アドバイス >いつシステムから送られるかご教授をお願いします。  ↑  自分で作成したウインドウの上に別のウインドウ(メモ帳など)が覆いかぶさり、  上に乗っていたウインドウが何処かに移動すると自分で作成したウインドウが  現れます。このときシステムから無効領域として WM_PAINT メッセージを処理  するように指示がでます。 ・他にも最小化から元に戻すときや、サイズを変更した時にも WM_PAINT を処理  するようにシステムから指示が出ます。 ・とにかく再描画が必要になったときにシステム(OS)より WM_PAINT で描画する  ように信号が出されるわけですよ。  だから >WinMain()でUpdateWindow()もInvalidateRect()もつかっていないのですが。  ↑  としなくても WM_PAINT で再描画されます。 ・以上。

noname#168725
質問者

お礼

回答どうありがとうございます! どうも! Oh-Orangeさんの回答は他の方の回答でもいつも勉強になります。 できればWM_PAINTが最初に発生するタイミングも教えていただきたかったのですが。 また教えてください。 どうもありがとうございました。

関連するQ&A

  • TextOut( ) が動かない

    LRESULT CALLBACK WndProc( HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam){ PAINTSTRUCT ps; HDC hdc; switch(msg){ case WM_KEYDOWN:  if( wParam == VK_ESCAPE ){   hdc = BeginPaint(hWnd, &ps);   TextOut(hdc,0,0,str,strlen(str));   EndPaint(hWnd, &ps);  }  break; case WM_PAINT:  break; エスケープキーで文字表示をやりたいけど TextOut( ) が動作していないみたいでした。 switch(msg){ case WM_KEYDOWN:  if( wParam == VK_ESCAPE ){   hdc = BeginPaint(hWnd, &ps);   TextOut(hdc,0,0,str,strlen(str));   EndPaint(hWnd, &ps);  }  break; case WM_PAINT:  hdc = BeginPaint(hWnd, &ps);  TextOut(hdc,0,0,str,strlen(str));  EndPaint(hWnd, &ps);  break; とすると、常に文字が表示されたから、やっぱり case WM_KEYDOWN: の中の TextOut( ) が 動作していないんだと思いました。 TextOut( ) は case WM_PAINT: からのつながりが ある場合でないと実行されないんですか? ソースのおかしいところがあったら教えてください。

  • 猫でもわかる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; }

  • WM_VSCROLL内の実行回数について

    Visual Studio 2010 Express WIN32 ユニコードビルド C言語 でクライアント領域に縦スクロールバーを貼り付け次のようなプログラムを作りました。 スクロールバーの勉強中に適当に作ったプログラムです。 LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { PAINTSTRUCT ps; TCHAR moji[256]; static int countout=0; static int countin=0;       switch(message){       case WM_PAINT: BeginPaint(hwnd,&ps); wsprintf(moji,TEXT("switch文の外=%d回 switch文の中=%d"),countout,countin); TextOut(ps.hdc,0,0,moji,lstrlen(moji)); EndPaint(hwnd,&ps); break; case WM_VSCROLL: countout=countout+1; switch(LOWORD(wParam)){ case SB_LINEDOWN: countin=countin+1; break; } InvalidateRect(hwnd,NULL,TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,message,wParam,lParam); } return 0; } 私はこのプログラムの実行結果は スクロールバーのどこをクリックしてもcountoutは+1され下の矢印をクリックしたときはcountinが+1 されるという動作になると思ったのですが実行してみると スクロールバーの矢印をクリック countout が+2 スクロールバーのつまみをクリック countout が+3 スクロールバーの下矢印をクリック countout が+2,countinが+1 されるという結果になりました。 この結果から推測するとVSCROLLバーをクリックしたときはWM_VSCROLL:メッセージが複数回送られているということになると思うのですがどうしてこうなるのでしょうか? プログラミングの本などではWM_VSCROLL:の中のswitch文の外に初期化やInvalidateRectがあるのでWM_VSCROLLメッセージが送られるのは1回だけだと思ったのですが・・・・。

  • TextOut( ) を BeginPaint( ) と GetDC( )

    LRESULT CALLBACK の case WM_PAINT: で、 hdc = BeginPaint(hWnd, &ps); TextOut(hdc,0,0,str,strlen(str)); EndPaint(hWnd, &ps); ↑問題無し。↓文字がちらつく。 hdc = GetDC(hWnd); TextOut(hdc,0,0,str,strlen(str)); ReleaseDC(hWnd,hdc); ちらつきの原因は、高速で TextOut( ) が繰り返されるから だと思いました。 どうして TextOut( ) が繰り返されるんですか? 上の方法の場合は、 ReleaseDC(hWnd,hdc); は書かなくてもいいですか?

  • C言語・Windows RECTが渡せない

    C言語のWindowsプログラムで、左クリック後に四角形の描画をしたいのですがうまくいきません。 WM_LBUTTONDOWNイベントで定義したRECT構造体を、別の関数に渡しRectangleで描画したいのですが、その関数内でRECTの値を調べるととんでもない値になっています。 何度やってもどうして値がおかしくなるのかわかりません。 WM_LBUTTONDOWNもWM_PAINTも正常に反応していると思います。 どうか知恵をお貸しくださいm(_ _)m 以下ソースコードのメッセージ処理部分です。 ウィンドウ生成のひな型はサイトの物を丸写しし、正常に動作することを確認しています。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rcPos; switch (msg){ case WM_LBUTTONDOWN: rcPos.top =0; rcPos.left =0; rcPos.bottom =100; rcPos.right =100; InvalidateRect(hWnd, &rcPos, FALSE); break; //ウィンドウの描画 case WM_PAINT: hdc = BeginPaint(hWnd, &ps); DrawGr(hWnd, hdc, &rcPos); EndPaint(hWnd, &ps); break; //ウィンドウの削除 case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } return (0L); } //描画 int DrawGr(HWND hWnd, HDC hdc, RECT *rcPos) { int i; HBRUSH hBrush, hOldBrush; char *str_org = "rc.top=%d rc.left=%d rc.bottom=%d rc.right=%d"; char strx[256]; //四角形 hBrush = CreateSolidBrush(RGB(100, 100, 255)); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); //デバッグ用 wsprintf((LPSTR)strx, (LPCSTR)str_org, rcPos->top, rcPos->left, rcPos->bottom, rcPos->right); MessageBox(hWnd, (LPCSTR)strx, (LPCSTR)"終了確認", MB_OKCANCEL | MB_ICONQUESTION); Rectangle(hdc, rcPos->left, rcPos->top, rcPos->right, rcPos->bottom); SelectObject(hdc, hOldBrush); DeleteObject(hBrush); return 0; }

  • LPTSTR型の変数に文字を格納

    LPTSTR型の変数に文字を格納 現在C言語でWindowsプログラミングを学習しています。 LPTSTR 型の変数にキーボードから入力されて1文字づつ格納したいのですが、 下記のコードであればうまくいきません。 自分がTCHARやLPTSTRのことを根本から理解できていないのが原因だと思うのですが。 LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) { static LPTSTR buffer; HDC hdc; PAINTSTRUCT ps; switch(msg){ case WM_CHRAR: *buffer++=(TCHAR)wp; InvalidateRect(hWnd,NULL,TRUE); return 0; case WM_PRINT: hdc=BeginPaint(hWnd,&ps); DrawText(hdc,buffer,-1,&rc,DT_WORDBREAK); EndPaint(hWnd,&ps); return 0; ・ ・ ・ ・

  • 画像を切り替えるプログラムで悩んでいます。

    C言語で、ビットマップを『2枚』表示した後、メニューの選択により、どちらかの画像だけを表示したいのです、色々試して見たのですが、うまく行きません。ヒント、アドバイスをお願いします。 本当は『2枚』だけでなく、スキャンして、保存した画像を全て表示したいのですが、まだその方法が出来ません。 1、グローバルな変数として、   HDC hdc_mem1, hdc_mem2;//2種類のメモリデバイスコンテキストハ  ンドルを格納  int show_no = 1;//画像選択のための変数1で初期化 2、/*ウィンドウプロシージャ*/ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; static DWORD dwRop;   PAINTSTRUCT ps; HBITMAP hBmp; HDC hdc_memx; switch(msg){ case WM_CREATE: hdc = GetDC(hWnd); hdc_mem1, hdc_mem2; dwRop = SRCCOPY; hBmp = LoadBitmap(hInst, "MYBMP1"); if(hBmp == NULL){ MessageBox(hWnd, "画像1のロードに失敗しました", "エラー", MB_OK | MB_ICONWARNING); return 0; } hdc_mem1 = CreateCompatibleDC(hdc); SelectObject(hdc_mem1, hBmp); hBmp = LoadBitmap(hInst, "MYBMP2"); if(hBmp == NULL){ MessageBox(hWnd, "画像2のロードに失敗しました", "エラー", MB_OK | MB_ICONWARNING); return 0; } hdc_mem2 = CreateCompatibleDC(hdc); SelectObject(hdc_mem2, hBmp); ReleaseDC(hWnd, hdc); break; case WM_PAINT: BeginPaint(hWnd, &ps); hdc_memx = hdc_mem1, hdc_mem2; if(show_no == 1) hdc_memx = hdc_mem1; //変化なし hdc_memx != hdc_mem2;//変化なし if(show_no == 2) hdc_memx = hdc_mem2; /変化なし  hdc_memx != hdc_mem1;/変化なし BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdc_mem1, ps.rcPaint.left, ps.rcPaint.top, dwRop); BitBlt(ps.hdc, 400,200, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdc_mem2, ps.rcPaint.left, ps.rcPaint.top, dwRop); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)){ case IDM_PICT1: show_no = 1; InvalidateRect(hWnd, NULL, TRUE); break; case IDM_PICT2: show_no = 2; InvalidateRect(hWnd, NULL, TRUE); break; case IDM_SRCCOPY: dwRop = SRCCOPY; InvalidateRect(hWnd, NULL, TRUE); break; case IDM_NOTSRCCOPY: dwRop = NOTSRCCOPY; InvalidateRect(hWnd, NULL, TRUE); break; case IDM_SRCAND: dwRop = SRCAND; InvalidateRect(hWnd, NULL, TRUE); break; case IDM_SRCPAINT: dwRop = SRCPAINT; InvalidateRect(hWnd, NULL, TRUE); break; case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; } break; case WM_DESTROY: DeleteObject(hBmp); DeleteObject(hBmp); DeleteDC(hdc_mem1); DeleteDC(hdc_mem2); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; } 3、if文のところを色々と変えたのですが、うまく切り替わってくれません。   if(show_no == 1) hdc_memx = hdc_mem1; hdc_memx != hdc_mem2; if(show_no == 2) hdc_memx = hdc_mem2;  hdc_memx != hdc_mem1;

  • wsprintf( ) でポインタに代入

    wsprintf(p, "%d" , i); を書いたせいで、i の値が変わります。 wsprintf(p, "%d" , i); によってどんなことが起こっているのか詳しく知りたいです。 ポインタのことがまだよく分かってないんです。 #include <windows.h> LPCSTR szStr = "\n char c[255];\n char *p = \"\\0\";\n int i = 12345;\n\n switch (msg){\n case WM_LBUTTONDOWN:\n  wsprintf(c, \"%d\" , i);\n  wsprintf(p, \"%d\" , i);\n  MessageBox(hWnd , c , \"\" , MB_OK);\n break;"; LRESULT CALLBACK WndProc(HWND , UINT , WPARAM , LPARAM); int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE , LPSTR , int){ 省略 return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wParam , LPARAM lParam){ HDC hDC; PAINTSTRUCT ps; RECT rt; char c[255]; char *p = "\0"; int i = 12345; switch (msg){ case WM_LBUTTONDOWN: wsprintf(c, "%d" , i); wsprintf(p, "%d" , i); MessageBox(hWnd , c , "" , MB_OK); break; case WM_PAINT: GetClientRect(hWnd, &rt); hDC = BeginPaint(hWnd, &ps); DrawText(hDC, szStr, lstrlen(szStr), &rt, DT_WORDBREAK); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd , msg , wParam , lParam)); } return (0L); }

  • なぜCreateHatchBushの設定が途中で喪失するのか

    いつもお世話になります。 縦縞の四角形を表示するプログラムですが、ある一定の四角形を描画すると四角形の中の縦縞がなくなり、白色になります。 原因が分かりません。アドバイスをお願い致します。 (四角形をマウスドラッグ中に小さくすると黒い線がたくさんでてきますが、これはアプリケーションの仕様です) プロシージャソースは以下の通り。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; static POINT start, end; static bool push; switch(msg) { case WM_CREATE: push = false; break; case WM_LBUTTONDOWN: start.x = LOWORD(lParam); start.y = HIWORD(lParam); push = true; break; case WM_MOUSEMOVE: if(push){ end.x = LOWORD(lParam); end.y = HIWORD(lParam); InvalidateRect(hWnd, NULL, FALSE); } break; case WM_LBUTTONUP: end.x = LOWORD(lParam); end.y = HIWORD(lParam); push = false; InvalidateRect(hWnd, NULL, FALSE); break; case WM_PAINT: HBRUSH hBrush; hDC = BeginPaint(hWnd, &ps); hBrush = CreateHatchBrush(HS_VERTICAL, RGB(255, 0, 0)); SelectObject(hDC, hBrush); Rectangle(hDC, start.x, start.y, end.x, end.y); DeleteObject(hBrush); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } よろしくお願い致します。

  • DeleteObjectについて(初心者です)

    今こちらのサイトを参考に、APIを学んでいるものです。 http://wisdom.sakura.ne.jp/system/winapi/win32/win26.html 質問させて頂きますのはここの部分です。 LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) { HDC hdc; static LOGPEN lopnPen; PAINTSTRUCT ps; switch (msg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_CREATE: lopnPen.lopnStyle = PS_SOLID; lopnPen.lopnWidth.x = 5; lopnPen.lopnColor = 0XFF; return 0; case WM_PAINT: hdc = BeginPaint(hwnd , &ps); SelectObject(hdc , CreatePenIndirect(&lopnPen)); Ellipse(hdc , 10 , 10 , 200 , 50); DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH))); EndPaint(hwnd , &ps); return 0; } return DefWindowProc(hwnd , msg , wp , lp); } 一度yahoo知恵袋にて質問したのですが、別の面で少し疑問が残ったのでここでもう一度質問させて頂きます。 SelectObjectは引数で渡されたオブジェクトを選択中にし、返り値として以前に選択していたオブジェクトを返すという回答がありましたが、それならば DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH))); のGetStockObjectの引数WHITE_BRUSHを別のもの(例えばBLACK_PEN)に置き換えても、返り値は以前選択していたオブジェクトのままなので何も相違ないはずですよね? 当方理解もままならない初心者ですから盛大な勘違いをしているかもしれません。 分かる方、どうかご教授お願いします。

専門家に質問してみよう