17.5 设置段落格式
17.5.1 设置简单的文本格式
(1)对齐方式及起始坐标:设字符串的长度为size.cx
对齐方式 |
文本输出的起始位置(设输出框左右边界分别为xLeft、XRight) |
左对齐 |
xStart =xLeft; |
右对齐 |
xStart = xRight – size.cx |
中间对齐 |
xStart = (xLeft + xRight –size.cx) /2 |
两端对齐 |
xStart = xLeft,但要调用SetTextJustification进行调整 |
(2)两个重要函数
①GetTextExtentPoint32(hdc,pString,iCount,&size);——计算字符串长度
②SetTextJustification(hdc,xRight- xLeft –size.cx,3);
//参数2表示要分配到字符串内空格字符上的空间大小;即输出框中剩余的空间大小。
//参数3表示该范围内(xRight -xLeft)的字符串中空格的数量。
(3)每次调用SetTextJustification后,如果要求的空间无法在空格字符间平均分配,将产生一个误差项。这个误差会影响下一次的GetTextExtentPoint32。所以当开始新的一行时,要清除这个误差项,即SetTextJusitifaction(hdc,0,0);
17.5.2 段落的处理——图解段落调整(代码部分见示例中的Justify函数)
【Justify1程序】
效果图
/*------------------------------------------------------------ JUSTIFY1.C -- Justified Type Program #1 (c)Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void DrawRuler(HDC hdc, RECT *pRc); void Justify(HDC hdc, PTSTR pText, RECT *pRc, int iAlign); TCHAR szAppName[] = TEXT("Justify1"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASSEX wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Justified Type #1"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // 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; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static TCHAR szText[] = { TEXT("You don't know about me, without you ") TEXT("have read a book by the name of "The ") TEXT("Adventures of Tom Sawyer," but that ") TEXT("ain't no matter. That book was made by ") TEXT("Mr. Mark Twain, and he told the truth, ") TEXT("mainly. There was things which he ") TEXT("stretched, but mainly he told the truth. ") TEXT("That is nothing. I never seen anybody ") TEXT("but lied, one time or another, without ") TEXT("it was Aunt Polly, or the widow, or ") TEXT("maybe Mary. Aunt Polly -- Tom's Aunt ") TEXT("Polly, she is -- and Mary, and the Widow ") TEXT("Douglas, is all told about in that book ") TEXT("-- which is mostly a true book; with ") TEXT("some stretchers, as I said before.") }; static LOGFONT lf; static CHOOSEFONT cf; static int iAlign = IDM_ALIGN_LEFT; HDC hdc, hdcPrn; static PRINTDLG pd; static DOCINFO di = { sizeof(DOCINFO), TEXT("Justify1:Printing") }; PAINTSTRUCT ps; RECT rect; HMENU hMenu; BOOL fSuccess; int iSavePointSize; switch (message) { case WM_CREATE: //初始化CHOOSEFONT结构体 memset(&cf, 0, sizeof(CHOOSEFONT)); cf.lStructSize = sizeof(CHOOSEFONT); cf.hwndOwner = hwnd; cf.lpLogFont = &lf; cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS; return 0; case WM_COMMAND: hMenu = GetMenu(hwnd); switch (LOWORD(wParam)) { case IDM_FILE_PRINT: //获取打印机DC pd.lStructSize = sizeof(PRINTDLG); pd.hwndOwner = hwnd; pd.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; if (!PrintDlg(&pd)) return 0; if (NULL == (hdcPrn = pd.hDC)) { MessageBox(hwnd, TEXT("Cannot obtain Printer DC"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; } //设置1英寸的页边距 rect.left = GetDeviceCaps(hdcPrn, LOGPIXELSX) - GetDeviceCaps(hdcPrn, PHYSICALOFFSETX); rect.top = GetDeviceCaps(hdcPrn, LOGPIXELSY) - GetDeviceCaps(hdcPrn, PHYSICALOFFSETY); rect.right = GetDeviceCaps(hdcPrn, PHYSICALWIDTH) - GetDeviceCaps(hdcPrn, LOGPIXELSX); rect.bottom = GetDeviceCaps(hdcPrn, PHYSICALHEIGHT) - GetDeviceCaps(hdcPrn, LOGPIXELSY); //在打印内容 SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); fSuccess = FALSE; iSavePointSize = 5; if (0 < iSavePointSize < 10); if ((StartDoc(hdcPrn, &di) > 0) && (StartPage(hdcPrn) > 0)) { //根据所选的字体来调整高度 iSavePointSize = lf.lfHeight; lf.lfHeight = -(GetDeviceCaps(hdcPrn, LOGPIXELSY)*cf.iPointSize) / 720; //因为iPointSize以1/10磅为单位 SelectObject(hdcPrn, CreateFontIndirect(&lf)); lf.lfHeight = iSavePointSize; //设置颜色 SetTextColor(hdcPrn, cf.rgbColors); //显示文本 Justify(hdcPrn, szText, &rect, iAlign); if (EndPage(hdcPrn) > 0) { fSuccess = TRUE; EndDoc(hdcPrn); } } ShowCursor(FALSE); SetCursor(LoadCursor(NULL, IDC_ARROW)); DeleteObject(hdcPrn); if (!fSuccess) MessageBox(hwnd, TEXT("Could not print text"), szAppName, MB_ICONEXCLAMATION | MB_OK); return 0; case IDM_FONT: if (ChooseFont(&cf)) InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_ALIGN_LEFT: case IDM_ALIGN_RIGHT: case IDM_ALIGN_CENTER: case IDM_ALIGN_JUSTIFIED: CheckMenuItem(hMenu, iAlign, MF_UNCHECKED); iAlign = LOWORD(wParam); CheckMenuItem(hMenu, iAlign, MF_CHECKED); InvalidateRect(hwnd, NULL, TRUE); return 0; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); DrawRuler(hdc, &rect); //计算文本输出的区域(跳过两个标尺的客户区范围 ) rect.left += GetDeviceCaps(hdc, LOGPIXELSX) / 2; //0.5英寸 rect.top += GetDeviceCaps(hdc, LOGPIXELSY) / 2; //0.5英寸 rect.right -= GetDeviceCaps(hdc, LOGPIXELSX) / 4; //0.25英寸 SelectObject(hdc, CreateFontIndirect(&lf)); SetTextColor(hdc, cf.rgbColors); Justify(hdc, szText, &rect, iAlign); DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT))); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } //画标尺 void DrawRuler(HDC hdc, RECT *pRc) { static int iRuleSize[16] = { 360, 72, 144, 72, 216, 72, 144, 72, 288, 72, 144, 72, 216, 72, 144, 72 }; int i, j; POINT ptClient; SaveDC(hdc); //设置为逻辑Twips映射模式——这是一种自定义的模式 SetMapMode(hdc, MM_ANISOTROPIC); SetWindowExtEx(hdc, 1440, 1440, NULL); //逻辑单位为1/1440英寸 SetViewportExtEx(hdc, GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY), NULL); //将窗口原点移动左上角半英寸的地方,也就是逻辑坐标系的原点设在(0.5,0.5)英寸的地方 SetWindowOrgEx(hdc, -720, -720, NULL); //计算右边距(距离最右边1/4英寸) ptClient.x = pRc->right; //设备坐标 ptClient.y = pRc->bottom; //设备坐标 DPtoLP(hdc, &ptClient, 1); //转为逻辑坐标 ptClient.x -= 360; // 右边缩进1/4英寸 //画标尺 MoveToEx(hdc, 0, -360, NULL); // LineTo(hdc, ptClient.x, -360); //画水平标尺横线 MoveToEx(hdc, -360, 0, NULL); LineTo(hdc, -360, ptClient.y); //水平标尺各刻度线,1/16英寸的间隔画刻度线(1英寸是1440个逻辑单位) for (i = 0, j = 0; i <= ptClient.x; i += 1440 / 16, j++) { MoveToEx(hdc, i, -360, NULL); LineTo(hdc, i, -360 - iRuleSize[j % 16]); } //垂直标尺各刻度线,1/16英寸的间隔画刻度线(1英寸是1440个逻辑单位) for (i = 0, j = 0; i <= ptClient.y; i += 1440 / 16, j++) { MoveToEx(hdc, -360, i, NULL); LineTo(hdc, -360 - iRuleSize[j % 16], i); } RestoreDC(hdc, -1); } void Justify(HDC hdc, PTSTR pText, RECT *pRc, int iAlign) { int xStart, yStart, cSpaceChars; PTSTR pBegin, pEnd; SIZE size; yStart = pRc->top; do //处理每一行文本 { cSpaceChars = 0; //每行空格的个数,先初始化为0 while (*pText == ' ') //跳过每行开始处的空格 pText++; pBegin = pText; //pBegin指向该行的第一个字母 do { pEnd = pText; //将pEnd指针定位在行尾(注意,最终指向行尾) //但每次循环,先将上次的pText的位置保存在pEnd中。 //跳到下一个空格的地方 while (*pText != '