小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

VC中基于CEditView的打印和打印預(yù)覽設(shè)計(jì)

 戴維圖書(shū)館 2013-01-28

VC中基于CEditView的打印和打印預(yù)覽設(shè)計(jì)

154人閱讀 評(píng)論(0) 收藏 舉報(bào)
 
 

Visual C++中的MFC文檔視圖結(jié)構(gòu)為我們提供了打印和打印預(yù)覽程序結(jié)構(gòu)框架,使得我們只需在OnPrint或OnDraw等重載函數(shù)中添加相關(guān)代碼就可實(shí)現(xiàn)文檔內(nèi)容或圖像的打印和打印預(yù)覽功能。但是,如果程序僅僅是用來(lái)實(shí)現(xiàn)ASCII文檔內(nèi)容的顯示和打印,那么就沒(méi)有必要從頭開(kāi)始,若能在CEditView框架基礎(chǔ)上進(jìn)行程序設(shè)計(jì),即可起到事半功倍的效果。

  一、 CEditView程序框架的功能特點(diǎn)

  在用MFC AppWizard(exe)創(chuàng)建一個(gè)單文檔或多文檔應(yīng)用程序的過(guò)程中,若在向?qū)У牡诹綄⒁晥D類的基類選定為CEditView,那么該應(yīng)用程序就具有文檔的自動(dòng)顯示、編輯、查找和替換、剪貼板的剪切、復(fù)制和粘貼、打印以及打印預(yù)覽等功能。(作為示例,設(shè)這里創(chuàng)建的是單文檔應(yīng)用程序Ex_Prn1)

  但是,CEditView也存在下列缺陷:

   (1) CEditView不具有所見(jiàn)即所得編輯功能。

   (2) CEditView只能將文本作單一字體的顯示,不支持特殊格式的字符。

   (3) CEditView可以容納的文本總數(shù)有限,在32位Windows中最多不超過(guò)1M。

   (4) 打印和打印預(yù)覽功能還很勉強(qiáng)。

  因此,很有必要在CEditView基礎(chǔ)上進(jìn)行更深入的程序設(shè)計(jì),尤其是在打印和打印預(yù)覽方面。

  二、 打印和打印預(yù)覽的程序設(shè)計(jì)

  完整的打印和打印預(yù)覽設(shè)計(jì)工作包括控制頁(yè)邊距和行距、設(shè)計(jì)頁(yè)眉頁(yè)腳、控制打印字體、選擇打印模式、多頁(yè)打印以及預(yù)覽功能實(shí)現(xiàn)等。好在CEditView已經(jīng)實(shí)現(xiàn)了多頁(yè)打印和預(yù)覽功能,因此,我們只要在此基礎(chǔ)上添加頁(yè)邊距設(shè)置、頁(yè)眉頁(yè)腳以及控制打印字體等功能,就一定能滿足絕大多數(shù)ASCII文檔打印的需要。

  1.設(shè)置頁(yè)邊距

  頁(yè)邊距是指打印的文本區(qū)域與打印紙邊界之間的距離,包括左、右、上和下邊距。設(shè)置時(shí)可參考CPrintInfo的成員變量m_rectDraw的數(shù)值,但m_rectDraw的數(shù)值表示的是有效打印區(qū)域,它本身與打印紙邊界有一定的邊距,這個(gè)邊距是打印機(jī)自身造成的,因此稱之為物理邊距,并且這些物理邊距在不同大小的紙張中是不一樣的,因此首先要獲取這些數(shù)值。這時(shí)就需要調(diào)用全局函數(shù)GetDeviceCaps,它的原型如下:

int GetDeviceCaps( HDC hdc, int nIndex);

  其中,hdc用來(lái)指定設(shè)備環(huán)境句柄,nIndex用來(lái)指定要獲取的參量索引,對(duì)于打印機(jī)而言,它常常需要下列的預(yù)定義值:

   LOGPIXELSX   打印機(jī)水平分辨率

   LOGPIXELSY   打印機(jī)垂直分辨率

   PHYSICALWIDTH  打印紙的實(shí)際寬度

   PHYSICALHEIGHT 打印紙的實(shí)際高度

   PHYSICALOFFSETX 實(shí)際可打印區(qū)域的物理左邊距

   PHYSICALOFFSETY 實(shí)際可打印區(qū)域的物理上邊距

  需要說(shuō)明的是,若一張打印紙的大小為A4(210 x 297毫米),且打印機(jī)的分辨率為300 x 300dpi,當(dāng)指定函數(shù)的參數(shù)值為PHYSICALWIDTH時(shí),則返回的值不是210毫米,而是2480。這個(gè)結(jié)果是這樣計(jì)算來(lái)的:首先將毫米單位轉(zhuǎn)換成英寸,即210毫米變成8.267英寸,然后乘以300dpi。

  下面的函數(shù)代碼就是用來(lái)設(shè)置頁(yè)邊距,并且還計(jì)算頁(yè)面的物理邊距:

void CEx_Prn1View::SetPageMargin(CDC *pDC, CPrintInfo *pInfo, int l, int t, int r, int b)
// l, t, r, b分別表示左上右下邊距, 單位為0.1mm
{
int nOldMode = pDC->GetMapMode();
pDC->SetMapMode(MM_LOMETRIC);
// 計(jì)算一個(gè)設(shè)備單位等于多少0.1mm
double scaleX = 254.0 / (double)GetDeviceCaps(
pDC->m_hAttribDC, LOGPIXELSX);
double scaleY = 254.0 / (double)GetDeviceCaps(
pDC->m_hAttribDC, LOGPIXELSY);
int x = GetDeviceCaps(pDC->m_hAttribDC,
PHYSICALOFFSETX);
int y = GetDeviceCaps(pDC->m_hAttribDC,
PHYSICALOFFSETY);
int w = GetDeviceCaps(pDC->m_hAttribDC,
PHYSICALWIDTH);
int h = GetDeviceCaps(pDC->m_hAttribDC,
PHYSICALHEIGHT);
int nPageWidth = (int)((double)w*scaleX + 0.5);
// 紙寬,單位0.1mm
int nPageHeight = (int)((double)h*scaleY + 0.5);
// 紙高,單位0.1mm
m_nPhyLeft = (int)((double)x*scaleX + 0.5);
// 物理左邊距,單位0.1mm
m_nPhyTop = (int)((double)y*scaleY + 0.5);
// 物理上邊距,單位0.1mm
pDC->DPtoLP(&pInfo->m_rectDraw);
CRect rcTemp = pInfo->m_rectDraw;
rcTemp.NormalizeRect();
m_nPhyRight = nPageWidth - rcTemp.Width() -
m_nPhyLeft; // 物理右邊距,單位0.1mm
m_nPhyBottom = nPageHeight - rcTemp.Height() -
m_nPhyTop; // 物理下邊距,單位0.1mm
// 若邊距小于物理邊距,則調(diào)整它們
if (l < m_nPhyLeft) l = m_nPhyLeft;
if (t < m_nPhyTop) t = m_nPhyTop;
if (r < m_nPhyRight) r = m_nPhyRight;
if (b < m_nPhyBottom) b = m_nPhyBottom;
// 計(jì)算并調(diào)整pInfo->m_rectDraw的大小
pInfo->m_rectDraw.left = l - m_nPhyLeft;
pInfo->m_rectDraw.top = - t + m_nPhyTop;
pInfo->m_rectDraw.right -= r - m_nPhyRight;
pInfo->m_rectDraw.bottom += b - m_nPhyBottom;
pDC->LPtoDP(&pInfo->m_rectDraw);
pDC->SetMapMode(nOldMode);
// 恢復(fù)原來(lái)的映射模式
}

  需要說(shuō)明的是,由于CEditView中的設(shè)置環(huán)境映射模式是MM_TEXT,即邏輯坐標(biāo)和設(shè)備坐標(biāo)相同,因此需要通過(guò)LPtoDP和DPtoLP函數(shù)在邏輯坐標(biāo)(LP)和設(shè)備坐標(biāo)(DP)之間進(jìn)行轉(zhuǎn)換。

2.頁(yè)眉和頁(yè)腳

  打印文檔時(shí),往往需要打印文檔的標(biāo)題及頁(yè)碼或其他內(nèi)容的頁(yè)眉和頁(yè)腳。我們知道,在視圖類的函數(shù)OnPrint中處理頁(yè)眉和頁(yè)腳是最合適的,因?yàn)槊看蛴∫豁?yè),就調(diào)用該函數(shù)一次,且只在打印過(guò)程中調(diào)用。有時(shí),為了避免與正文重合,還需要調(diào)整CPrintInfo中的成員變量m_rectDraw的值。例如下面的代碼:

void CEx_Prn1View::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
SetPageMargin(pDC, pInfo, 250, 250, 250, 250);
// 頁(yè)邊距均為25毫米
int nOldMode = pDC->GetMapMode();
pDC->SetMapMode(MM_LOMETRIC);
pDC->DPtoLP(&pInfo->m_rectDraw);
// 先設(shè)置頁(yè)眉字體,然后打印頁(yè)眉
CFont font;
font.CreateFontIndirect(&m_lfHead);
CFont *oldFont = pDC->SelectObject(&font);
// 計(jì)算頁(yè)眉繪制的區(qū)域
int nHeadMargin = 200; // 設(shè)置頁(yè)眉邊距為20mm
CRect rc(pInfo->m_rectDraw);
rc.top = -nHeadMargin + m_nPhyTop;
rc.bottom = pInfo->m_rectDraw.top;
// 設(shè)頁(yè)眉內(nèi)容為打印的文檔名
CEx_Prn1Doc* pDoc = GetDocument();
CString str = pDoc->GetPathName(); // 獲取文檔全名
pDC->DrawText(str, rc, DT_TOP|DT_CENTER);
// 先設(shè)置頁(yè)腳字體,然后打印頁(yè)腳
font.Detach();
font.CreateFontIndirect(&m_lfFoot);
pDC->SelectObject(&font);
// 計(jì)算頁(yè)腳繪制的區(qū)域
int nFootMargin = 200; // 設(shè)置頁(yè)腳邊距為20mm
rc.top = pInfo->m_rectDraw.bottom;
rc.bottom = rc.top - (nFootMargin - m_nPhyBottom);
// 設(shè)頁(yè)腳內(nèi)容為打印的頁(yè)碼
str.Format("- %d -", pInfo->m_nCurPage);
pDC->DrawText(str, rc, DT_BOTTOM |
DT_SINGLELINE | DT_RIGHT);
pDC->SelectObject(oldFont); // 恢復(fù)原來(lái)的字體
pDC->LPtoDP(&pInfo->m_rectDraw);
pDC->SetMapMode(nOldMode); // 恢復(fù)原來(lái)映射模式
CEditView::OnPrint(pDC, pInfo);
}

  這樣,在用戶視圖類的構(gòu)造函數(shù)中添加LOGFONT類型的成員變量m_lfHead和m_lfFont的下列初始化代碼:

CEx_Prn1View::CEx_Prn1View()
{
memset(&m_lfHead, 0, sizeof(LOGFONT)); // 成員為0
double fontScale = 254.0/72.0;
// 一個(gè)點(diǎn)相當(dāng)于多少0.1mm
// 頁(yè)眉字體
m_lfHead.lfHeight = -(int)(9 * fontScale + 0.5); // 9號(hào)字
m_lfHead.lfWeight = FW_NORMAL;
m_lfHead.lfCharSet = GB2312_CHARSET;
strcpy((LPSTR)&(m_lfHead.lfFaceName),
"楷體_GB2312");
// 頁(yè)腳字體
m_lfFoot = m_lfHead;
}

  到這里,編譯并運(yùn)行程序后,打開(kāi)一個(gè)文檔,選擇"文件"|"打印預(yù)覽"菜單命令就可以看到效果了。但是文檔顯示的字體還需要進(jìn)行設(shè)置,這比較簡(jiǎn)單。只需添加個(gè)菜單項(xiàng)(設(shè)為ID_VIEW_FONT),然后用ClassWizard在CEx_Prn1View類添加該命令的消息映射函數(shù),并添加下列代碼:

void CEx_Prn1View::OnViewFont()
{
CFontDialog dlg;
if (dlg.DoModal() == IDOK) {
LOGFONT lf;
dlg.GetCurrentFont(&lf);
HFONT hFont;
hFont = ::CreateFontIndirect(&lf);
if (hFont != NULL)
SendMessage(WM_SETFONT, (WPARAM)hFont);
}
}

  3.重置TAB值

  在CEditView中,默認(rèn)的Tab值等于8個(gè)字符。但實(shí)際情況的Tab值往往是4個(gè)字符,所以需要重設(shè)這個(gè)Tab值。

  CEditView::SetTabStops就是這樣的函數(shù),但MSDN對(duì)其解釋令人費(fèi)解,什么"設(shè)置的Tab值是以對(duì)話框點(diǎn)為單位的"等等。實(shí)際上,只要打開(kāi)MFC的源代碼文件ViewEdit.cpp就可以看到默認(rèn)的Tab值為8*4,顯然,若設(shè)置為4個(gè)字符,則SetTabStops的參數(shù)值應(yīng)為4*4,即16。設(shè)置Tab值的代碼可直接添加在 CEx_Prn1View::OnInitialUpdate函數(shù)中:

void CEx_Prn1View::OnInitialUpdate()
{
CEditView::OnInitialUpdate();
SetTabStops(4 * 4); // 設(shè)置一個(gè)停止位等于4個(gè)字符
}

  再次運(yùn)行程序,最后的結(jié)果如上圖所示。

  

  三、 結(jié)束語(yǔ)

  通過(guò)在CEditView中添加設(shè)置頁(yè)邊距、頁(yè)眉頁(yè)腳以及改變字體和Tab值等功能,不能代碼量小,而且更主要的是滿足了一般ASCII文檔的內(nèi)容顯示和打印的要求。

分享到:

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多