【Windows编程】系列第三篇:文本字符输出

windows1

上一篇咱们展现了如何使用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消息。好比在以下状况下就会主动求处理:框架

  1. 用户移动一个窗口,致使原来被盖住的部分窗口显示出来。函数

  2. 用户调整窗口的大小,而且窗口风格类型设置为CS_HREDRAW和CS_VREDRAW。字体

  3. 程序调用ScrollWindow或者ScrollDC函数滚动客户区。ui

  4. 程序调用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);
}

 

程序运行,点击鼠标左键后效果以下:

textout

程序中的DrawText、ExtTextOut能设置文本输出的矩形范围,超出部分是看不见的,从运行结果咱们也能够看出有两行显示不全,就是因为设置的显示范围小的缘故。

另外ExtTextOut函数还能够设置字符的间距,运行结果的第三行就是这种本身设置间距不同的结果。

本程序还用CreateFont函数建立了一个斜体、右上排列的文本串。经过上例,咱们把经常使用的文本输出做为实例展现给你们,只要好好对照实例代码,在结合MSDN的说明,再加上本系列的第一篇的Windows编程基本框架,必定能够掌握好Windows编程的基本文本输出。

更多经验交流能够加入Windows编程讨论QQ群:454398517。


关注微信公众平台:程序员互动联盟(coder_online),你能够第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛作朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员本身的家。

image010

转载请注明出处,谢谢合做!

相关文章
相关标签/搜索