计算机世界日报
返回首页 产品报价 实用技巧 国产软件 技术天地 站点精选

计算机世界展览会日报

  综合要闻
  企业&人.com
  产品与技术
  网络与通信
  市场与渠道
  99全文检索

CCW网站

  网络世界
  微电脑世界
  IT经理世界
  CCW展览
  信息服务中心   家用电脑世界

兄弟刊物

  电子与信息化
  今日电子
  中国新闻科技
  电子知识产权
  电子产品世界

网上专递

  Linux园地
  友情链接
  冬涛谈法
Dongtao on Law

98内容总汇



实用技巧

VC5 打 印 字 体 的 控 制

华 光 科 技 股 份 有 限 公 司 开 发 中 心 高 洲 平

---- VC5.0 为Windows 的 程 序 员 提 供 了 一 个 很 好 的C++ 开 发 环 境, 减 少 了 很 多 编 程 负 担, 但 同 时 也 为 我 们 在 程 序 中 加 入 自 己 的 思 想 增 加 了 难 度。 本 人 在 一 软 件 开 发 中, 想 控 制 文 字 打 印 时 的 字 体, 使 字 体 大 小 缩 小 一 倍, 以 节 省 打 印 纸。 经 过 一 段 时 间 的 摸 索, 终 于 解 决 了 这 一 问 题, 下 面 分 几 步 向 大 家 做 一 介 绍。

---- 一、 对VC5 自 动 生 成 的 程 序 框 架 进 行 改 进

---- 这 里 用VC5 自 动 创 建 一 个 例 子 程 序Test, 单 文 档 界 面, 注 意 在 最 后 一 步 修 改view 的 继 承 类 为CEditView。

---- 在view 类 中,VC5 已 经 自 动 创 建 了 三 个 用 于 支 持 打 印 的 函 数:OnPreparePrinting,OnBeginPrinting,OnEndPrinting。 为 了 实 现 我 们 的 功 能, 需 要 再 继 承 以 下 几 个 函 数:OnPrepareDC,OnPrint。 并 将OnPrepareDC 和OnEndPrinting 改 为 如 下 实 现:


// OnPrepareDC()
void CTestView::OnPrepareDC
(CDC* pDC, CPrintInfo* pInfo)
{
	CView::OnPrepareDC(pDC, pInfo);
}

// OnEndPrinting()
void CTestView::OnEndPrinting
(CDC* pDC, CPrintInfo* pInfo)
{
	CView::OnEndPrinting(pDC, pInfo);
}

---- 用CView 来 替 代 原 来 的CEditView, 用 以 避 免CEidtView 对 打 印 的 控 制。 控 制 字 体 及 输 出 的 功 能 主 要 在OnBeginPrinting 和OnPrint 两 个 函 数 来 实 现。

---- 二、 实 现OnBeginPrinting 函 数

---- 根 据VC5 编 程 机 制, 在OnBeginPrinting 函 数 实 现 打 印 前 的 准 备 工 作, 包 括 设 置 打 印 字 体, 根 据 打 印 机 当 前 页 面 尺 寸 计 算 所 需 页 数 等。 下 面 的 程 序 是 对 打 印 字 体 的 重 新 设 置 和 计 算 所 需 打 印 纸 页 数。

---- 程 序 中 首 先 取 得 打 印 机 的 横 向 和 纵 向 分 辨 率, 再 得 到 当 前 打 印 字 体 的 大 小, 然 后 计 算 出 新 的 字 体 大 小, 为 默 认 字 体 的 一 半。 读 者 可 以 根 据 需 要 设 定 自 己 的 打 印 字 体 大 小。

---- 接 着, 取 得 当 前 打 印 纸 的 宽 度 和 高 度, 再 根 据 新 字 体 的 宽 度 和 高 度 计 算 出 每 行 的 最 大 字 符 数 和 每 页 的 最 大 行 数。

---- 由 于 打 印 文 件 中 有 些 行 的 宽 度 可 能 超 过 每 行 的 最 大 字 符 数, 所 以 程 序 中 调 用 函 数RedealTextData() 对 打 印 文 件 进 行 重 新 整 理, 函 数 的 实 现 在 下 面 介 绍。

---- 最 后, 程 序 中 计 算 并 设 置 所 需 的 打 印 页 数。

	OnBeginPrinting()函数实现如下:
//====================================
// OnBeginPrinting
//====================================
void CTestView::OnBeginPrinting(CDC* pDC,
		CPrintInfo* pInfo) 
{
	//设置新的缩小字体 ////////////////
	
	//取打印机的横方向和纵方向的分辨率
	//即每英寸点数
	short cxInch = pDC- >GetDeviceCaps(LOGPIXELSX);
	short cyInch = pDC- >GetDeviceCaps(LOGPIXELSY);

	// 取当前字体大小
	CFont	*curFont = pDC- >GetCurrentFont();
	LOGFONT	curLogFont;
	LOGFONT	newLogFont;

	curFont- >GetLogFont( &curLogFont );
	long NewFontWidth = curLogFont.lfWidth;
	long NewFontHeight = curLogFont.lfHeight;
	newLogFont = curLogFont;

	//计算新的字体大小 --缩小一倍
	newLogFont.lfWidth =(long)((float)NewFontWidth/2.0
				 * ((float)cxInch / 72.0));
	newLogFont.lfHeight =(long)((float)NewFontHeight/2.0
				 * ((float)cyInch / 72.0)); 
	
	//创建并设置新的字体,保留以前的字体
	CFont	newFont;
	CFont *oldFont;

	newFont.CreateFontIndirect(&newLogFont);
	oldFont = pDC- >SelectObject(&newFont );
	/////////////////////////////////
	//根据字体宽度、高度计算
	//每行最大字数及每页最大行数

	//取打印纸张高度和宽度
	int nPageHeight, nPageWidth;
	nPageHeight = pDC- >GetDeviceCaps(VERTRES);
	nPageWidth = pDC- >GetDeviceCaps(HORZRES);

	TEXTMETRIC TextM;
	pDC- >GetTextMetrics(&TextM);
	//字体高度
	m_LineHeight = (unsigned short)TextM.tmHeight;
	//字体平均宽度
	m_CharWidth=(unsigned short)
				TextM.tmAveCharWidth;

	//每行最大字数
	m_MaxLineChar = nPageWidth / m_CharWidth - 8; 
	//每页最大行数
	m_LinesPerPage = nPageHeight/ m_LineHeight; 
	//根据每行最大字数对文字进行重新调整
	RedealTextData(); 
	//////////////////////////////////////
	//计算所需打印纸张数目
	int nPrintableLineCount = INT_MAX/m_LineHeight;

	// m_lines为文件总行数
	if (m_lines < nPrintableLineCount)
		nPrintableLineCount = m_lines;
	unsigned short MaxPage = (nPrintableLineCount
			+ m_LinesPerPage - 1) 
			/ m_LinesPerPage;
	//设置所需打印纸张数目
	pInfo- >SetMaxPage(MaxPage);
	pInfo- >m_nCurPage = 1;

	//////////////////////////////////////////
	//最后不要忘记将字体还原,这一句是必需的
	pDC- >SelectObject(oldFont );
}

---- RedealTextData 函 数 根 据 每 行 最 大 宽 度 对 文 件 进 行 重 新 调 整。 主 要 是 计 算 文 件 中 每 行 的 宽 度, 如 果 超 过 最 大 宽 度 则 加 入 换 行 符(0x0d,0x0a)。 函 数 实 现 如 下:


//=======================================
// RedealTextData
//注:
//pDoc- >buffer为文件缓冲区
//pDoc- >file_length为文件字节长度
//pDoc- >TextLines为文件原行数
//pDoc- >MaxLineLength为文件原最大行字节宽度
//=======================================
void CTextView::RedealTextData()
{
  CDocViewDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);

  short LineLengthMax = m_MaxLineChar;
  unsigned short lines=0;
  unsigned long	i,j;

  //申请新的缓冲区保存调整后的文件
  long	size = pDoc- >file_length + pDoc- >TextLines*
	(pDoc- >MaxLineLength/m_MaxLineChar+1);
  m_newBuffer = new char [size ];
  LPSTR newTempPtr = m_newBuffer;
  m_file_length =pDoc- >file_length;
  //保存文件新的行数
  m_lines = 1;
  i = 0;
  //记录当前行的宽度
  short	theLineLength=0;	
  //记录当前行中汉字字节数,
  //以防止将一半汉字分为两行
  unsigned short halfChinese=0;

  while(i < pDoc- >file_length)
  {
   *newTempPtr++ = pDoc- >buffer[i];
		
   j=i+1;
   if( (pDoc- >buffer[i] == 0x0d && 	pDoc- >buffer[j] == 0x0a))
   {
      m_lines++;
      theLineLength = 0;
   }
   else
   {
      //如果是TAB字符,宽度加8
      if(pDoc- >buffer[i] == VK_TAB)
		theLineLength += 8;
      else 
      {
      //大于0xa1的字节为汉字字节
	if((unsigned char)pDoc- >buffer[i] >= 0xa1)
		halfChinese++;
	theLineLength++;
	}
	//如果行宽大于每行最大宽度,进行特殊处理
	if(theLineLength > LineLengthMax)
	{
	  char	buff[256];
	  short m=255;
	  newTempPtr--;
	  if((unsigned char )*newTempPtr < 0xa1)
	  {
	    //如果当前字符的前一个字符是数字、
	    //字母或一些特殊的前置符号时,
	    //指针循环向前取,
	    //以防止将一个单词分为两行。
	    while((*newTempPtr >='0' && *newTempPtr< ='9')||
		    (*newTempPtr >='a' && *newTempPtr < = 'z') ||
		    (*newTempPtr >='A' &&  *newTempPtr < = 'Z') ||
		    *newTempPtr == '_' || *newTempPtr == '*' ||
		     *newTempPtr == '^' || *newTempPtr == '~' )
		buff[m--] = *newTempPtr--;
	   }
	   else //汉字
	   {	
	      //防止将一个汉字分为两行。
	      if(halfChinese%2)
	        buff[m--] = *newTempPtr--;
	   }
	   newTempPtr++;
	   //加入换行符,分为两行
	   *newTempPtr++ = 0x0d;
	   *newTempPtr++ = 0x0a;
	   for(short k=m+1; k< 256; k++)
	      *newTempPtr++ = buff[k];

	   m_lines++;
	   theLineLength = 0;
	   m_file_length += 2;
	}
   }
   i++;
  }
}

---- 三、 实 现OnPrint 函 数

---- 在OnPrint 函 数 中 实 现 真 正 的 文 字 输 出, 主 要 功 能 包 括 设 置 打 印 字 体 大 小, 计 算 当 前 页 号 文 字 输 出 位 置, 以 及 文 字 的 输 出 打 印。

---- 程 序 中 首 先 计 算 打 印 区 域, 文 字 在 这 个 打 印 区 域 内 输 出。 然 后 设 置 新 的 打 印 字 体。

---- 由 于OnPrint 函 数 是 每 打 印 一 页 被 调 用 一 次, 所 以 需 要 根 据 当 前 打 印 页 号 计 算 出 当 前 页 的 文 字 在 整 个 文 字 缓 冲 区 的 起 始 偏 移 量 和 终 止 偏 移 量。 这 里 程 序 中 调 用 了 函 数GetOffset(), 此 函 数 在 下 面 介 绍。

---- 最 后 调 用Windows 的DrawText() 函 数 实 现 文 字 的 输 出。

	OnPrint()函数实现如下:
//====================================
// OnPrint
//========================================
void CTestView::OnPrint(CDC* pDC, 
		CPrintInfo* pInfo) 
{
	//计算打印区域 //////////////////
	long yTopOfPage =(pInfo- >m_nCurPage -1) * 
		m_LinesPerPage * m_LineHeight;

	//左边空出两个字符宽度
	pDC- >SetViewportOrg(m_CharWidth * 2, 
				-yTopOfPage);
	
	int nPageWidth = pDC- >GetDeviceCaps(HORZRES);
	CRect rectClip = CRect(0, 
			yTopOfPage, 
			nPageWidth,
		 yTopOfPage + m_LinesPerPage * 
		m_LineHeight);

	/////设置缩小字体 ///////////////////
	//取打印机的横方向和纵方向的分辨率
	//即每英寸点数
	short cxInch=pDC- >GetDeviceCaps(LOGPIXELSX);
	short cyInch= DC- >GetDeviceCaps(LOGPIXELSY);

	//取当前字体大小
	CFont	*curFont = pDC- >GetCurrentFont();
	LOGFONT	curLogFont;
	LOGFONT	newLogFont;

	curFont- >GetLogFont( &curLogFont );
	long NewFontWidth = curLogFont.lfWidth;
	long NewFontHeight = curLogFont.lfHeight;
	newLogFont = curLogFont;

	//计算新的字体大小 --缩小一倍
	newLogFont.lfWidth = (long)((float)NewFontWidth/2.0 
			* ((float)cxInch / 72.0));
	newLogFont.lfHeight = (long)((float)NewFontHeight/2.0 
			* ((float)cyInch / 72.0)); 
	
	//创建并设置新的字体,保留以前的字体
	CFont	newFont;
	CFont *oldFont;
	newFont.CreateFontIndirect(&newLogFont);
	oldFont = pDC- >SelectObject(&newFont );

	/////文字打印输出 /////////////////
	unsigned short CurrentStartLine ,
			 CurrentEndLine;
	long	StartPrintOffset, 
		EndPrintOffset, 
		PrintSize;
	LPSTR	tempPtr;
	RECT	rect1,rect2;
	//根据当前打印页号计算文字起始行
	CurrentStartLine=(pInfo- >m_nCurPage-1) * m_LinesPerPage;
	//文字终止行
	CurrentEndLine = CurrentStartLine+m_LinesPerPage;

	if(CurrentEndLine > m_lines)
		CurrentEndLine = m_lines;
	//计算打印文字的起始位置和终止位置
	StartPrintOffset=GetOffset(m_newBuffer,
			m_file_length, CurrentStartLine);
	EndPrintOffset = GetOffset(m_newBuffer,
			m_file_length,CurrentEndLine);

	PrintSize = EndPrintOffset -	 StartPrintOffset;

	tempPtr = m_newBuffer + StartPrintOffset;
	//文字输出
	pDC- >DrawText(tempPtr, PrintSize,
		&rectClip,
		DT_NOCLIP |DT_NOPREFIX
 		|DT_EXPANDTABS);

	//还原旧的打印字体
	pDC- >SelectObject(oldFont );
}

---- 程 序 中 的 GetOffset 函 数 是 根 据 给 定 的 行 号 计 算 文 字 的 位 置, 其 实 现 如 下:


//========================================
// GetOffset ()  
//========================================
long	CTestView::GetOffset(LPSTR buffer, 
		long buffer_length, 
		unsigned short StartLine)
{
	if(StartLine == 0) return 0;

	unsigned short lines=0;
	long	i,j;

	i = 0;
	while(i < buffer_length)
	{
	   j=i+1;
	   if( (buffer[i++] == 0x0d && buffer[j] == 0x0a))
	   {
		lines++;
		if(lines == StartLine)
			return i;
	   }
	}
	return buffer_length;
}

---- 以 上 是 本 人 在 编 程 中 的 一 点 心 得, 欢 迎 和 大 家 共 同 交 流。

 
免 费 订 阅

实用技巧分类

Office应用
CAD
C、C++
数据库应用
Delphi
Internet应用
Java
Notes应用
操作系统应用
PowerBuilder
VB
Visual Foxpro
其他类
上周 排行榜
如 何 投 稿 ?

编者的话

在日常的工作生活中, 我们对计算机软硬件技术的应用开发肯定有许多的心得体会, 拿来和众人分享:让别人得到他们想要的,使自己找到苦苦寻觅的; 小的点点滴滴,大的工程系统,这里都需要。投稿 的关键在“技巧”二 字,知他人所不知,这样的稿件本栏最最欢迎! 大家公认的 好文章自然会有好的奖励。希望每个人 在这里都有所收获...

r2.gif (980 bytes)
  中国惠普
  3Com中国
  Motorola中国
  CA中国
  Cabletron
  Sony在中国
  西门子WinCC
  爱普生中国
  中国建设银行
  德州仪器(TI)
  问博医药


中国计算机世界出版服务公司版权所有