INTRODUCTION AND RELEVANT INFORMATION:
I am trying to bypass another problem in my application by trying to do printing/print preview on my own.
I am trying to create a table that would look like in
this picture[
^].
I am using
C++
and
WinAPI
, on
WindowsXP SP3
. I work in
MS Visual Studio 2008
.
I do not have a printer, so I am testing the results by printing to MS OneNote
and XPS file
.
PROBLEM:
Text is obtained from database and is of variable length. Since it might not fit into the original cell, I will need to expand the cell and fit the text appropriately, like in the above image.
SIDE EFFECT:
The result of my testing code gives inconsistent results regarding font size.
In
OneNote the
print result[
^] seems fine, however, in
XPS it looks
different[
^].
MY EFFORTS TO SOLVE THIS TASK:
I have checked
MSDN documentation to get started. So far I am able to successfully draw text and lines on a printing surface.
I have used
DrawTextEx [
^] to perform word breaking ( by using flag
DT_WORDBREAK
).
To obtain the size of the printing area I have used
GetDeviceCaps[
^], and to obtain printer device context I have used
print property sheet[
^].
QUESTIONS:
IMPORTANT REMARKS:
If the following questions are considered too broad please leave a comment and I will edit my post. I still believe that my mistakes are minor and can be explained in a single post.
1. Can you explain me how to adjust cells so the entire string can fit ?
2. Why is my font inconsistently drawn ?
As always, here are the instructions for creating
SSCCE :
1) In Visual Studio, create
default Win32 project
.
2) in
stdafx.h
file
comment out #define WIN32_LEAN_AND_MEAN
so print property sheet can work properly.
3) In
stdafx.h
add the following, below
#include <windows.h>
line :
#include <windowsx.h>
#include <commctrl.h>
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")
4) Add the following function above window procedure :
HRESULT DisplayPrintPropertySheet(HWND hWnd)
{
HRESULT hResult;
PRINTDLGEX pdx = {0};
LPPRINTPAGERANGE pPageRanges = NULL;
pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
if (!pPageRanges)
return E_OUTOFMEMORY;
pdx.lStructSize = sizeof(PRINTDLGEX);
pdx.hwndOwner = hWnd;
pdx.hDevMode = NULL;
pdx.hDevNames = NULL;
pdx.hDC = NULL;
pdx.Flags = PD_RETURNDC;
pdx.Flags2 = 0;
pdx.ExclusionFlags = 0;
pdx.nPageRanges = 0;
pdx.nMaxPageRanges = 10;
pdx.lpPageRanges = pPageRanges;
pdx.nMinPage = 1;
pdx.nMaxPage = 1000;
pdx.nCopies = 1;
pdx.hInstance = 0;
pdx.lpPrintTemplateName = NULL;
pdx.lpCallback = NULL;
pdx.nPropertyPages = 0;
pdx.lphPropertyPages = NULL;
pdx.nStartPage = START_PAGE_GENERAL;
pdx.dwResultAction = 0;
hResult = PrintDlgEx(&pdx);
if ( ( hResult == S_OK )
&& ( pdx.dwResultAction == PD_RESULT_PRINT ) )
{
DOCINFO diDocInfo = {0};
diDocInfo.cbSize = sizeof( DOCINFO );
diDocInfo.lpszDocName = L"Testing printing...";
HFONT font, oldFont;
long lfHeight = -MulDiv( 14, GetDeviceCaps( pdx.hDC, LOGPIXELSY), 72 );
font = CreateFont( lfHeight,
0, 0, 0, FW_BOLD, TRUE, FALSE, FALSE, 0, 0, 0,
0, 0, L"Microsoft Sans Serif" );
oldFont = SelectFont( pdx.hDC, font );
SetBkMode( pdx.hDC, TRANSPARENT );
SetTextColor( pdx.hDC, RGB( 255, 0, 0 ) );
if( StartDoc( pdx.hDC, &diDocInfo ) > 0 )
{
if( StartPage( pdx.hDC ) > 0 )
{
int pageWidth, pageHeight;
pageWidth = GetDeviceCaps( pdx.hDC, HORZRES );
pageHeight = GetDeviceCaps( pdx.hDC, VERTRES );
for( int i = 0; i < pageWidth; i += pageWidth / 4 )
{
MoveToEx( pdx.hDC, i, 0, NULL );
LineTo( pdx.hDC, i, pageHeight );
}
for( int j = 0; j < pageHeight; j += pageWidth / 10 )
{
MoveToEx( pdx.hDC, 0, j, NULL );
LineTo( pdx.hDC, pageWidth, j );
}
RECT r;
r.left = 0;
r.top = 0;
r.right = 550;
r.bottom = 100;
FillRect( pdx.hDC, &r,
(HBRUSH)GetStockObject(LTGRAY_BRUSH) );
if( 0 == DrawTextEx( pdx.hDC,
L"This is test string!",
wcslen( L"This is test string!" ),
&r,
DT_CENTER | DT_WORDBREAK | DT_NOCLIP, NULL ) )
MessageBox( hWnd, L"DrawText failed!", L"Error", MB_OK );
if( EndPage( pdx.hDC ) < 0 )
MessageBox( hWnd, L"EndDoc failed!", L"Error", MB_OK );
}
EndDoc( pdx.hDC );
SelectFont( pdx.hDC, oldFont );
DeleteFont( font );
}
}
if (pdx.hDevMode != NULL)
GlobalFree(pdx.hDevMode);
if (pdx.hDevNames != NULL)
GlobalFree(pdx.hDevNames);
if (pdx.lpPageRanges != NULL)
GlobalFree(pPageRanges);
if (pdx.hDC != NULL)
DeleteDC(pdx.hDC);
return hResult;
}
5) In
WM_COMMAND
handler, modify
case IDM_ABOUT
like this :
case IDM_ABOUT: {
if( FAILED( DisplayPrintPropertySheet( hWnd ) ) )
MessageBox( hWnd,
L"Can't display print property sheet!",
L"Error", MB_OK );
}
break;
EDITED on June, 8th 2014 :
After the block
if ( ( hResult == S_OK ) && ( pdx.dwResultAction == PD_RESULT_PRINT ) )
in the submitted
SSCCE I have added the following for testing purposes :
int xDpi = GetDeviceCaps( pdx.hDC, LOGPIXELSX ),
yDpi = GetDeviceCaps( pdx.hDC, LOGPIXELSY );
int mapMode = GetMapMode( pdx.hDC );
wchar_t displayDPI[50];
swprintf_s( displayDPI, 50, L" xDPI = %s , yDPI = %s", xDpi, yDpi );
MessageBox( hWnd, displayDPI, L"", MB_OK );
switch( mapMode )
{
case MM_ANISOTROPIC:
MessageBox( hWnd, L"MM_ANISOTROPIC", L"", MB_OK );
break;
case MM_HIENGLISH:
MessageBox( hWnd, L"MM_HIENGLISH", L"", MB_OK );
break;
case MM_HIMETRIC:
MessageBox( hWnd, L"MM_HIMETRIC", L"", MB_OK );
break;
case MM_ISOTROPIC:
MessageBox( hWnd, L"MM_ISOTROPIC", L"", MB_OK );
break;
case MM_LOENGLISH:
MessageBox( hWnd, L"MM_LOENGLISH", L"", MB_OK );
break;
case MM_LOMETRIC:
MessageBox( hWnd, L"MM_LOMETRIC", L"", MB_OK );
break;
case MM_TEXT:
MessageBox( hWnd, L"MM_TEXT", L"", MB_OK );
break;
case MM_TWIPS:
MessageBox( hWnd, L"MM_TWIPS", L"", MB_OK );
break;
default:
MessageBeep(0);
break;
}
In both cases mapping mode was the same (
MM_TEXT
) but for
XPS I got
xDPI = 600 , yDPI = 600
in the
MessageBox
while
OneNote had
xDPI = 300 , yDPI = 300
.
This leads to the conclusion that with the same characteristics virtual printers will reproduce the same result. This also explains why
OneNote printed properly into
XPS when I tested it, and why my application failed. To solve this problem I need to find
DPI aware solution...
EDITED on June, 9th 2014 :
Using
GDI+
to create font and draw text I was able to get consistent results ( DPI is no longer a problem ). Still, if anyone knows how to achieve the same result using only
GDI
I would be still interested.
The only thing left for me is to draw a proper grid so the text can fit into cells properly.
EDITED on June, 10th 2014 :
After carefully reading through
this MSDN link[
^] I was able to alter the font creating code to achieve ( in my opinion ) stable results :
font = CreateFont(
lfHeight / ( GetDeviceCaps( pdx.hDC, LOGPIXELSY ) / 96 ),
0, 0, 0, FW_BOLD, TRUE, FALSE, FALSE, 0, 0, 0, 0, 0, L"Microsoft Sans Serif" );
Just to be safe, I will try to stick with
GDI+
but will update this post with the testing results when
GDI
and the mentioned equation is used in case someone else stumbles upon the same problem. I just hope it will save that persons time...