VC 打 印 字 体 的 控 制

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 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

----
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值