明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

VC5打印字體的控制

[摘要]VC5.0 為Windows 的程序員提供了一個很好的C++ 開發(fā)環(huán)境,減少了很多編程負(fù)擔(dān),但同時也為我們在程序中加入自己的思想增加了難度。本人在一軟件開發(fā)中,想控制文字打印時的字體,使字體大小縮小一倍,以節(jié)省打印紙。經(jīng)過一段時間的摸索,終于解決了這一問題,下面分幾步向大家做一介紹。---- 一、...
VC5.0 為Windows 的程序員提供了一個很好的C++ 開發(fā)環(huán)境,減少了很多編程負(fù)擔(dān),但同時也為我們在程序中加入自己的思想增加了難度。本人在一軟件開發(fā)中,想控制文字打印時的字體,使字體大小縮小一倍,以節(jié)省打印紙。經(jīng)過一段時間的摸索,終于解決了這一問題,下面分幾步向大家做一介紹。

---- 一、對VC5 自動生成的程序框架進(jìn)行改進(jìn)

---- 這里用VC5 自動創(chuàng)建一個例子程序Test,單文檔界面,注意在最后一步修改view 的繼承類為CEditView。

---- 在view 類中,VC5 已經(jīng)自動創(chuàng)建了三個用于支持打印的函數(shù):OnPreparePrinting,OnBeginPrinting,OnEndPrinting。為了實現(xiàn)我們的功能,需要再繼承以下幾個函數(shù):OnPrepareDC,OnPrint。并將OnPrepareDC 和OnEndPrinting 改為如下實現(xiàn):


// 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 對打印的控制?刂谱煮w及輸出的功能主要在OnBeginPrinting 和OnPrint 兩個函數(shù)來實現(xiàn)。

---- 二、實現(xiàn)OnBeginPrinting 函數(shù)

---- 根據(jù)VC5 編程機(jī)制,在OnBeginPrinting 函數(shù)實現(xiàn)打印前的準(zhǔn)備工作,包括設(shè)置打印字體,根據(jù)打印機(jī)當(dāng)前頁面尺寸計算所需頁數(shù)等。下面的程序是對打印字體的重新設(shè)置和計算所需打印紙頁數(shù)。

---- 程序中首先取得打印機(jī)的橫向和縱向分辨率,再得到當(dāng)前打印字體的大小,然后計算出新的字體大小,為默認(rèn)字體的一半。讀者可以根據(jù)需要設(shè)定自己的打印字體大小。

---- 接著,取得當(dāng)前打印紙的寬度和高度,再根據(jù)新字體的寬度和高度計算出每行的最大字符數(shù)和每頁的最大行數(shù)。

---- 由于打印文件中有些行的寬度可能超過每行的最大字符數(shù),所以程序中調(diào)用函數(shù)RedealTextData() 對打印文件進(jìn)行重新整理,函數(shù)的實現(xiàn)在下面介紹。

---- 最后,程序中計算并設(shè)置所需的打印頁數(shù)。

OnBeginPrinting()函數(shù)實現(xiàn)如下:
//====================================
// OnBeginPrinting
//====================================
void CTestView::OnBeginPrinting(CDC* pDC,
CPrintInfo* pInfo)
{
//設(shè)置新的? 字體////////////////

//取打印機(jī)的橫方向和縱方向的分辨率
//即每英寸點數(shù)
short cxInch = pDC- >GetDeviceCaps(LOGPIXELSX);
short cyInch = pDC- >GetDeviceCaps(LOGPIXELSY);

// 取當(dāng)前字體大小
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));

//創(chuàng)建并設(shè)置新的字體,保留以前的字體
CFont newFont;
CFont *oldFont;

newFont.CreateFontIndirect(&newLogFont);
oldFont = pDC- >SelectObject(&newFont );
/////////////////////////////////
//根據(jù)字體寬度、高度計算
//每行最大字?jǐn)?shù)及每頁最大行數(shù)

//取打印紙張高度和寬度
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;

//每行最大字?jǐn)?shù)
m_MaxLineChar = nPageWidth / m_CharWidth - 8;
//每頁最大行數(shù)
m_LinesPerPage = nPageHeight/ m_LineHeight;
//根據(jù)每行最大字?jǐn)?shù)對文字進(jìn)行重新調(diào)整
RedealTextData();
//////////////////////////////////////
//計算所需打印紙張數(shù)目
int nPrintableLineCount = INT_MAX/m_LineHeight;

// m_lines為文件總行數(shù)
if (m_lines < nPrintableLineCount)
nPrintableLineCount = m_lines;
unsigned short MaxPage = (nPrintableLineCount
+ m_LinesPerPage - 1)
/ m_LinesPerPage;
//設(shè)置所需打印紙張數(shù)目
pInfo- >SetMaxPage(MaxPage);
pInfo- >m_nCurPage = 1;

//////////////////////////////////////////
//最后不要忘記將字體還原,這一句是必需的
pDC- >SelectObject(oldFont );
}
---- RedealTextData 函數(shù)根據(jù)每行最大寬度對文件進(jìn)行重新調(diào)整。主要是計算文件中每行的寬度,如果超過最大寬度則加入換行符(0x0d,0x0a)。函數(shù)實現(xiàn)如下:


//=======================================
// RedealTextData
//注:
//pDoc- >buffer為文件緩沖區(qū)
//pDoc- >file_length為文件字節(jié)長度
//pDoc- >TextLines為文件原行數(shù)
//pDoc- >MaxLineLength為文件原最大行字節(jié)寬度
//=======================================
void CTextView::RedealTextData()
{
CDocViewDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

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

//申請新的緩沖區(qū)保存調(diào)整后的文件
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;
//保存文件新的行數(shù)
m_lines = 1;
i = 0;
//記錄當(dāng)前行的寬度
short theLineLength=0;
//記錄當(dāng)前行中漢字字節(jié)數(shù),
//以防止將一半漢字分為兩行
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的字節(jié)為漢字字節(jié)
if((unsigned char)pDoc- >buffer[i] >= 0xa1)
halfChinese++;
theLineLength++;
}
//如果行寬大于每行最大寬度,進(jìn)行特殊處理
if(theLineLength > LineLengthMax)
{
char buff[256];
short m=255;
newTempPtr--;
if((unsigned char )*newTempPtr < 0xa1)
{
//如果當(dāng)前字符的前一個字符是數(shù)字、
//字母或一些特殊的前置符號時,
//指針循環(huán)向前取,
//以防止將一個單詞分為兩行。
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++;
}
}
---- 三、實現(xiàn)OnPrint 函數(shù)

---- 在OnPrint 函數(shù)中實現(xiàn)真正的文字輸出,主要功能包括設(shè)置打印字體大小,計算當(dāng)前頁號文字輸出位置,以及文字的輸出打印。

---- 程序中首先計算打印區(qū)域,文字在這個打印區(qū)域內(nèi)輸出。然后設(shè)置新的打印字體。

---- 由于OnPrint 函數(shù)是每打印一頁被調(diào)用一次,所以需要根據(jù)當(dāng)前打印頁號計算出當(dāng)前頁的文字在整個文字緩沖區(qū)的起始偏移量和終止偏移量。這里程序中調(diào)用了函數(shù)GetOffset(),此函數(shù)在下面介紹。

---- 最后調(diào)用Windows 的DrawText() 函數(shù)實現(xiàn)文字的輸出。

OnPrint()函數(shù)實現(xiàn)如下:
//====================================
// OnPrint
//========================================
void CTestView::OnPrint(CDC* pDC,
CPrintInfo* pInfo)
{
//計算打印區(qū)域//////////////////
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);

/////設(shè)置縮小字體///////////////////
//取打印機(jī)的橫方向和縱方向的分辨率
//即每英寸點數(shù)
short cxInch=pDC- >GetDeviceCaps(LOGPIXELSX);
short cyInch= DC- >GetDeviceCaps(LOGPIXELSY);

//取當(dāng)前字體大小
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));

//創(chuàng)建并設(shè)置新的字體,保留以前的字體
CFont newFont;
CFont *oldFont;
newFont.CreateFontIndirect(&newLogFont);
oldFont = pDC- >SelectObject(&newFont );

/////文字打印輸出/////////////////
unsigned short CurrentStartLine ,
CurrentEndLine;
long StartPrintOffset,
EndPrintOffset,
PrintSize;
LPSTR tempPtr;
RECT rect1,rect2;
//根據(jù)當(dāng)前打印頁號計算文字起始行
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 函數(shù)是根據(jù)給定的行號計算文字的位置,其實現(xiàn)如下:


//========================================
// 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;
}
---- 以上是本人在編程中的一點心得,歡迎和大家共同交流。


標(biāo)簽:VC5打印字體的控制