【Windows编程】系列第三篇:文本字符输出
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準>>>
上一篇我們展示了如何使用Windows SDK創(chuàng)建基本控件,本篇來討論如何輸出文本字符。
在使用Win32編程時,我們常常要輸出文本到窗口上,Windows所有的文本字符或者圖形輸出都是通過圖形設(shè)備接口(GDI)進行的,Windows的三大核心組件之一的GDI32.dll封裝了所有的文本和圖像輸出。
GDI基本知識
Windows下要繪圖和輸出文本,都是通過GDI(Graphics Device Interface,圖形設(shè)備接口)完成的,GDI是windows在繪制圖文時的設(shè)備上下文環(huán)境,包括畫筆、畫刷、字體、位圖等多種與繪制有關(guān)的對象。設(shè)備環(huán)境(DC)在繪制中起至關(guān)重要的作用。幾乎所有的繪制(包括圖形和文本)都與設(shè)備環(huán)境相關(guān),注意“環(huán)境”的意義,就跟我們在畫布上繪畫和寫字一樣,繪制時的畫布是哪個,用的什么筆,什么顏色,填充整個畫布時用的什么刷子等等,這就是我們的繪制時的環(huán)境,而Windows繪圖的DC設(shè)備上下文就是一樣的道理。設(shè)備環(huán)境句柄(HDC)就是用來描述DC的句柄,可以說,只要有了這個句柄,就具備了在窗口上輸出圖形和文本的條件。你獲得了窗口客戶區(qū)的HDC,就可以在窗口客戶區(qū)上畫;你獲得了窗口的非客戶區(qū)HDC,就可以在它上面畫;你獲得了桌面HDC,就可以直接在桌面上畫……
獲取設(shè)備環(huán)境句柄的方法有兩種:一是處理WM_PAINT消息時,通過BeginPaint函數(shù)返回。另外一種就是通過GetDC、GetWindowDC的API函數(shù)獲取。
通過WM_PAINT消息獲取DC
Windows在檢測到需要重新繪制或者刷新窗口時,會主動要求處理WM_PAINT消息。比如在如下情況下就會主動求處理:
用戶移動一個窗口,導(dǎo)致原來被蓋住的部分窗口顯示出來。
用戶調(diào)整窗口的大小,并且窗口風(fēng)格類型設(shè)置為CS_HREDRAW和CS_VREDRAW。
程序調(diào)用ScrollWindow或者ScrollDC函數(shù)滾動客戶區(qū)。
程序調(diào)用InvalidateRect或者InvalidateRgn函數(shù),該函數(shù)顯示生產(chǎn)一條WM_PAINT消息。
我們可以在該消息中完成圖文繪制,該消息的處理具有特定的格式,必須在實際繪制前調(diào)用BeginPaint,在繪制完成后調(diào)用EndPaint函數(shù),也就是說我們需要把所有繪制的功能都放到這兩個函數(shù)之間,并且HDC也只能在這之間使用,不能保存起來在其它地方使用。使用WM_PAINT有一個好處,就是windows會自己計算哪些區(qū)域需要更新,也就是說只有真正變化的地方才會更新,這樣更新的代價會降低到最小。
通過API函數(shù)獲取HDC
我們還可以通過GetDC、GetWindowDC函數(shù)來獲取HDC,但是要注意,通過這個來獲取的HDC,可以保存起來在其它時候使用,但是要記住一旦窗口有更新,必須想辦法重新繪制,否則就會消失了。最后在使用完畢后需要調(diào)用ReleaseDC來釋放,否則會造成資源泄露。
創(chuàng)建特定字體
我們平時最常見的文本輸出是不需要自己創(chuàng)建字體的,因為常見的對象都有系統(tǒng)預(yù)定義好的。如果想輸出點特殊(非系統(tǒng)預(yù)定義的)字體,就需要我們創(chuàng)建并自動選入設(shè)備環(huán)境。創(chuàng)建字體主要有CreateFont和CreateFontIndirect,這兩個函數(shù)的參數(shù)都很多,基本一樣,具體用法看后面的實例。
實現(xiàn)文本繪制
有了上面的基礎(chǔ),我們就可以通過Windows的API來完成文本輸出了,常用的文本輸出函數(shù)有TextOut、DrawText、DrawTextExt、ExtTextOut等,這些函數(shù)基本都有相似的參數(shù),比如hdc,坐標(biāo)位置,字符串。下面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?nameszAppName,???????????//?window?captionWS_OVERLAPPEDWINDOW,?//?window?styleCW_USEDEFAULT,???????//?initial?x?positionCW_USEDEFAULT,???????//?initial?y?position400,?????????????????//?initial?x?size300,?????????????????//?initial?y?sizeNULL,????????????????//?parent?window?handleNULL,????????????????//?window?menu?handlehInstance,???????????//?program?instance?handleNULL);???????????????//?creation?parametersShowWindow(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,?所創(chuàng)建字體的字符高度0,???????????//?nWidth,???????字體的字符平均寬度200,??????????//?nEscapement,??字符輸出方向與水平向右的方向所成角度,以0.1度為單位0,?????????????//?nOrientation,?字符與基線的角度,以0.1度為單位FW_BOLD,????????//?nWeight,??????字符顏色的深淺度TRUE,????????????//?bItalic,??????斜體屬性標(biāo)志(FALSE:正常字體,TRUE:斜體)FALSE,????????????//?bUnderline,???下劃線屬性標(biāo)志(FALSE:無下劃線,TRUE:有下劃線)FALSE,?????????????//?cStrikeOut,???刪除線屬性標(biāo)志(FALSE:無刪除線,TRUE:有刪除線)ANSI_CHARSET,???????//?nCharSet,????????字符集標(biāo)識0:ANSI字符集,1:系統(tǒng)缺省字符集OUT_DEFAULT_PRECIS,??//?nOutPrecision,???輸出精度CLIP_DEFAULT_PRECIS,?//?nClipPrecision,??剪切精度DEFAULT_QUALITY,??????//?nQuality,????????輸出品質(zhì)DEFAULT_PITCH|FF_SWISS,?//?nPitchAndFamily,?字符間距TEXT("Arial"));??????????//?lpszFacename,????現(xiàn)有系統(tǒng)TrueType字體名稱HFONT?hOldFont?=?(HFONT)SelectObject(hDC,?hFont);SetBkMode(hDC,?TRANSPARENT);SetTextColor(hDC,?RGB(0x00,?0xFF,?0xFF));TextOut(hDC,?0,?150,?TEXT("創(chuàng)建Font"),?6);DeleteObject(hFont);EndPaint(hWnd,?&ps);}return?0;case?WM_DESTROY:PostQuitMessage(0);return?0?;}return?DefWindowProc?(hWnd,?message,?wParam,?lParam); }?
程序運行,點擊鼠標(biāo)左鍵后效果如下:
程序中的DrawText、ExtTextOut能設(shè)置文本輸出的矩形范圍,超出部分是看不見的,從運行結(jié)果我們也可以看出有兩行顯示不全,就是由于設(shè)置的顯示范圍小的緣故。
另外ExtTextOut函數(shù)還可以設(shè)置字符的間距,運行結(jié)果的第三行就是這種自己設(shè)置間距不一樣的結(jié)果。
本程序還用CreateFont函數(shù)創(chuàng)建了一個斜體、右上排列的文本串。通過上例,我們把常用的文本輸出作為實例展示給大家,只要好好對照實例代碼,在結(jié)合MSDN的說明,再加上本系列的第一篇的Windows編程基本框架,一定可以掌握好Windows編程的基本文本輸出。
更多經(jīng)驗交流可以加入Windows編程討論QQ群:454398517。
關(guān)注微信公眾平臺:程序員互動聯(lián)盟(coder_online),你可以第一時間獲取原創(chuàng)技術(shù)文章,和(java/C/C++/Android/Windows/Linux)技術(shù)大牛做朋友,在線交流編程經(jīng)驗,獲取編程基礎(chǔ)知識,解決編程問題。程序員互動聯(lián)盟,開發(fā)人員自己的家。
轉(zhuǎn)載請注明出處,謝謝合作!
轉(zhuǎn)載于:https://my.oschina.net/u/2336532/blog/470870
總結(jié)
以上是生活随笔為你收集整理的【Windows编程】系列第三篇:文本字符输出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Delphi中Chrome Chromi
- 下一篇: HTML5系列四(特征检测、Modern