2017-06-18 9 views
3

WM_CREATEメッセージに私の好みのデバイスコンテキストプロパティを設定して、それをWM_PAINTメッセージで使用しようとしました。私の方法は、それぞれWM_CREATEWM_PAINTメッセージでSaveDCRestoreDCの機能を使用することです。しかし、結果は私の必要性を満たしていません。私が本当に必要とするのは、クライアントエリアの中心に円を表示することです。"SaveDC"と "RestoreDC"関数を異なるメッセージ処理コードで使用できませんか?

#include <windows.h> 

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        PSTR szCmdLine, int iCmdShow) 
{ 
    static TCHAR szAppName[] = TEXT ("HelloWin") ; 
    HWND   hwnd ; 
    MSG   msg ; 
    WNDCLASS  wndclass ; 

    wndclass.style   = CS_HREDRAW | CS_VREDRAW ; 
    wndclass.lpfnWndProc = WndProc ; 
    wndclass.cbClsExtra = 0 ; 
    wndclass.cbWndExtra = 0 ; 
    wndclass.hInstance  = hInstance ; 
    wndclass.hIcon   = LoadIcon (NULL, IDI_APPLICATION) ; 
    wndclass.hCursor  = LoadCursor (NULL, IDC_ARROW) ; 
    wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 
    wndclass.lpszMenuName = NULL ; 
    wndclass.lpszClassName = szAppName ; 

    if (!RegisterClass (&wndclass)) 
    { 
      MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
         szAppName, MB_ICONERROR) ; 
      return 0 ; 
    } 

    hwnd = CreateWindow (szAppName,     // window class name 
          TEXT ("The Hello Program"), // window caption 
          WS_OVERLAPPEDWINDOW,  // window style 
          CW_USEDEFAULT,    // initial x position 
          CW_USEDEFAULT,    // initial y position 
          CW_USEDEFAULT,    // initial x size 
          CW_USEDEFAULT,    // initial y size 
          NULL,      // parent window handle 
          NULL,      // window menu handle 
          hInstance,     // program instance handle 
          NULL) ;      // creation parameters 

    ShowWindow (hwnd, iCmdShow) ; 
    UpdateWindow (hwnd) ; 

    while (GetMessage (&msg, NULL, 0, 0)) 
    { 
      TranslateMessage (&msg) ; 
      DispatchMessage (&msg) ; 
    } 
    return msg.wParam ; 
} 

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    HDC   hdc ; 
    PAINTSTRUCT ps ; 
    RECT rect; 
    static int nSavedDC; 

    switch (message) 
    {   
    case WM_CREATE: 
     hdc = GetDC(hwnd); 
     SetMapMode(hdc, MM_LOMETRIC); 
     GetClientRect(hwnd, &rect); 
     SetViewportOrgEx(hdc, rect.right/2, rect.bottom/2, NULL); 
     nSavedDC = SaveDC(hdc);   //I want to save the current state of device context to be used in WM_PAINT message. 
     ReleaseDC(hwnd, hdc); 
     return 0; 

    case WM_PAINT: 
      hdc = BeginPaint (hwnd, &ps) ; 
      RestoreDC(hdc, nSavedDC);  //Restore the the state of device context which is saved in WM_CREATE message. 
      Ellipse(hdc, -100, 100, 100, -100); 
      EndPaint (hwnd, &ps) ; 
      return 0 ; 

    case WM_DESTROY: 
      PostQuitMessage (0) ; 
      return 0 ; 
    } 
    return DefWindowProc (hwnd, message, wParam, lParam) ; 
} 
+1

このコードは動作しません。あなたは 'ReleaseDC(hwnd、hdc);を呼び出すことはできません;適切な呼び出しは 'ReleaseDC(hwnd、nSavedDc);'となりますが、もちろん意味がありません。最初に 'WM_CREATE'で' SaveDC'をする必要があるのはなぜですか?どんな妥当な目的のために書いたコードでもゼロ使用があるので、あなたはここで何を達成していると思いますか?あなたは何をしようとしているのですか? –

+3

これはDCの仕組みではありません。技術的には、毎回同じDCを得ることが保証されていないため、その都度DCを手動でロードすることが技術的に想定されています。 (それぞれのウィンドウに特定のDCを要求する方法がありますが、これらは16ビットWindowsのホールドオーバーであり、現在では非常に複雑なプログラムで驚異的な結果を生み出すことができます)Raymond Chenはこの件に関して多くのことを持っています。 'BeginPaint()'または 'GetDC()'を呼び出すたびに状態をロードし、元に戻す前にリセットしてください。 – andlabs

+1

@KenWhite 'ReleaseDC(hwnd、nSavedDc);'は 'nSavedDc'が整数なので完全に間違っています。元の 'ReleaseDC(hwnd、hdc);'コードは正しいです。 – VTT

答えて

1

コードにエラー処理が欠けています。各GDI関数呼び出しによって返されるすべての値を検査する必要があります。

MSDN pageに記載されているように、SaveDC/RestoreDCの目的は、描画を完了した後で主に元の状態に復元することです。これはまさにあなたがWM_CREATEWM_PAINTメッセージハンドラの両方でやっていないことです。 DCは常に変更された状態のままです。一度DCの状態を設定するためにSaveDC/RestoreDCを使用して、すぐにそれを復元し、すべてのペイント操作ではなく、最初から私は少なくとも一つの障害物を考えるたびに設定するよう

:他のいくつかの機能がRestoreDCハンドラの間で呼び出す場合DC状態のスタックの上にないアイテムを復元すると、スタックの上に保存された状態は、hereのように破壊されます。

関連する問題