2017-06-18 24 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在修改狀態。

至於使用SaveDC/RestoreDC建立DC狀態一次,然後迅速恢復它在每次繪製操作,而不是從頭開始每次我覺得至少一個障礙物的時間設置:如果其他函數調用處理程序之間RestoreDC DC恢復不在DC狀態堆棧頂部的物品,那麼在堆棧頂部的已保存狀態將被破壞,如here所述。

相關問題