[Win32]文本分散对齐

本文由 Ocrosoft 于 2018-06-10 21:58:11 发表

使用SetWindowExtEx和SetViewportExtEx实现在屏幕上绘制尺子(标准长度)

使用SetTextJustification实现分散对齐

效果

1.1.main.c

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

static TCHAR szAppName[] = TEXT("Justify1");

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 = szAppName;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, TEXT("Justified Type #1"),
		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

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;

	// 保存DC
	SaveDC(hdc);

	SetMapMode(hdc, MM_ANISOTROPIC);
	SetWindowExtEx(hdc, 1440, 1440, NULL);
	// LOGPIXELSX:x方向上每英寸点数
	// LOGPIXELSY:y方向上每英寸点数
	// 将一英寸分为1440份,即逻辑坐标为1/1440英寸
	SetViewportExtEx(hdc, GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY), NULL);
	//SetViewportOrgEx(hdc, GetDeviceCaps(hdc, LOGPIXELSX) / 2, GetDeviceCaps(hdc, LOGPIXELSY) / 2, NULL);
	SetWindowOrgEx(hdc, -720, -720, NULL);
	// 屏幕原点是(0.5英寸(1.27cm),0.5英寸)

	ptClient.x = prc->right;
	ptClient.y = prc->bottom;
	DPtoLP(hdc, &ptClient, 1);
	// 360为逻辑坐标,为0.25英寸
	ptClient.x -= 360; // 右页边距

	// 绘制尺子的边线
	MoveToEx(hdc, 0, -360, NULL);
	LineTo(hdc, ptClient.x, -360);
	MoveToEx(hdc, -360, 0, NULL);
	LineTo(hdc, -360, ptClient.y);

	// 每次右移1/16英寸
	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英寸
	for (i = 0, j = 0; i < ptClient.y; i += 1440 / 16, j++)
	{
		MoveToEx(hdc, -360, i, NULL);
		LineTo(hdc, -360 - iRuleSize[j % 16], i);
	}

	// 恢复到最近保存的DC
	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;

		// 转到第一个非空格字符
		while (*pText == ' ')
			pText++;

		pBegin = pText;

		// 找到客户区能显示的一行的结尾(进行分词)
		do
		{
			pEnd = pText;

			// 转到下一个空格的后一个字符(或结尾的\0)
			while (*pText != '\0' && *pText++ != ' ');

			if (*pText == '\0')
				break;

			// 空格数量增加
			cSpaceChars++;
			// 计算这一行的长度
			GetTextExtentPoint32(hdc, pBegin, pText - pBegin - 1, &size);
		} while (size.cx < (prc->right - prc->left));

		// 将上一个单词结尾做为结尾,减去多算的空格
		cSpaceChars--;

		// 找到上一个单词的结尾(可能单词间有多个空格)
		while (*(pEnd - 1) == ' ')
		{
			pEnd--;
			cSpaceChars--;
		}

		// 如果到结尾了,或者空格数量小于等于0(可能是一整个单词,会强行在一行显示)
		if (*pText == '\0' || cSpaceChars <= 0)
			pEnd = pText;

		GetTextExtentPoint32(hdc, pBegin, pEnd - pBegin, &size);

		switch (iAlign)
		{
		case ID_ALIGN_LEFT:
			// 从最左边开始输出
			xStart = prc->left;
			break;

		case ID_ALIGN_RIGHT:
			// 右对齐,右边界-文本长度
			xStart = prc->right - size.cx;
			break;

		case ID_ALIGN_CENTER:
			// 左右空白均分
			// 简化后就是下面的
			xStart = (prc->right - size.cx - prc->left) / 2 + prc->left;
			//xStart = (prc->right + prc->left - size.cx) / 2;
			break;

		case ID_ALIGN_JUSTIFIED:
			if (*pText != '\0' && cSpaceChars > 0)
				// SetTextJustification(HDC hdc, int extra, int count);
				// 下一次对hdc进行TextOut的时候,会对文本中的空格进行调整,使空格总宽度增加extra
				// 一般使用的间隔符为空格,count表示间隔符的数量
				SetTextJustification(hdc, prc->right - prc->left - size.cx, cSpaceChars);

			xStart = prc->left;
			break;
		}

		TextOut(hdc, xStart, yStart, pBegin, pEnd - pBegin);

		SetTextJustification(hdc, 0, 0);
		yStart += size.cy;
		pText = pEnd;
	} while (*pText && yStart < prc->bottom - size.cy);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static CHOOSEFONT cf;
	static int iAlign = ID_ALIGN_LEFT;
	static LOGFONT lf;
	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.") };

	BOOL fSuccess;
	HDC hdc;
	HMENU hMenu;
	int iSavePointSize;
	PAINTSTRUCT ps;
	RECT rect;

	switch (message)
	{
	case WM_CREATE:
		GetObject(GetStockObject(SYSTEM_FONT), sizeof(lf), &lf);

		cf.lStructSize = sizeof(CHOOSEFONT);
		cf.hwndOwner = hwnd;
		cf.hDC = NULL;
		cf.lpLogFont = &lf;
		cf.iPointSize = 0;
		cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS;
		cf.rgbColors = 0;
		cf.lCustData = 0;
		cf.lpfnHook = NULL;
		cf.lpTemplateName = NULL;
		cf.hInstance = NULL;
		cf.lpszStyle = NULL;
		cf.nFontType = 0;
		cf.nSizeMin = 0;
		cf.nSizeMax = 0;

		return 0;

	case WM_COMMAND:
		hMenu = GetMenu(hwnd);

		switch (wParam)
		{
		case ID_FONT:
			if (ChooseFont(&cf))
				InvalidateRect(hwnd, NULL, TRUE);
			return 0;

		case ID_ALIGN_LEFT:
		case ID_ALIGN_RIGHT:
		case ID_ALIGN_CENTER:
		case ID_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已经在DrawRuler中转换成逻辑坐标
		rect.left += GetDeviceCaps(hdc, LOGPIXELSX) / 2;
		rect.top += GetDeviceCaps(hdc, LOGPIXELSY) / 2;
		rect.right -= GetDeviceCaps(hdc, LOGPIXELSX) / 4;

		// 字体与颜色
		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);
}

欢迎转载,请保留出处与链接。Ocrosoft » [Win32]文本分散对齐

点赞 (2)or拍砖 (1)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址