上一篇咱們展現瞭如何使用Windows SDK建立基本控件,本篇來討論如何輸出文本字符。java
在使用Win32編程時,咱們經常要輸出文本到窗口上,Windows全部的文本字符或者圖形輸出都是經過圖形設備接口(GDI)進行的,Windows的三大核心組件之一的GDI32.dll封裝了全部的文本和圖像輸出。程序員
GDI基本知識編程
Windows下要繪圖和輸出文本,都是經過GDI(Graphics Device Interface,圖形設備接口)完成的,GDI是windows在繪製圖文時的設備上下文環境,包括畫筆、畫刷、字體、位圖等多種與繪製有關的對象。設備環境(DC)在繪製中起相當重要的做用。幾乎全部的繪製(包括圖形和文本)都與設備環境相關,注意「環境」的意義,就跟咱們在畫布上繪畫和寫字同樣,繪製時的畫布是哪一個,用的什麼筆,什麼顏色,填充整個畫布時用的什麼刷子等等,這就是咱們的繪製時的環境,而Windows繪圖的DC設備上下文就是同樣的道理。設備環境句柄(HDC)就是用來描述DC的句柄,能夠說,只要有了這個句柄,就具有了在窗口上輸出圖形和文本的條件。你得到了窗口客戶區的HDC,就能夠在窗口客戶區上畫;你得到了窗口的非客戶區HDC,就能夠在它上面畫;你得到了桌面HDC,就能夠直接在桌面上畫……windows
獲取設備環境句柄的方法有兩種:一是處理WM_PAINT消息時,經過BeginPaint函數返回。另一種就是經過GetDC、GetWindowDC的API函數獲取。微信
經過WM_PAINT消息獲取DC微信公衆平臺
Windows在檢測到須要從新繪製或者刷新窗口時,會主動要求處理WM_PAINT消息。好比在以下狀況下就會主動求處理:框架
用戶移動一個窗口,致使原來被蓋住的部分窗口顯示出來。函數
用戶調整窗口的大小,而且窗口風格類型設置爲CS_HREDRAW和CS_VREDRAW。字體
程序調用ScrollWindow或者ScrollDC函數滾動客戶區。ui
程序調用InvalidateRect或者InvalidateRgn函數,該函數顯示生產一條WM_PAINT消息。
咱們能夠在該消息中完成圖文繪製,該消息的處理具備特定的格式,必須在實際繪製前調用BeginPaint,在繪製完成後調用EndPaint函數,也就是說咱們須要把全部繪製的功能都放到這兩個函數之間,而且HDC也只能在這之間使用,不能保存起來在其它地方使用。使用WM_PAINT有一個好處,就是windows會本身計算哪些區域須要更新,也就是說只有真正變化的地方纔會更新,這樣更新的代價會下降到最小。
經過API函數獲取HDC
咱們還能夠經過GetDC、GetWindowDC函數來獲取HDC,可是要注意,經過這個來獲取的HDC,能夠保存起來在其它時候使用,可是要記住一旦窗口有更新,必須想辦法從新繪製,不然就會消失了。最後在使用完畢後須要調用ReleaseDC來釋放,不然會形成資源泄露。
建立特定字體
咱們平時最多見的文本輸出是不須要本身建立字體的,由於常見的對象都有系統預約義好的。若是想輸出點特殊(非系統預約義的)字體,就須要咱們建立並自動選入設備環境。建立字體主要有CreateFont和CreateFontIndirect,這兩個函數的參數都不少,基本同樣,具體用法看後面的實例。
實現文本繪製
有了上面的基礎,咱們就能夠經過Windows的API來完成文本輸出了,經常使用的文本輸出函數有TextOut、DrawText、DrawTextExt、ExtTextOut等,這些函數基本都有類似的參數,好比hdc,座標位置,字符串。下面TextOut、DrawText、ExtTextOut爲例來講明如何在Windows窗口中如何輸出文本,其它請查看MSDN的用法。
#include <windows.h> #include <tchar.h> static TCHAR szAppName[] = TEXT("Textout"); static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { 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 szAppName, // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position 400, // initial x size 300, // 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; } static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; switch (message) { case WM_CREATE: return 0; case WM_PAINT: { RECT rect = {10, 30, 100, 50}; TCHAR str[] = TEXT("English and 中文"); hDC = BeginPaint(hWnd, &ps); TextOut(hDC, 10, 10, str, _tcslen(str)); SetTextColor(hDC, RGB(255,0,0)); DrawText(hDC, str, -1, &rect, DT_LEFT|DT_VCENTER); SetTextColor(hDC, RGB(0,255,0)); INT dx[] = {8,8,8,8,16,8,8,8,16,8,8,8,10}; ExtTextOut(hDC, 10, 50, 0, &rect, str, _tcslen(str), dx); SetTextColor(hDC, RGB(0,0,255)); rect.right = 110; rect.top = 70; rect.bottom = 82; ExtTextOut(hDC, 10, rect.top, ETO_CLIPPED, &rect, str, _tcslen(str), dx); HFONT hFont = CreateFont(96, // nHeight, 所建立字體的字符高度 0, // nWidth, 字體的字符平均寬度 200, // nEscapement, 字符輸出方向與水平向右的方向所成角度,以0.1度爲單位 0, // nOrientation, 字符與基線的角度,以0.1度爲單位 FW_BOLD, // nWeight, 字符顏色的深淺度 TRUE, // bItalic, 斜體屬性標誌(FALSE:正常字體,TRUE:斜體) FALSE, // bUnderline, 下劃線屬性標誌(FALSE:無下劃線,TRUE:有下劃線) FALSE, // cStrikeOut, 刪除線屬性標誌(FALSE:無刪除線,TRUE:有刪除線) ANSI_CHARSET, // nCharSet, 字符集標識0:ANSI字符集,1:系統缺省字符集 OUT_DEFAULT_PRECIS, // nOutPrecision, 輸出精度 CLIP_DEFAULT_PRECIS, // nClipPrecision, 剪切精度 DEFAULT_QUALITY, // nQuality, 輸出品質 DEFAULT_PITCH|FF_SWISS, // nPitchAndFamily, 字符間距 TEXT("Arial")); // lpszFacename, 現有系統TrueType字體名稱 HFONT hOldFont = (HFONT)SelectObject(hDC, hFont); SetBkMode(hDC, TRANSPARENT); SetTextColor(hDC, RGB(0x00, 0xFF, 0xFF)); TextOut(hDC, 0, 150, TEXT("建立Font"), 6); DeleteObject(hFont); EndPaint(hWnd, &ps); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0 ; } return DefWindowProc (hWnd, message, wParam, lParam); }
程序運行,點擊鼠標左鍵後效果以下:
程序中的DrawText、ExtTextOut能設置文本輸出的矩形範圍,超出部分是看不見的,從運行結果咱們也能夠看出有兩行顯示不全,就是因爲設置的顯示範圍小的緣故。
另外ExtTextOut函數還能夠設置字符的間距,運行結果的第三行就是這種本身設置間距不同的結果。
本程序還用CreateFont函數建立了一個斜體、右上排列的文本串。經過上例,咱們把經常使用的文本輸出做爲實例展現給你們,只要好好對照實例代碼,在結合MSDN的說明,再加上本系列的第一篇的Windows編程基本框架,必定能夠掌握好Windows編程的基本文本輸出。
更多經驗交流能夠加入Windows編程討論QQ羣:454398517。
關注微信公衆平臺:程序員互動聯盟(coder_online),你能夠第一時間獲取原創技術文章,和(java/C/C++/Android/Windows/Linux)技術大牛作朋友,在線交流編程經驗,獲取編程基礎知識,解決編程問題。程序員互動聯盟,開發人員本身的家。
轉載請註明出處,謝謝合做!