荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: NY (imyou), 信区: Visual
标  题: VC5 打 印 字 体 的 控 制
发信站: 荔园晨风BBS站 (Wed Jun 11 12:37:46 2003), 站内信件


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

一、 对VC5 自 动 生 成 的 程 序 框 架 进 行 改 进 ---- 这 里 用VC5 自 动 创
建 一 个 例 子 程 序Test, 单 文 档 界 面, 注 意 在 最 后 一 步 修 改view 的
 继 承 类 为CEditView。
---- 在view 类 中,VC5 已 经 自 动 创 建 了 三 个 用 于 支 持 打 印 的 函 数
:OnPreparePrinting,OnBeginPrinting,OnEndPrinting。 为 了 实 现 我 们 的 功
 能, 需 要 再 继 承 以 下 几 个 函 数:OnPrepareDC,OnPrint。 并 将OnPrepar
eDC 和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 编 程 机 制, 在OnBeginPrintin
g 函 数 实 现 打 印 前 的 准 备 工 作, 包 括 设 置 打 印 字 体, 根 据 打 印
 机 当 前 页 面 尺 寸 计 算 所 需 页 数 等。 下 面 的 程 序 是 对 打 印 字 体
 的 重 新 设 置 和 计 算 所 需 打 印 纸 页 数。
---- 程 序 中 首 先 取 得 打 印 机 的 横 向 和 纵 向 分 辨 率, 再 得 到 当
前 打 印 字 体 的 大 小, 然 后 计 算 出 新 的 字 体 大 小, 为 默 认 字 体
的 一 半。 读 者 可 以 根 据 需 要 设 定 自 己 的 打 印 字 体 大 小。
---- 接 着, 取 得 当 前 打 印 纸 的 宽 度 和 高 度, 再 根 据 新 字 体 的 宽
 度 和 高 度 计 算 出 每 行 的 最 大 字 符 数 和 每 页 的 最 大 行 数。
---- 由 于 打 印 文 件 中 有 些 行 的 宽 度 可 能 超 过 每 行 的 最 大 字 符
 数, 所 以 程 序 中 调 用 函 数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 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 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
----
 以 上 是 本 人 在 编 程 中 的 一 点 心 得, 欢 迎 和 大 家 共 同 交 流。




--
        Bill           Ferdy           Mac          Seaone

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.66]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店