void CPrintview::MyPrintStart()
{
CView::OnFilePrint();
}
BOOL CPrintview::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
The call into MFC's CView gets to OnFilePrint() ok, but when
OnFilePrint() tries to call back to OnPreparePrinting(CPrintInfo*
pInfo), it can't find its' way back to my app and bombs out. I really
hate the idea of re-writing my whole app over again using the VC5
Wizard's Doc/View just to get it's 'free' printing. I really don't
want to do very much printing. Can anyone tell me:
1. how come it can't find it's way back to OnPreparePrinting?
2. is there an easier way to print a small (1 page) document without
using the MFC CView?
3. maybe point me to some code, Scribble is driving me nuts.
Printing using API is not hard (and it seems a lot easier than trying to hack
out a solution from MFC).
Use the PrintDlg() function to get a DC.
Use StartDoc() to start your document
while there are pages to print( use StartPage)
... draw page to DC
use EndPage
EndDoc
DeleteDC()
Or, if you want to print fancy text, colours, formating, images etc. without
the hassles of either MFC or API then why not use the HTML control I have
written - available from http://www.gipsysoft.com
Sorry for the blatant product plug<bg>.
--
ru...@gipsysoft.com
http://www.gipsysoft.com
QHTM, Small, light Win32 HTML control in just one 250k DLL.
Zoom+, The only screen magnifier a developer needs. It does it all.
Code-to-go - quality FREE source code, hints and tips.
>Russ,
>Thanks much, that was exactly what I needed. However you
>underestimated my stupidity and neglected to include directions for
>painting the DC. The VC5 no-Help file wants to tell me about printing
>with MFC, but it's pointedly not Helpful about printing from the API.
>Eventually I dug some code out of Petzold's Windows3.1 book that
>FINALLY got me some output on my rusty dusty printer. Dunno if that
>means it's gonna print on anybody's else's printer but I'll just write
>in MY Help file what kind of printer they gotta buy if they want to
>use my app. If you got any good out of your plug for your program,
>more power to you. Thanks again
You're missing the fact that Windows is a graphics
environment and all output is in graphics mode, whether
it is text or lines or rectangles. There's really no difference
in drawing a picture on the screen and drawing it to another
device such as the printer.
You should try to structure your code like this:
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
RECT rect;
GetClientRect(hwnd,&rect);
DrawMyPicture(hdc,&rect,hwnd);
EndPaint(hwnd,&ps);
break;
case WM_COMMAND/IDM_PRINT:
PRINTDLG pd;
pd.Flags=PD_RETURNDC | ...
...fill in rest of pd..
if(PrintDlg(&pd)){
StartDoc(...);
StartPage(...);
RECT rect;
rect.top=rect.left=0;
rect.right=GetDeviceCaps(pd.hDC,HORZRES);
rect.bottom=GetDeviceCaps(pd.hDC,VERTRES);
DrawMyPicture(pd.hDC,&rect,NULL);
EndPage(...);
EndDoc(...);
DeleteDC(hdc);
}
break;
If you don't want the dialog box to appear and you're
happy with an HDC for the default printer, you can also
use PD_RETURNDEFAULT.
Your DrawMyPicture() function is provided with an HDC
and RECT in which to draw the picture. You don't even
have to know whether the user selected portrait or
landscape in the PrintDlg(0 dialog box - just retrieve
the dimensions and draw in the RECT. The HWND (or
NULL) is provided in case you need to know whether you
are drawing on the screen or not. Most of the time you
really don't have to know that.
Note that I have simplified this, assuming that there
is a 1-1 correspondence between the screen picture
and the printer picture. Obviously, you'll need to structure
it differently if it's a text application - the screen will only
show part of it (with scrollbars) and the printer routine
will have to loop through each page.
But you should never have code that's specific to one
type of printer. If you code it properly, it should work
on all output devices, both video & printer.
--
John A. Grant * I speak only for myself * (remove 'z' to reply)
Airborne Geophysics, Geological Survey of Canada, Ottawa
If you followup, please do NOT e-mail me a copy: I will read it here
But... my problem is that I began in MFC without using a Doc/View
architecture because I didn't intend to have a document on screen. In
fact I don't display a main window, just start right off calling up a
Dialog box, and run everything from there. So when I decided to add
printing I anticipated printing from a file (instead of the Edit boxes
in my Dialog box, cause I'll be printing more than one record). So my
hDC will be peopled by TextOut()s. I guess that in GDI this is a type
of 'drawing', and I know that I have to keep track of coordinates, but
I think of it as just printing.
I expect I'll know a lot more about C++ Windows printing when I'm done
with this. Heck, I already do.
Earl
>Again, thanks for the instruction for the C++ newbie. I was kidding
>about my stuff not working on 'other' printers... but not entirely. I
>just don't have 100% confidence that it'll run on any printer but mine
>when I get done. I guess that your:
>case WM_COMMAND/IDM_PRINT
>denotes a menu click that the WindowProc intercepts?
Yes, I mean the 'Print' command, however you decide to
implement it, usually File | Print ...
I've been doing
>it a little different in MFC. I couldn't find documentation of that
>IDM/PRINT anyplacer. I'm gonna push a button on my Dialog box.
A 'Print' button in a dialog box that initiates printing is fine.
>But... my problem is that I began in MFC without using a Doc/View
>architecture because I didn't intend to have a document on screen. In
>fact I don't display a main window, just start right off calling up a
>Dialog box, and run everything from there.
That's ok.
>>So when I decided to add
>printing I anticipated printing from a file (instead of the Edit boxes
>in my Dialog box, cause I'll be printing more than one record). So my
>hDC will be peopled by TextOut()s. I guess that in GDI this is a type
>of 'drawing', and I know that I have to keep track of coordinates, but
>I think of it as just printing.
>
>I expect I'll know a lot more about C++ Windows printing when I'm done
>with this. Heck, I already do.
It has little to do with "C++" and little to do with "printing".
It's just basic Windows programming. The fact that the
output device is a piece of paper isn't really very relevant
to what you're doing.
TextOut() is really no different than Rectangle(), in that they
are both GDI graphics functions. They should operate the
same for an HDC connected to any device.
If you're trying to print the contents of the "edit" control,
you might want to use DrawText(), which can do a
signficant amount of formatting for you.
It sounds like you're jumping into the middle of Windows
programming without having learned some of the basics.
I strongly recommend that you get a copy of "Programming
Windows ..." by Charles Petzold (Microsoft Press). This is
the classic book for learning Windows programming and is
recommended by everyone. You should learn from it, even
if you plan to use MFC. The examples are excellent and
are provided on disk in both source & EXE form.
If you get Petzold's book, he goes through the development
of a Notepad-like editor and has various discussions on
displaying text
CHOOSEFONT cf;
LOGFONT lf;
GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT),(LPSTR) &lf);
cf.lStructSize=sizeof(CHOOSEFONT);
cf.hwndOwner=hCRemindWindow;
cf.lpLogFont=&lf; //lf is supposed to return loaded with users
font choices after cf dialog.
cf.Flags=CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_BOTH |
CF_NOVECTORFONTS|CF_TTONLY;
PrintDlg(&lppd); //get print dialog box
cf.hDC=lppd.hDC; //set choosefont member to printer device context.
ChooseFont( &cf );
SetMapMode(lppd.hDC,MM_TEXT);
HGDIOBJ result=SelectObject(lppd.hDC, CreateFontIndirect(&lf));
//select font into printer DC.
// 'result' now equals to 0x98. Don't know what that tells me.
GetTextMetrics(lppd.hDC,&tm);
cxChar=tm.tmAveCharWidth; //stays the same whether I do the
SelectObject or not.
TextOut(lppd.hDC,0,800,"This dog won't hunt",18);
Can anybody give me a clue what I'm doing wrong?
There's too much unchecked code in there to sort out.
I suggest that you break it down into stages and check
each function call for sucess/fail. Check the function
return values and use GetLastError() to get the specific
error.
(a) is the initial font in ChooseFont() reasonable?
(b) does CreateFontIndirect() work ok?
(c) whenever you use SelectObject(), it returns an
object of the same type. You hang onto that object
and put it back when you are done:
HFONT hfont=CreateFont(...);
hfont=(HFONT)SelectObject(hdc,hfont);
...draw some text...
hfont=(HFONT)SelectObject(hdc,hfont);
DeleteObject(hfont);
(d) To ensure your code works always, you should use
ZeroMemory() to clear the CHOOSEFONT struct, even
if you are setting all of the members explicitly. In future
versions, CHOOSEFONT may have more members
and your code won't be initializing them.
(e) Presumably, some place in your code, you are
doing the following sequence:
StartDoc()
StartPage()
EndPage()
EndDoc()
Read the docs for StartPage() & EndPage() so that
you are aware of the differences between W95 & WNT
for initializing the HDC.
after user chooses font, setting Arial 24 points
cf.lp.LogFont.lfHeight -40
Width 0
Escapement 0
lfPitchAndFamily 34""
lfFaceName 0x00064F4E0 "Arial"
iPointsize 240
I dunno, do they make sense?
>
> (b) does CreateFontIndirect() work ok?
>
I made 2 statements:
HFONT myfont=CreateFontIndirect(&lf);
returns 0x0F14 into myfont.
HGDIOBJ result=SelectObject(lppd.hDC,myfont);
returns 0x98 into result.
I *THINK* these are likely values.
> (d) To ensure your code works always, you should use
> ZeroMemory() to clear the CHOOSEFONT struct, even
I used your ZeroMemory() tip after creating the PrintDialog structure,
the CHOOSEFONT structure and the LOGFONT structure. VERY HANDY,
thanks, but no help to problem.
> Read the docs for StartPage() & EndPage() so that
> you are aware of the differences between W95 & WNT
> for initializing the HDC.
I looked at the StartPage/Win95/NT differences in the documentation. I
routinely work in Win98, as my modem and some other stuff don't work
in NT4. So when I test in NT4 I fall into all those traps. Would make
more sense to play in NT4, but would need to buy more hardware to do
it.
All my function returns LOOK normal to me. I don't know how to 'look'
at the hdc to see what I've actually got it set up to. I guess the
thing that would make most sense is to make it print to the screen,
before using it on the printer, but that little troubleshoot angle
will take me another day or two at my speed.
I'm using an old Epsom LQ570+ dot-matrix printer, I wonder if there's
anything extra you have to do to print windows fonts on this animal?
Earl
> (c) whenever you use SelectObject(), it returns an
> object of the same type. You hang onto that object
> and put it back when you are done:
> HFONT hfont=CreateFont(...);
> hfont=(HFONT)SelectObject(hdc,hfont);
> ...draw some text...
> hfont=(HFONT)SelectObject(hdc,hfont);
> DeleteObject(hfont);
>
> if you are setting all of the members explicitly. In future
Don't get too caught up in the actual value of the handles
(HDC, HFONT etc). You're not really supposed to know what
they are - just get them and pass them around between functions.
The only thing you need to know is if they are NULL or not.
NULL is an indication that something's wrong :)
Anyway, you seem to be creating & selecting the various
objects ok.
I haven't used a dot-matrix printer for 10 years. I don't
know if there are any problems printing particular fonts on
them or not. Perhaps you need to test your app on another
printer to resolve this.
I'm a bit concerned about the use of "lppd" as the name of
the struct. How have you declared this variable? I hope you
haven't done this:
LPPRINTDLG lppd;
PrintDlg(&lppd);
"lp" means "long pointer" and is a throwback to ye olden
dayes, when Win16 apps could be created with a choice
of several memory models.
This is correct:
PRINTDLG pd;
...
PrintDlg(&pd);
In my app's CHOOSEFONT I use
cf.Flags=CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_BOTH |
CF_NOVECTORFONTS|CF_TTONLY;
If I use
cf.Flags=CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_PRINTERFONTS |
CF_NOVECTORFONTS|CF_TTONLY;
the OS tells me no fonts are loaded, "open Control Panel | Fonts and
load some"
In ControlPanel I find, of course, scads of fonts in the Font folder.
Perhaps the problem is telling my app that they do exist. A path
statement somewhere? Can't find anything like LoadFont or GetFont in
the API. One of the arcane VC5 Project Settings?
Earl
On Thu, 17 Jun 1999 22:01:09 -0400, "John A. Grant"
<zjag...@znrcanz.gcz.ca> wrote:
>
> I haven't used a dot-matrix printer for 10 years. I don't
> know if there are any problems printing particular fonts on
> them or not. Perhaps you need to test your app on another
> printer to resolve this.
>
> I'm a bit concerned about the use of "lppd" as the name of
> the struct. How have you declared this variable? I hope you
> haven't done this:
> LPPRINTDLG lppd;
> PrintDlg(&lppd);
>
> "lp" means "long pointer" and is a throwback to ye olden
> dayes, when Win16 apps could be created with a choice
> of several memory models.
>
> This is correct:
> PRINTDLG pd;
> ...
> PrintDlg(&pd);
Thanks for the suggestions. I tried the PRINTDLG pd; - no help. Not
quite ready to beg somebody's else's printer yet. I may be driving you
nuts, but I AM picking up nice little tidbits along the way, thanks
again.
>John,
>Perhaps the light begins to dawn... faintly.
>I observed that the VC5 SuperPad sample uses 2 different ways to set
>the font, one for the screen and one for the printer. I couldn't trace
>into MFC far enough to see what they're doing, API wise.
>
>In my app's CHOOSEFONT I use
>cf.Flags=CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_BOTH |
>CF_NOVECTORFONTS|CF_TTONLY;
>If I use
>cf.Flags=CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_PRINTERFONTS |
>CF_NOVECTORFONTS|CF_TTONLY;
>the OS tells me no fonts are loaded, "open Control Panel | Fonts and
>load some"
>
>In ControlPanel I find, of course, scads of fonts in the Font folder.
>Perhaps the problem is telling my app that they do exist. A path
>statement somewhere? Can't find anything like LoadFont or GetFont in
>the API. One of the arcane VC5 Project Settings?
>Earl
I had a quick look at superpad - I think it just keeps a
separate font for screen & printer, otherwise the mechanism
is the same.
Try using WordPad to print some text in a variety of fonts,
including Arial & System. If it works on your printer, then you
know your printer is capable of doing it. That will eliminate
the hardware & driver.
I really don't know the difference between printer & screen
fonts. There are 3 flags:
CF_SCREENFONTS
CF_PRINTERFONTS
CF_BOTH (=CF_SCREENFONTS | CF_PRINTERFONTS)
If you don't use one of those flags, presumably it won't list
any fonts!
I'm getting confused now. You don't want to put StartDoc() in
ALL of the functions! Can you post the sequence of function
calls you're using? It should look something like this:
PrintDlg() with CF_RETURNDC
ChooseFont() with printer HDC
StartDoc()
StartPage()
...print some text...
EndPage()
EndDoc()
When you select the font into the HDC, you need to be
aware that the HDC might be reset for each page, but it's
different for W31, W95 & WNT. It's conceivable that your
HDC is being reset and you're losing your selected font.
Read the docs on StartPage() or EndPage().
Note that you only supply an HDC for ChooseFont()
if you use CF_PRINTERFONTS or CF_BOTH. In other
words, ChooseFont() doesn't need an HDC if it is only
enumerating fonts for the screen. Otherwise, it needs the
HDC. Presumably, it won't list all printer fonts, just those
that are compatible with the printer for which the HDC is
provided.
On Fri, 18 Jun 1999 17:33:52 -0400, "John A. Grant"
<zjag...@znrcanz.gcz.ca> wrote:
> Try using WordPad to print some text in a variety of fonts,
> including Arial & System. If it works on your printer, then you
> know your printer is capable of doing it. That will eliminate
> the hardware & driver.
John,
WordPad (and SuperPad also) does allow me to change font size on my
dot-matrix printer.
In my last post I said I could not use
cf.Flags= CF_PRINTERFONTS
I found if I moved the ChooseFont() to after the PrintDlg() that the
OS would accept the CF_PRINTERFONTS.
I decided to examine TextMetric members after my machinations.
GetTextMetrics(pd.hDC,&tm);
ebptr1->SetWindowText(itoa(tm.tmHeight,temp,10));//write char height
//to an EditBox.
After selecting Arial, size 8 font, tm.tmHeight equals 16
After selecting Arial, size 24 font, tm.tmHeight equals 46
so the TextMetrics for the printer DC *DO* change size, but the
printer still insists on printing the same-dimensioned characters.
about this:
s= StartDoc(pd.hDC,&di); //but I have set DOCINFO di members to
ficticious values. Don't think they matter?
Thought maybe the mix of MFC and API was confusing something so put
::StartDoc(), etc in all the functions - no help.
Earl
PRINTDLG pd;
ZeroMemory(&pd,sizeof(pd));
HWND hCRemindWindow;
hCRemindWindow=CRemindDialog::GetSafeHwnd();
pd.Flags=PD_RETURNDC;
pd.hwndOwner=hCRemindWindow;
pd.nFromPage=0;
pd.nToPage=0;
pd.nMinPage=0;
pd.nMaxPage=0;
pd.nCopies=1;
pd.hDevMode=NULL;
pd.hDevNames=NULL;
pd.lStructSize=sizeof(pd);
pd.hDC=NULL;
pd.hInstance=NULL;
pd.lCustData=0L;
pd.lpfnPrintHook=NULL;
pd.lpfnSetupHook=NULL;
pd.lpPrintTemplateName=NULL;
pd.lpSetupTemplateName=NULL;
pd.hPrintTemplate=NULL;
pd.hSetupTemplate=NULL;
CHOOSEFONT cf;
LOGFONT lf;
int test;
ZeroMemory(&cf,sizeof(cf));
ZeroMemory(&lf,sizeof(lf));
cf.hDC=pd.hDC;
test=GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT),(LPSTR)
&lf);
cf.lStructSize=sizeof(CHOOSEFONT);
cf.hwndOwner=hCRemindWindow;
cf.lpLogFont=&lf;//lf supposed to come back loaded with users font
choices after cf dialog.
cf.Flags=CF_INITTOLOGFONTSTRUCT | CF_EFFECTS | CF_PRINTERFONTS |
CF_NOVECTORFONTS|CF_TTONLY;
TEXTMETRIC tm;
int cxChar, cxCaps,cyChar,xPage,yPage;
int xcursor, ycursor;
xcursor=ycursor=0;
GetTextMetrics(pd.hDC,&tm);
char temp[5];
ebptr1->SetWindowText(itoa(tm.tmHeight,temp,10));
if(::PrintDlg(&pd))
{
cf.hDC=pd.hDC;//do it again after PrintDlg has been done.
::ChooseFont( &cf );
cf.hDC=pd.hDC;//do this again to make sure.
DOCINFO di;
di.cbSize=sizeof(di);
di.lpszOutput=NULL;
di.lpszDatatype =NULL;
di.fwType=0;
di.lpszDocName=NULL;
HFONT myfont=::CreateFontIndirect(cf.lpLogFont);
HGDIOBJ result=::SelectObject(pd.hDC,myfont);
//HGDIOBJ result=SelectObject(pd.hDC,
//CreateFontIndirect(&lf));
::SetMapMode(pd.hDC,MM_TEXT);
xPage=GetDeviceCaps(pd.hDC,HORZRES);
yPage=GetDeviceCaps(pd.hDC,VERTRES);
::GetTextMetrics(pd.hDC,&tm);
cxChar=tm.tmAveCharWidth;
cxCaps=(tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar/2;
cyChar=tm.tmHeight + tm.tmExternalLeading;
ebptr1->SetWindowText(itoa(tm.tmHeight,temp,10));//after load
//new font in.
s= ::StartDoc(pd.hDC,&di);//&di
s=::StartPage(pd.hDC);
::TextOut(pd.hDC,0,800,"This dog won't hunt",10);
::EndPage(pd.hDC);
::EndDoc(pd.hDC);
DeleteDC(pd.hDC);
}
> When you select the font into the HDC, you need to be
> aware that the HDC might be reset for each page, but it's
> different for W31, W95 & WNT. It's conceivable that your
> HDC is being reset and you're losing your selected font.
> Read the docs on StartPage() or EndPage().
>
Perhaps the HDC is getting reset after StartDoc(), will check it again
with GetTextMetrics after StartPage() and see if it changes.
> Note that you only supply an HDC for ChooseFont()
> if you use CF_PRINTERFONTS or CF_BOTH. In other
> words, ChooseFont() doesn't need an HDC if it is only
> enumerating fonts for the screen. Otherwise, it needs the
> HDC. Presumably, it won't list all printer fonts, just those
> that are compatible with the printer for which the HDC is
> provided.
Actually, I didn't even intend to include ChooseFont() in working
edition of the app, I just wanted legit values to load into the
LOGFONT structure. But... I do want something better than the
DOS-type-looking output the printer gives me now when I can't choose a
font.
I went into NT (had been putting this off as I was anticipating a
lotta stuff not working in NT). As a matter of fact it probably
doesn't, but the size of the printer font on my printer paper WOULD
change. I selected Arial size 72 points and it delivered a capital 'T'
about ź"" tall. Which is a lot smaller than I had anticipated, but it
WOULD change size, and give me Windows printing instead of 'DOS'
printing.
Went back to Win98. Selected my font into the printer DC AFTER the
StartPage(), thus:
s=::StartPage(pd.hDC);
result=SelectObject(pd.hDC, CreateFontIndirect(&lf));//select font
//into printer DC.
Now the printer would deliver Windows printing, however this time an
Arial size 72 capital 'T' was ˝" tall. That size difference is another
can of worms, but at least I believe the major bottleneck that has
bugged me for a week is gone.
Thanks much for your help and support John, couldn't have done it
without you. Matter of fact, I couldn't make any sense of the StartDoc
escape commands until the 1st guy who replied to be on this board
clued me in.
If I had to do this stuff for a living I'd be starving in an attic.
Earl
[...]
>Went back to Win98. Selected my font into the printer DC AFTER the
>StartPage(), thus:
>s=::StartPage(pd.hDC);
>result=SelectObject(pd.hDC, CreateFontIndirect(&lf));//select font
>//into printer DC.
[...]
That's what I was trying to tell you - do it on a per page
basis. But you don't need to create the font for each page.
Make sure you delete the HFONT when no longer required.