1. 程式人生 > >windows程式設計讀書筆記四

windows程式設計讀書筆記四

前面的程式碰到重新整理時碰到閃爍問題,百度一搜,一堆關於雙緩衝解決閃爍的文章。

具體實施方案為:

1、建立一個記憶體DC

       hdcMem = CreateCompatibleDC(hdc);

此時,記憶體DC的顯示錶面是單色、1個畫素寬、1個畫素高。即顯示錶面僅僅1位。

2、CreateCompatibleBitmap建立一個與裝置相容的點陣圖,

::GetClientRect(hwnd, &rc);

        hBitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);

3、把畫布物件選入記憶體DC

      SelectObject(hdcMem, hBitmap);

4、將記憶體DC中的圖一次性丟給DC,或則將DC中的圖丟給記憶體DC

      BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);

      BitBlt(hdcMem, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);

在用本方法改進前面的CAD程式碰到的問題

1、初始化時 ,將當前hdc內容丟給記憶體DC,BitBlt語句的位置。

       a、放在WM_CREATE訊息中,裡面的內容是黑色的;

       b、只有放置在WM_SIZE或WM_PAINT訊息內,內容才和DC一樣是白色(注意hdc的釋放及申請);

       從上述兩點,可以看出,建立視窗時,windows系統並沒有繪製視窗。跟蹤發現,CreateWindow執行完畢,視窗並未繪製,而是在後面的ShowWindow時視窗完成了繪製,此刻後進入了WM_SIZE訊息,所以此時hdc內是有內容的,同理WM_PAINT發生在後面,hdc也是有內容。

2、剛開始改動時,延續了前面程式的做法,所有更新都在WM_PAINT中進行,無法避免閃爍。後面將繪製過程在響應訊息內完成,就好了。

/*--------------------------------------------------
 利用BitBlt來重新整理
  --------------------------------------------------*/
 
#include <windows.h>
#include <windowsx.h>
#include <vector>
using std::vector;

vector<POINT> pt;

enum LineStyle {HeavyLine, LightLine, DashLine};

struct line
{
	POINT ptStart;
	POINT ptEnd;
	enum LineStyle  lineStyel;
};

vector<line> lines;
vector<line> lines_scaled;


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

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("MyCAD") ;
     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 ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("MyCAD"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     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)
{
     static int		iCount =0;
	 static int		cxClient, cyClient;	 
	 static float	scaleratio = 1;
	 static HPEN	hPen[3];
	 static HBITMAP hBitmap, hBitmapTmp;
	 static HDC    hdcMem, hdcMemTmp;
	 static RECT rc;
	 static BOOL flagCreate;
	 static BOOL flagClicked;
	 line lineTmp;
     HDC          hdc;
     PAINTSTRUCT  ps ;
	 static POINT aptStart = {0,0}, aptEnd = { 0,0 }, aptCurrent;
	 static BOOL fdraw = 0;
     switch (message)
     {
	 case WM_CREATE:
		 flagCreate = TRUE;
		 hdc = GetDC(hwnd);		 
		 ::GetClientRect(hwnd, &rc);
		 hdcMem = CreateCompatibleDC(hdc);
		 hBitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
		 hdcMemTmp = CreateCompatibleDC(hdc);
		 hBitmapTmp = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
		 
		 SelectObject(hdcMem, hBitmap);
		 SelectObject(hdcMemTmp, hBitmapTmp);
		 SelectObject(hdcMemTmp, hPen[1]);
		 hPen[0] = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
		 hPen[1] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
		 hPen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0));
		 //此時hdc內沒有內容,將得到全黑影象
		 //BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
		 //BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
		 ReleaseDC(hwnd, hdc);
		 return 0;
	 case WM_SIZE:
		 cxClient = LOWORD(lParam);
		 cyClient = HIWORD(lParam);
		 //此時hdc內有內容,可以正常使用
		 //hdc = GetDC(hwnd);
		 //BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
		 //BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
		 //ReleaseDC(hwnd, hdc);
		 return 0;
     case WM_LBUTTONDOWN:

		 aptEnd.x = GET_X_LPARAM(lParam);
		 aptEnd.y = GET_Y_LPARAM(lParam);
	
		 if (fdraw != 0)
		 {			
			 lineTmp.ptStart = aptStart;
			 lineTmp.ptEnd = aptEnd;
			 lineTmp.lineStyel = HeavyLine;
			 lines.push_back(lineTmp);
			 iCount++;
		 }
		 else
		 {
			 aptStart = aptEnd;
			 SetPixel(hdcMem, aptStart.x, aptStart.y, 0);
			 fdraw = 1;
			 return 0;
		 }	
		 MoveToEx(hdcMem, aptStart.x, aptStart.y, NULL);
		 LineTo(hdcMem, aptEnd.x, aptEnd.y);
		 hdc = GetDC(hwnd);
		 BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMemTmp, 0, 0, SRCCOPY);
		 ReleaseDC(hwnd, hdc);
		 aptStart = aptEnd;
		 if (!lines_scaled.empty())
			 lines_scaled.clear();
		 lines_scaled = lines;
		
         return 0 ;

	 case WM_RBUTTONDOWN:
		 fdraw = 0;
		 InvalidateRect(hwnd, NULL, TRUE);
		 return 0;

     case WM_MOUSEMOVE:		 	 		
		 if (fdraw)
		 {
			 aptEnd.x = GET_X_LPARAM(lParam);
			 aptEnd.y = GET_Y_LPARAM(lParam);				 
			 BitBlt(hdcMemTmp, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);
			 MoveToEx(hdcMemTmp, aptStart.x, aptStart.y, NULL);
			 LineTo(hdcMemTmp, aptEnd.x, aptEnd.y);
			 hdc = GetDC(hwnd);
			 BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMemTmp, 0, 0, SRCCOPY);
			 ReleaseDC(hwnd, hdc);					
		 }		
		 aptCurrent.x= GET_X_LPARAM(lParam);
		 aptCurrent.y = GET_Y_LPARAM(lParam);			
          return 0 ;  

	 case WM_MOUSEWHEEL:
		 if (!lines_scaled.empty())
		 {
			 if ((short)HIWORD(wParam)>0)
			 {
				 scaleratio = 1.25;
			 }
			 else
			 {
				 scaleratio = 0.8;
				
			 }
			 for (int i = 0;i < (int)lines_scaled.size();i++)
			 {
				 lines_scaled[i].ptStart.x = scaleratio*(lines_scaled[i].ptStart.x - aptCurrent.x) + aptCurrent.x;
				 lines_scaled[i].ptStart.y = scaleratio*(lines_scaled[i].ptStart.y - aptCurrent.y) + aptCurrent.y;
				 lines_scaled[i].ptEnd.x = scaleratio*(lines_scaled[i].ptEnd.x - aptCurrent.x) + aptCurrent.x;
				 lines_scaled[i].ptEnd.y = scaleratio*(lines_scaled[i].ptEnd.y - aptCurrent.y) + aptCurrent.y;
			 }
			 hdc = GetDC(hwnd);
			 Rectangle(hdc,0,0, cxClient, cyClient);
			 for (int i = 0; i < (int)lines_scaled.size(); i++)
			 {
				 MoveToEx(hdc, lines_scaled[i].ptStart.x, lines_scaled[i].ptStart.y, NULL);
				 LineTo(hdc, lines_scaled[i].ptEnd.x, lines_scaled[i].ptEnd.y);
			 }
			 ReleaseDC(hwnd, hdc);
		 }
		 BitBlt(hdcMem, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);
		 BitBlt(hdcMemTmp, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);
		 return 0;
     case WM_PAINT:		
		 hdc = BeginPaint (hwnd, &ps) ;		  
		 if (flagCreate)
		 {
			BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
			BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);		 
			flagCreate = FALSE;
			return 0;
		  }		
		  BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);
          EndPaint (hwnd, &ps) ;		  
		  return 0;
               
     case WM_DESTROY:
          PostQuitMessage (0) ;
		  DeleteObject(hPen[0]);
		  DeleteObject(hPen[1]);
		  DeleteObject(hPen[2]);
		  DeleteDC(hdcMem);
		  DeleteObject(hBitmap);
		  DeleteDC(hdcMemTmp);
		  DeleteObject(hBitmapTmp);
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}