我做一个打印程序,结果在预览窗口中不能正确分页,这个程序是从一个数据库中取值进行打印。请各位高手帮忙看看,不剩感激!!!
void CSearchTurnover::MyPrint(CDC *pDC, CPrintInfo *pInfo)
{
//pDC->SetMapMode(MM_TEXT); pDC->DPtoLP(&pInfo->m_rectDraw); 
m_strReportTitle="报表程序";
m_strReportFooter="页数";
// int nWidth=pDC->GetDeviceCaps(HORZRES);
// int nHeight=pDC->GetDeviceCaps(VERTRES);
int nWidth = pDC->GetDeviceCaps(PHYSICALWIDTH)- 2*(pDC->GetDeviceCaps(PHYSICALOFFSETX));
int nHeight = pDC->GetDeviceCaps(PHYSICALHEIGHT)- 2*(pDC->GetDeviceCaps(PHYSICALOFFSETY));
int ghdf=pDC->GetDeviceCaps(LOGPIXELSY); CFont TitleFont, HeadingFont, DetailFont, FooterFont;
//字体大小设置
m_uSizeTitle=-MulDiv(32,-pDC->GetDeviceCaps(LOGPIXELSY),72);
m_uSizeContentHead=-MulDiv(12,-pDC->GetDeviceCaps(LOGPIXELSY),72);
m_uSizeContent=-MulDiv(9,-pDC->GetDeviceCaps(LOGPIXELSY),72);
m_uSizeFooter=-MulDiv(12,-pDC->GetDeviceCaps(LOGPIXELSY),72);

//字体创建
m_strFontTitle=_T("黑体");
m_strFontContentHead=_T("宋体");
m_strFontContent=_T("宋体");
m_strFontFooter=_T("宋体"); TitleFont.CreateFont(m_uSizeTitle, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, 
m_strFontTitle);
HeadingFont.CreateFont(m_uSizeContentHead, 0, 0, 0, FW_BOLD, FALSE, TRUE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, 
m_strFontContentHead);
DetailFont.CreateFont(m_uSizeContent, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, 
m_strFontContent);
FooterFont.CreateFont(m_uSizeFooter, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, 
m_strFontFooter); CRect DrawRect(0,0,nWidth,nHeight),rect,tempRect;
// DrawRect.InflateRect(-100,-50,-100,-20); DrawRect.left+=nWidth/20;
DrawRect.right-=nWidth/20;
DrawRect.top+=nHeight/20;
DrawRect.bottom-=nHeight/20; if (pInfo->m_nCurPage==1) 
pDC->SetWindowOrg(0,0);
// pDC->SetWindowExt(1000,1000);
// pDC->SetViewportOrg(DrawRect.left,DrawRect.top);
// pDC->SetViewportExt(DrawRect.right,DrawRect.bottom); int LineHeight;
CString line;
int y = DrawRect.top;//y值控制整个页面的纵象大小
int length=0;
int height=0;
int hangshu=0;//页行数
int FooterTabStops[] = {350};
int wordlen;
LPDEVMODE mode=pInfo->m_pPD->GetDevMode();
//分横向和纵象打印
if(mode->dmOrientation==DMORIENT_LANDSCAPE)
wordlen=DrawRect.Width()/20;//字体长度
else
wordlen=DrawRect.Width()/10;
//查找数据库字段
if(hSearchCondition=="")
return;
// 标题 TEXTMETRIC metrics;
CFont *OldFont = pDC->SelectObject(&TitleFont);
pDC->GetTextMetrics(&metrics);
pDC->DrawText(m_strReportTitle,DrawRect,DT_TOP|DT_CENTER);
LineHeight = metrics.tmHeight + metrics.tmExternalLeading;
y += LineHeight;
// 表头
// 字段填充
pDC->SelectObject(&DetailFont);
pDC->GetTextMetrics(&metrics);
LineHeight = metrics.tmHeight + metrics.tmExternalLeading; //计算最大页数
int islongest=0;
for(int i=0;i<m_pListResult.GetItemCount();i++)
{
for(int j=0;j<m_pListResult.GetHeaderCtrl()->GetItemCount();j++)
{
CString value;
value=m_pListResult.GetItemText(i,j);
islongest=value.GetLength()>islongest?value.GetLength():islongest;
}
//height 为每个输出行的最大高度
//pagenum为最大页数
//hangshu 为每页行数
height+=(islongest/20+3)*LineHeight;
hangshu++;
if(height>nHeight-200)
{
rowperpage.Add(hangshu);
islongest=0;
height=y;
hangshu=0;
pagenum+=1;
}

}
pInfo->SetMaxPage(pagenum+1); //标题与表头空一行
y += LineHeight;
line.Empty(); 
CString strValue;
if(pNowRec>m_pListResult.GetItemCount())
pNowRec=0;
if(0<pResultArray.GetSize())
{
for(int j=0;j<pResultArray.GetSize()-1;j++)
{
strValue=pResultArray.GetAt(j);
strValue.TrimLeft();
strValue.TrimRight();
pDC->TextOut(DrawRect.left+wordlen*j,y,strValue);
}
y += LineHeight;
//表头与内容空一行
y += LineHeight;
} //填充提取数据
// y=DrawRect.top;
CStringArray resulttext;
for( i=pNowRec;i<m_pListResult.GetItemCount();i++)
{
CString value;
int n=0; if (pInfo && abs(y)+DrawRect.Height()/20 > DrawRect.bottom) 
{
// pInfo->m_nCurPage = pInfo->m_nCurPage + 1;
// pInfo->SetMaxPage(pInfo->m_nCurPage + 1);
if(pInfo->m_nCurPage>1)
{
int v_length;
// v_length=(pInfo->m_nCurPage-1)*(pInfo->m_rectDraw.Height()+200)+400; 
// v_length=(pInfo->m_nCurPage-1)*nHeight+nHeight/20; 
v_length=(pInfo->m_nCurPage-1)*nHeight;

pDC->SetWindowOrg(pInfo->m_rectDraw.left,v_length);

pDC->SetViewportOrg(DrawRect.left,DrawRect.top);
pDC->SetViewportExt(DrawRect.right,DrawRect.bottom);
}
else if(pInfo->m_nCurPage==1)
{
pDC->SetWindowOrg(0,0);
pDC->SetViewportOrg(DrawRect.left,DrawRect.top);
pDC->SetViewportExt(DrawRect.right,DrawRect.bottom);
}
}
if(abs(y)>DrawRect.Height()*pInfo->m_nCurPage)
{
pNowRec=i;
break;
}
resulttext.RemoveAll();
for(int j=0;j<m_pListResult.GetHeaderCtrl()->GetItemCount();j++)
{
value=m_pListResult.GetItemText(i,j);
resulttext.Add(value);
}
CRect textrect;
int length= 0;
// for(int y=rect.top;y+LineHeight<rect.bottom;y+=LineHeight)
// for(int x=DrawRect.left;x+700<DrawRect.right;x+=700)
int x=DrawRect.left;int m=0;int result=0;int linage;
while(m<resulttext.GetSize())
{
//对字串进行处理时,每行长度由wordlen控制
//则转行数输出计算由字串长度/wordlen
//共有行数linage*LineHeight为字串共占有行数维度大小
textrect.left=x;
textrect.top=y;
x+=wordlen;
linage=resulttext.GetAt(m).GetLength()/20+3;
textrect.right=x;
textrect.bottom=y+LineHeight*linage;
pDC->DrawText(resulttext.GetAt(m),textrect,DT_TOP|DT_WORDBREAK);
result=textrect.bottom>=result?textrect.bottom:result;
// pDC->DrawText(resulttext.GetAt(i),textrect,DT_CALCRECT);
length++;m++;
}
y=result+10;//行与行间留一定空隙
} // 页角
if (pInfo) 
{
pDC->SelectObject(&FooterFont);
line.Format("%s : %d ", m_strReportFooter, pInfo->m_nCurPage);
pDC->DrawText(line,DrawRect,DT_BOTTOM |DT_RIGHT|DT_SINGLELINE);
}
pDC->LPtoDP(&pInfo->m_rectDraw);  pDC->SelectObject(OldFont);
}

解决方案 »

  1.   

    This article describes the Windows printing protocol and explains how to print documents that contain more than one page. The article covers the following topics: Printing protocol
    Overriding view class functions
    Pagination
    Printer pages vs. document pages
    Print-time pagination 
    The Printing Protocol
    To print a multipage document, the framework and view interact in the following manner. First the framework displays the Print dialog box, creates a device context for the printer, and calls the StartDoc member function of the CDC object. Then, for each page of the document, the framework calls the StartPage member function of the CDC object, instructs the view object to print the page, and calls the EndPage member function. If the printer mode must be changed before starting a particular page, the view object sends the appropriate escape code by calling the Escape member function of the CDC object. When the entire document has been printed, the framework calls the EndDoc member function.Overriding View Class Functions
    The CView class defines several member functions that are called by the framework during printing. By overriding these functions in your view class, you provide the connections between the framework’s printing logic and your view class’s printing logic. The following table lists these member functions.CView’s Overridable Functions for PrintingName Reason for overriding 
    OnPreparePrinting To insert values in the Print dialog box, especially the length of the document 
    OnBeginPrinting To allocate fonts or other GDI resources 
    OnPrepareDC To adjust attributes of the device context for a given page, or to do print-time pagination 
    OnPrint To print a given page 
    OnEndPrinting To deallocate GDI resources 
    You can do printing-related processing in other functions as well, but these functions are the ones that drive the printing process.The following figure illustrates the steps involved in the printing process and shows where each of CView’s printing member functions are called. The rest of this article explains most of these steps in more detail. Additional parts of the printing process are described in the article Printing: Allocating GDI Resources. The Printing LoopPagination
    The framework stores much of the information about a print job in a CPrintInfo structure. Several of the values in CPrintInfo pertain to pagination; these values are accessible as shown in the following table.Page Number Information Stored in CPrintInfoMember variable or 
    function name(s) 
    Page number referenced 
    GetMinPage/SetMinPage First page of document 
    GetMaxPage/SetMaxPage Last page of document 
    GetFromPage First page to be printed 
    GetToPage Last page to be printed 
    m_nCurPage Page currently being printed 
    Page numbers start at 1, that is, the first page is numbered 1, not 0. For more information about these and other members of CPrintInfo, see the Class Library Reference.At the beginning of the printing process, the framework calls the view’s OnPreparePrinting member function, passing a pointer to a CPrintInfo structure. AppWizard provides an implementation of OnPreparePrinting that calls DoPreparePrinting, another member function of CView. DoPreparePrinting is the function that displays the Print dialog box and creates a printer device context.At this point the application doesn’t know how many pages are in the document. It uses the default values 1 and 0xFFFF for the numbers of the first and last page of the document. If you know how many pages your document has, override OnPreparePrinting and call SetMaxPage for the CPrintInfo structure before you send it to DoPreparePrinting. This lets you specify the length of your document. DoPreparePrinting then displays the Print dialog box. When it returns, the CPrintInfo structure contains the values specified by the user. If the user wishes to print only a selected range of pages, he or she can specify the starting and ending page numbers in the Print dialog box. The framework retrieves these values using the GetFromPage and GetToPage functions of CPrintInfo. If the user doesn’t specify a page range, the framework calls GetMinPage and GetMaxPage and uses the values returned to print the entire document.For each page of a document to be printed, the framework calls two member functions in your view class, OnPrepareDC and OnPrint, and passes each function two parameters: a pointer to a CDC object and a pointer to a CPrintInfo structure. Each time the framework calls OnPrepareDC and OnPrint, it passes a different value in the m_nCurPage member of the CPrintInfo structure. In this way the framework tells the view which page should be printed.The OnPrepareDC member function is also used for screen display. It makes adjustments to the device context before drawing takes place. OnPrepareDC serves a similar role in printing, but there are a couple of differences: first, the CDC object represents a printer device context instead of a screen device context, and second, a CPrintInfo object is passed as a second parameter. (This parameter is NULL when OnPrepareDC is called for screen display.) Override OnPrepareDC to make adjustments to the device context based on which page is being printed. For example, you can move the viewport origin and the clipping region to ensure that the appropriate portion of the document gets printed. 
      

  2.   

    The OnPrint member function performs the actual printing of the page. The article Printing: How Default Printing Is Done shows how the framework calls OnDraw with a printer device context to perform printing. More precisely, the framework calls OnPrint with a CPrintInfo structure and a device context, and OnPrint passes the device context to OnDraw. Override OnPrint to perform any rendering that should be done only during printing and not for screen display. For example, to print headers or footers (see the article Printing: Headers and Footers for more information). Then call OnDraw from the override of OnDraw to do the rendering common to both screen display and printing. The fact that OnDraw does the rendering for both screen display and printing means that your application is WYSIWYG: “What you see is what you get.” However, suppose you aren’t writing a WYSIWYG application. For example, consider a text editor that uses a bold font for printing but displays control codes to indicate bold text on the screen. In such a situation, you use OnDraw strictly for screen display. When you override OnPrint, substitute the call to OnDraw with a call to a separate drawing function. That function draws the document the way it appears on paper, using the attributes that you don’t display on the screen.Printer Pages vs. Document Pages
    When you refer to page numbers, it’s sometimes necessary to distinguish between the printer’s concept of a page and a document’s concept of a page. From the point of view of the printer, a page is one sheet of paper. However, one sheet of paper doesn’t necessarily equal one page of the document. For example, if you’re printing a newsletter, where the sheets are to be folded, one sheet of paper might contain both the first and last pages of the document, side by side. Similarly, if you’re printing a spreadsheet, the document doesn’t consist of pages at all. Instead, one sheet of paper might contain rows 1 through 20, columns 6 through 10.All the page numbers in the CPrintInfo structure refer to printer pages. The framework calls OnPrepareDC and OnPrint once for each sheet of paper that will pass through the printer. When you override the OnPreparePrinting function to specify the length of the document, you must use printer pages. If there is a one-to-one correspondence (that is, one printer page equals one document page), then this is easy. If, on the other hand, document pages and printer pages do not directly correspond, you must translate between them. For example, consider printing a spreadsheet. When overriding OnPreparePrinting, you must calculate how many sheets of paper will be required to print the entire spreadsheet and then use that value when calling the SetMaxPage member function of CPrintInfo. Similarly, when overriding OnPrepareDC, you must translate m_nCurPage into the range of rows and columns that will appear on that particular sheet and then adjust the viewport origin accordingly.Print-Time Pagination
    In some situations, your view class may not know in advance how long the document is until it has actually been printed. For example, suppose your application isn’t WYSIWYG, so a document’s length on the screen doesn’t correspond to its length when printed.This causes a problem when you override OnPreparePrinting for your view class: you can’t pass a value to the SetMaxPage function of the CPrintInfo structure, because you don’t know the length of a document. If the user doesn’t specify a page number to stop at using the Print dialog box, the framework doesn’t know when to stop the print loop. The only way to determine when to stop the print loop is to print out the document and see when it ends. Your view class must check for the end of the document while it is being printed, and then inform the framework when the end is reached.The framework relies on your view class’s OnPrepareDC function to tell it when to stop. After each call to OnPrepareDC, the framework checks a member of the CPrintInfo structure called m_bContinuePrinting. Its default value is TRUE. As long as it remains so, the framework continues the print loop. If it is set to FALSE, the framework stops. To perform print-time pagination, override OnPrepareDC to check whether the end of the document has been reached, and set m_bContinuePrinting to FALSE when it has. The default implementation of OnPrepareDC sets m_bContinuePrinting to FALSE if the current page is greater than 1. This means that if the length of the document wasn’t specified, the framework assumes the document is one page long. One consequence of this is that you must be careful if you call the base class version of OnPrepareDC. Do not assume that m_bContinuePrinting will be TRUE after calling the base class version.