📄 easyreport.cpp
字号:
/*******************************************************************************
* EasyReport.cpp: implementation of the CEasyReport class.
*
* MFC Easy! Report class
*
* Written by Vipul Lal <VipulLal@hotmail.com> or <vipul@del2.vsnl.net.in>
* Copyright (c) 2000-2002. All Rights Reserved.
*
* This code may be used in compiled form in any way you desire. This
* file may be redistributed unmodified by any means PROVIDING it is
* not sold for profit without the authors written consent, and
* providing that this notice and the authors name and all copyright
* notices remains intact.
*
* An email letting me know how you are using it would be nice.
*
* This file is provided "as is" with no expressed or implied warranty.
* The author accepts no liability for any damage/loss of business that
* this product may cause.
*
* Description:
* This class encapsulates the functionality required for most reports.
* We could have derived this class from CDocument, but that would not
* have been as flexible as a stand alone class.
*
*
*
*******************************************************************************/
#include "stdafx.h"
#include "EasyReport.h"
#include "RepElement.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_SERIAL(CEasyReport, CObject,1);
void CEasyReport::Serialize(CArchive & inAr)
{
// no serialize yet !
}
/*****************************************************************
*
* method :CEasyReport::CEasyReport()
*
* parameters : None
*
* returns : Nothing
*
* description: Constructor. Set up page sizes, initalize pointers
* to null etc.
*
****************************************************************/
CEasyReport::CEasyReport()
{
int i;
for(i=0;i < eMaxStyles ;i++)
{
m_Fonts[i]= NULL;
}
// print device context...
m_PrinterDC = NULL;
// No data columns as yet..
m_NumDataCols = 0;
m_DataCols = NULL;
// setup page defaults. Note: The report used the LO_METRIC
// unit of measurement. Thus, 1 inch = 2.54 cms = 25.4 mm =
// 254 LO_METRIC units.
m_PageHeight = 11 * 254; // height of the entire page
m_PageWidth = (int)(8.5 * 254);
m_TopMargin = 127; // Half inch margin all around
m_BottomMargin = 127;
m_LeftMargin = 127;
m_RightMargin = 127;
// headers and footers. By default, ReportHeader and ReportFooter
// are set to .5". The default report header consists of the
// company name centered on the page. The default page header
// contains the report name and the date. The default page
// footer contains the page number centered within the margins.
// These are defaults. You can override these in derived classes
// or set these directly. For instance, to customize the default
// report header, override the WriteReportHeader() virtual. Ditto
// for other headers and footers.
m_PageHdrHt = 100; // height of the page header is 1cm
m_PageFtrHt = 100; // height of the page footer is 1cm
m_CurPage = m_PageCount = 0;
// The m_SuppressBlankTbl, if true, will suppress a table header from
// appearing on the report unless something is written to one of the
// columns. The RepeatTblHdr flag forces the system to repeat the
// column headings on every page.
m_SuppressBlankTbl = true; // do not write the column headings if no data is written to the column
m_RepeatTblHdr = false; // do not repeat column headings on every page
// Default report heading contains the company name
m_CompanyName = "Power Play Software"; // replace with your company name !
m_ReportHdrHt = 200; // 2 cm high
m_ReportFtrHt = 0; // no report footer
m_StdPen.CreatePen(PS_SOLID,2, RGB(0,0,0));
}
/*****************************************************************
*
* method :void CEasyReport::SetupTextStyles(CDC *inDC)
*
* parameters : inDC: Handle to the printer device context
*
* returns : Nothing.
*
* description: Set up the fonts required for the report. This is a
* virtual function, so if you override in derived classes, you can
* modify the default fonts. Actually, it might have been better if
* we had individual virtual functions, like "CreateHeadingFont" etc
* which would enable the user to override individual font styles
* per report. Maybe we can implement this in a later version!
*
* The Caption font is used for the report title.
* The ColHeading font is used for column headings.
* The DataFont is used for the data in columns
* The TextFont is used for paragraphs of text.
*
****************************************************************/
void CEasyReport::SetupTextStyles(HDC inDC)
{
// create default fonts...
LOGFONT aFont;
CPoint aPoint;
// The caption font is 20 point bold, italics
aPoint.y = (20 * GetDeviceCaps(inDC, LOGPIXELSY))/72;
DPtoLP(inDC, &aPoint,1);
memset(&aFont,0,sizeof(aFont));
aFont.lfHeight = aPoint.y;
aFont.lfWeight = FW_BOLD;
aFont.lfItalic = 1;
aFont.lfOutPrecision = OUT_STROKE_PRECIS; // Truetype font
aFont.lfQuality = PROOF_QUALITY;
aFont.lfPitchAndFamily = FF_ROMAN | VARIABLE_PITCH;
m_Fonts[ eCaptionFont ] = new CFont();
m_Fonts[ eCaptionFont ]->CreateFontIndirect(&aFont);
// the column heading font is 10-point bold, italic
aPoint.y = (10 * GetDeviceCaps(inDC,LOGPIXELSY))/72;
DPtoLP(inDC,&aPoint,1);
memset(&aFont,0,sizeof(aFont));
aFont.lfHeight = aPoint.y;
aFont.lfItalic = 1;
aFont.lfWeight = FW_BOLD;
aFont.lfOutPrecision = OUT_TT_PRECIS ; // Truetype font
aFont.lfQuality = PROOF_QUALITY;
aFont.lfPitchAndFamily = FF_SWISS | VARIABLE_PITCH;
m_Fonts[ eColHeadingFont ] = new CFont();
m_Fonts[ eColHeadingFont ]->CreateFontIndirect(&aFont);
// the data font is 10 point regular
aPoint.y = (10 * GetDeviceCaps(inDC,LOGPIXELSY))/72;
::DPtoLP(inDC,&aPoint,1);
memset(&aFont,0,sizeof(aFont));
aFont.lfHeight = aPoint.y;
aFont.lfWeight = FW_REGULAR;
aFont.lfOutPrecision = OUT_TT_PRECIS; // Truetype font
aFont.lfQuality = PROOF_QUALITY;
aFont.lfPitchAndFamily = FF_ROMAN | FIXED_PITCH;
m_Fonts[ eDataFont ] = new CFont();
m_Fonts[ eDataFont ]->CreateFontIndirect(&aFont);
// the text font is ansi variable font
m_Fonts[ eTextFont ] = new CFont();
m_Fonts[ eTextFont ]->CreateStockObject(ANSI_VAR_FONT);
// determine the cell sizes for the fonts...
TEXTMETRIC aTM;
SelectObject(inDC,(HFONT)m_Fonts[eCaptionFont]);
GetTextMetrics( inDC, &aTM );
m_TextSizes[ eCaptionFont].cx = aTM.tmAveCharWidth;
m_TextSizes[ eCaptionFont].cy = aTM.tmHeight;
SelectObject(inDC,(HFONT)m_Fonts[eColHeadingFont]);
GetTextMetrics( inDC, &aTM );
m_TextSizes[ eColHeadingFont].cx = aTM.tmAveCharWidth;
m_TextSizes[ eColHeadingFont].cy = aTM.tmHeight;
SelectObject(inDC,(HFONT)m_Fonts[eDataFont]);
GetTextMetrics(inDC,&aTM );
m_TextSizes[ eDataFont].cx = aTM.tmAveCharWidth;
m_TextSizes[ eDataFont].cy = aTM.tmHeight;
SelectObject(inDC,(HFONT)m_Fonts[eTextFont]);
GetTextMetrics(inDC,&aTM );
m_TextSizes[ eTextFont].cx = aTM.tmAveCharWidth;
m_TextSizes[ eTextFont].cy = aTM.tmHeight+ aTM.tmExternalLeading;
m_BreakChar = aTM.tmBreakChar;
}
/*****************************************************************
*
* method :CEasyReport::~CEasyReport()
*
* parameters :
*
* returns :
*
* description: Destructor. Clean up the resources we allocated.
*
****************************************************************/
CEasyReport::~CEasyReport()
{
DoCleanup();
}
/*****************************************************************
*
* method :void CEasyReport::DoCleanup()
*
* parameters :
*
* returns :
*
* description: Clean up all the resources we allocated
*
*
****************************************************************/
void CEasyReport::DoCleanup()
{
int i;
CElement *aElem;
for(i=0; i< m_ReportItems.GetSize();i++)
{
aElem = (CElement *) m_ReportItems[i];
delete aElem;
}
m_ReportItems.RemoveAll(); // clear counts...
for(i=0;i< eMaxStyles;i++)
{
delete m_Fonts[i];
m_Fonts[i]=NULL;
}
m_PageItems.RemoveAll();
}
/*****************************************************************
*
* method :void SetupRectForCol(int inTabStop, CRect &outRect)
*
* parameters :
*
* returns :
*
* description: set up rectangle so that the printing can happen only
* within the tab stop and the next tab stop, or up the edge of the
* right margin
*
****************************************************************/
void CEasyReport::SetupRectForCol(int inTabStop, CRect &outRect)
{
outRect.top = m_DataTop;
outRect.bottom = outRect.top + m_TextSizes[eDataFont].cy;
if( inTabStop <= 0 )
{
// rectangle extends from the left edge upto the first tab stop
outRect.left = m_LeftMargin;
outRect.right = m_TabStops[1];
return;
}
// If inTab is after the last valid tab, trim it to be within the right margin.
if( inTabStop > m_TabStops.GetSize()-1)
{
// inTabStop = m_TabStops.GetSize()-1;
// set to the last tab
outRect.left = m_TabStops[ m_TabStops.GetSize() - 2 ];
outRect.right = m_PageWidth - m_RightMargin;
return;
}
outRect.left = m_TabStops[inTabStop];
outRect.right = m_TabStops[inTabStop+1];
}
/*****************************************************************
*
* method :void WriteParagraph(const char *inText)
*
* parameters : inText: Long text which may be word wrapped
*
* returns : nothing
*
* description: Write a paragraph of text. If the text extends
* beyond the right edge, the text is wrapped around. Note: This
* function is not called directly, but through AtTab with tabs
* set to NULL.
*
****************************************************************/
void CEasyReport::WriteParagraph(const char *inText)
{
int aAbsBottom, aAbsWidth;
int aCurPos, aLen, aRight;
char aTempStr[128]; // non portable (should be TCHAR etc)!
CRect aRect;
CSize aSize;
CTextBox *aBox;
aRect.left = m_LeftMargin;
aRect.right = m_PageWidth - m_RightMargin;
aAbsBottom = m_PageHeight - ( m_BottomMargin + m_PageFtrHt );
aAbsWidth = m_PageWidth - ( m_LeftMargin + m_RightMargin);
aLen = strlen(inText);
aCurPos = 0;
::SelectObject(m_PrinterDC,(HFONT)m_Fonts[eTextFont]);
::SetTextCharacterExtra(m_PrinterDC,0);
while(inText[aCurPos])
{
if( m_DataTop + m_TextSizes[eTextFont].cy > aAbsBottom )
{
EjectPage(false);
aAbsBottom = m_PageHeight - ( m_BottomMargin + m_PageFtrHt );
}
// see if the remainder of the string will fit into the right margin
::SetTextJustification(m_PrinterDC,0,0);
::GetTextExtentExPoint(m_PrinterDC, inText + aCurPos, aLen - aCurPos, aAbsWidth, &aRight,NULL, &aSize);
if( inText[aCurPos+aRight] != 0 )
{
while( inText [aCurPos + aRight ] != m_BreakChar )
{
--aRight;
if( aRight <= 0 )
{
// Hopeless, the entire string is one big word !
::GetTextExtentExPoint(m_PrinterDC, inText + aCurPos, aLen - aCurPos, aAbsWidth, &aRight,NULL, &aSize);
--aRight;
break;
}
}
}
ASSERT(aRight < sizeof(aTempStr)); // Warning ! this check is at compile time only !
strncpy( aTempStr, inText + aCurPos, aRight);
aTempStr[aRight] = 0;
aRect.top = m_DataTop;
aRect.bottom = aRect.top + m_TextSizes[eTextFont].cy;
aBox = new CTextBox(&aRect, aTempStr, eTextFont);
aBox->SetDocPtr( this );
m_ReportItems.Add(aBox);
if( inText[ aCurPos + aRight] == m_BreakChar)
++aRight;
aCurPos += aRight;
m_DataTop += m_TextSizes[eTextFont].cy;
}
}
/*****************************************************************
*
* method :void CEasyReport::AtTab(int inTabStop, const char *inText)
*
* parameters : inTabStop
* char *inText: text to display
*
* returns : nothing
*
* description: If a tabular section is in place (ie if m_NumDataCols
* is non-zero, then we assume that this is a text area and we write
* out a paragraph. If a tabular section is in place, we write the
* data into the indicated column.
*
*
****************************************************************/
void CEasyReport::AtTab(int inTabStop, const char *inText)
{
CRect aRect;
if( m_NumDataCols == 0)
{
WriteParagraph(inText);
}
else
{
if( m_RedrawTblHdr )
{
if( m_DataTop + m_TableHeadingHt + GetDataFontSize().cy > (GetBottomEdge() - m_PageFtrHt) )
EjectPage(false);
if( !m_RepeatTblHdr )
WriteTableHeader();
m_RedrawTblHdr = false;
}
SetupRectForCol(inTabStop, aRect);
CTextBox *aBox = new CTextBox(&aRect,inText,eDataFont);
aBox->SetDocPtr(this);
ASSERT( inTabStop < m_NumDataCols);
switch( m_DataCols[inTabStop].m_align)
{
case CColInfo::eLeft:
aBox->SetAlign(DT_LEFT);
break;
case CColInfo::eDecimal:
case CColInfo::eRight:
// for fixed width fonts, if you control the format of data, then
// simply aligning the text right aligns the decimal places. For
// propotional fonts, you will have to adjust the left edge of
// the box.
aBox->SetAlign(DT_RIGHT);
break;
case CColInfo::eCenter:
aBox->SetAlign( DT_CENTER );
break;
}
m_ReportItems.Add( aBox );
}
}
/*****************************************************************
*
* method :void CEasyReport::SetDataCols(CColInfo *inCols, int inColCount)
*
* parameters : inCols : Array of CColInfo structur
* inColCount: # of columns.
*
* returns : Nothing
*
* description: Use this function to start a new tabular section
* on the report. If inCols == NULL (ie if the user wants a non tabular
* section) the tab stops are set to every 8 characters and the word
* wrap feature is enabled.
*
* If inCols is not NULL, then the colum start positions are
* calculated based on the character counts of the column.
*
* The algorithm supports multiple row headings - simply put a
* '\n' into the heading string. See example in SampleReportDoc.cpp
*
* Note: The colum width is in number of characters, which is easy,
* since typically, a database column width is specified in # of
* characters. However, with True-type fonts and propotional spacing,
* the display may be truncated. To eliminate this problem, you might
* want to modify the code to either use MaxCharWidth for the font or
* you might want to specify the column with in LogicalUnits. Since
* MM_LOMETRIC unit is used in the report, the column width would be
* the size in mm * 10.
*
****************************************************************/
void CEasyReport::SetDataCols(CColInfo *inCols, int inColCount)
{
int i, aLeft, aMax, aCharWidth;
int nRows,nMaxRows;
const char *s;
CColInfo *aCol;
m_TabStops.RemoveAll();
if( inCols == NULL || inColCount == 0)
{
aCharWidth = m_TextSizes[ eTextFont].cx;
m_DataCols = NULL;
m_NumDataCols = 0;
m_TableHeadingHt = 0;
// Set up tabs at every 8 characters...
aMax = (m_PageWidth - m_RightMargin) / 8;
for(i=0; i <= aMax; i++)
m_TabStops.Add((WORD)(m_LeftMargin + i * 8 * aCharWidth) );
return;
}
aCharWidth = m_TextSizes[ eDataFont].cx;
m_DataCols = inCols;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -