//
// WinMain函数定义
//
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
//
// 窗口类定义
// 注册窗口类
// 创建并更新窗口
// 进入消息循环
// 其他细节...
//
return msg.wParam;
}
//
// 窗口过程函数定义
//
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static int cxChar, cxCaps, cyChar;
HDC hdc;
int i;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm;
switch (message) {
// 创建窗口(初始化)消息处理
... 省略 ...
// 绘制客户区消息处理
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (i = 0; i < NUMLINES; ++i) {
TextOut(hdc, 0, cyChar * i,
sysmetrics[i].szLabel,
lstrlen(sysmetrics[i].szLabel));
TextOut(hdc, 22 * cxCaps, cyChar * i,
sysmetrics[i].szDesc,
lstrlen(sysmetrics[i].szDesc));
// 第一次使用 9SetTextAlign
SetTextAlign(hdc, TA_RIGHT | TA_TOP);
TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer,
wsprintf(szBuffer, TEXT("%5d"),
GetSystemMetrics(sysmetrics[i].iIndex)));
// 第二次使用 SetTextAlign
SetTextAlign(hdc, TA_LEFT | TA_TOP);
}
EndPaint(hwnd, &ps);
return 0;
// 销毁窗口消息处理
... 省略 ...
return DefWindowProc(hwnd, message, wParam, lParam);
}
for (i = 0; i < NUMLINES; ++i) {
TextOut(hdc, 0, cyChar * i,
sysmetrics[i].szLabel,
lstrlen(sysmetrics[i].szLabel));
TextOut(hdc, 22 * cxCaps, cyChar * i,
sysmetrics[i].szDesc,
lstrlen(sysmetrics[i].szDesc));
SetTextAlign(hdc, TA_RIGHT | TA_TOP);
//
// 这之间所有的输出文本都会按TA_RIGHT | TA_TOP的方式对齐
//
SetTextAlign(hdc, TA_LEFT | TA_TOP);
//
// 这之后的所有输出文本都会按TA_LEFT | TA_TOP的方式对齐
// 包括进入下一次循环
//
}
因为Windows默认是使用TA_LEFT | TA_TOP这种文本对齐方式,所以在首次进入for循环的时候,前两个TextOut的输出的文本对齐方式也遵循第二个SetTextAlign函数的控制格式,这从而形成了一个闭环。
// Microsoft 对SetTextAlign函数第二个参数的解释
WINGDIAPI UINT WINAPI SetTextAlign(
HDC hdc,
UINT fmode
);
/*fmode
Unsigned integer that specifies the text alignment by using a mask of
the values. The following table shows the possible values. You can
combine only one of the values that affects horizontal and with only
one of the values that affects vertical alignment. In addition, you
can combine the horizontal and vertical values with only one of the
two flags that alter the current position. The default values are
TA_LEFT, TA_TOP, and TA_NOUPDATECP.*/
// fmode其中一种取值的解释
|Value |Description
TA_BOTTOM The reference point is on the bottom edge of the bounding rectangle.
注意上面提到了一个词“reference point”。然后我们看一下对于输出函数TextOut中坐标参数的解释:
// TextOutA 函数
BOOL TextOutA(
HDC hdc,
int x,
int y,
LPCSTR lpString,
int c
);
// 坐标参数解释
x
The x-coordinate, in logical coordinates, of the reference point that
the system uses to align the string.
y
The y-coordinate, in logical coordinates, of the reference point that
the system uses to align the string.
这里同样提到了reference point这个词。细心理解你会发现,这里的位置参数x和y就文本要放置的位置,而SetTextAlign函数中的参数fmode就是文本自身的锚点。
我们需要几个小实验来验证并进一步理解SetTextAlign函数用锚点和放置位置来确定输出文本对齐方式的过程。