|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Page CountI am using the following snippet. 'snippet. x = Printer.ScaleWidth / 2 A$ = "(" & Printer.Page & ")" Printer.CurrentX = x - Printer.TextWidth(A$) / 2 Printer.Print A$ Question: Is there a way to find out the total page count so I can do the following? x = Printer.ScaleWidth / 2 A$ = "(" & Printer.Page & ") of (" & ???? & ")" Printer.CurrentX = x - Printer.TextWidth(A$) / 2 Printer.Print A$ -- Thanks in advance bob rober***@mountaincable.net "Robert" <rober***@mountaincable.net> wrote in message There are various different ways of getting a page count without actually news:%23juPUlSLIHA.4688@TK2MSFTNGP06.phx.gbl... > Is there a way to find out the total page count so I can > do the following? > A$ = "(" & Printer.Page & ") of (" & ???? & ")" printing the stuff so that you can print your page numbers in that specific way. It all depends what you are printing. What exactly are you printing, and how are you currently printing it? You need to be *very* specific. Mike
Show quote
"Robert" <rober***@mountaincable.net> wrote in message Using the Printer object, no, not without "pre-printing" because you're news:%23juPUlSLIHA.4688@TK2MSFTNGP06.phx.gbl... >I am using VB 6.0 SP5. > > I am using the following snippet. > > 'snippet. > x = Printer.ScaleWidth / 2 > A$ = "(" & Printer.Page & ")" > Printer.CurrentX = x - Printer.TextWidth(A$) / 2 > Printer.Print A$ > > Question: > Is there a way to find out the total page count so I can do the following? > > x = Printer.ScaleWidth / 2 > A$ = "(" & Printer.Page & ") of (" & ???? & ")" > Printer.CurrentX = x - Printer.TextWidth(A$) / 2 > Printer.Print A$ basically printing on-the-fly. So, at any given point, there's no way for the Printer object to know how much more is going to get printed and thus provide a total page count. One relatively easy way is to substitute a PictureBox control array (each picbox in the array is a page) for the Printer object. You need to be sure to setup the picboxes to match the Printer object's settings...for example Width, Height, ScaleWidth, ScaleHeight, Font, etc. Instead of using NewPage, load another picbox into the control array. Then, your total page count is simply the number of picboxes you have in the control array. It takes a little bit of work, but it's not that bad. What I do is have a single routine for printing, and pass to it a Boolean indicating whether to print or print preview. -- Mike Microsoft MVP Visual Basic On Thu, 22 Nov 2007 22:06:31 -0500, "MikeD" <nob***@nowhere.edu> wrote: in <ejHzZ3XLIHA.3***@TK2MSFTNGP02.phx.gbl> Show quote > Doesn't that use an awful lot of memory?>"Robert" <rober***@mountaincable.net> wrote in message >news:%23juPUlSLIHA.4688@TK2MSFTNGP06.phx.gbl... >>I am using VB 6.0 SP5. >> >> I am using the following snippet. >> >> 'snippet. >> x = Printer.ScaleWidth / 2 >> A$ = "(" & Printer.Page & ")" >> Printer.CurrentX = x - Printer.TextWidth(A$) / 2 >> Printer.Print A$ >> >> Question: >> Is there a way to find out the total page count so I can do the following? >> >> x = Printer.ScaleWidth / 2 >> A$ = "(" & Printer.Page & ") of (" & ???? & ")" >> Printer.CurrentX = x - Printer.TextWidth(A$) / 2 >> Printer.Print A$ > >Using the Printer object, no, not without "pre-printing" because you're >basically printing on-the-fly. So, at any given point, there's no way for >the Printer object to know how much more is going to get printed and thus >provide a total page count. One relatively easy way is to substitute a >PictureBox control array (each picbox in the array is a page) for the >Printer object. You need to be sure to setup the picboxes to match the >Printer object's settings...for example Width, Height, ScaleWidth, >ScaleHeight, Font, etc. Instead of using NewPage, load another picbox into >the control array. Then, your total page count is simply the number of >picboxes you have in the control array. It takes a little bit of work, but >it's not that bad. What I do is have a single routine for printing, and pass >to it a Boolean indicating whether to print or print preview. --- Stefan Berglund "Stefan Berglund" <sorry.no.kool***@for.me> wrote in message Only temporarily....and it's not an extraordinary amount. Of course, it news:poqck3hd1vuisudp9gq2hi9demn1oidm2o@4ax.com... > > Doesn't that use an awful lot of memory? > depends on how much you're printing. -- Mike Microsoft MVP Visual Basic "MikeD" <nob***@nowhere.edu> wrote in message Actually that approach sometimes doesn't work very well and is unreliable, news:ejHzZ3XLIHA.3916@TK2MSFTNGP02.phx.gbl... > Using the Printer object, no, not without "pre-printing" because > you're basically printing on-the-fly. So, at any given point, there's > no way for the Printer object to know how much more is going > to get printed and thus provide a total page count. One relatively > easy way is to substitute a PictureBox control array (each picbox > in the array is a page) for the Printer object. You need to be sure > to setup the picboxes to match the Printer object's settings...for > example Width, Height, ScaleWidth, ScaleHeight, Font, etc. > Instead of using NewPage, load another picbox into . . . and in some cases you can end up printing "1 of 3", "2 of 3", "3 of 3", "4 of 3" on some documents. There are various reasons for this, but the main one is the fact that you often do not get exactly the same font size and text height (or text width) on the printer as you do on the picture box (or other screen device) because of the widely different dpi resolutions and because of the fact that both the width and the height of characters are constrained to whole device pixel values. Therefore, lines of text are likely to wrap at different "end of line" words and also the height of the lines of text themselves are likely to be different on the printer than they are on the picture box. To do the job accurately you really need to perform all calculations and base all your "next printed line" and "next page" decisions on the values returned by the actual target device (the printer). There are various different ways of doing this, depending on exactly what the OP is printing, which is why I asked him for further details. One very simple way (which incidentally I would not recommend because it might be troublesome on some printers) is to print your document to the printer on the "dummy run that counts the pages" in the normal way but to end the print job with Printer.KillDoc instead of Printer.EndDoc, and then follow that with a normal print run. However, I really wouldn't recommend doing it that way. There are of course various other methods that work very well, but the choice of method to use will depend a lot on what the OP is printing and how he is currently wrapping his blocks of text (or whatever he is printing). Something somewhere in his code is deciding which word to wrap each line on and which line to start a new page on. All the OP needs to do is tap into that on the "dummy run" by adding up the various widths and heights on the target device (the printer) without actually printing them. By the way, when performing such a task in any stuff you are wrapping yourself in standard VB code you should always use GetTextExtentPoint32 rather than the VB TextHeight and TextWidth functions because TextHeight and TextWidth are not usually totally accurate on devices which do not have a whole number of twips per pixel. TextHeight and TextWidth are usually okay on the screen and on most Epson printers, but they often return slightly inaccurate values on HP printers and various others, whereas GetTextExtentPoint32 is always accurate. Anyway, I'm assuming that the OP will eventually post back with further details. Mike
Show quote
"Mike Williams" <mi***@whiskyandCoke.com> wrote in message All I can say is that I've used it for years and never had any major issues.news:%23seQ2caLIHA.5116@TK2MSFTNGP03.phx.gbl... > "MikeD" <nob***@nowhere.edu> wrote in message > news:ejHzZ3XLIHA.3916@TK2MSFTNGP02.phx.gbl... > >> Using the Printer object, no, not without "pre-printing" because >> you're basically printing on-the-fly. So, at any given point, there's >> no way for the Printer object to know how much more is going >> to get printed and thus provide a total page count. One relatively >> easy way is to substitute a PictureBox control array (each picbox >> in the array is a page) for the Printer object. You need to be sure >> to setup the picboxes to match the Printer object's settings...for >> example Width, Height, ScaleWidth, ScaleHeight, Font, etc. >> Instead of using NewPage, load another picbox into . . . > > Actually that approach sometimes doesn't work very well and is unreliable, > and in some cases you can end up printing "1 of 3", "2 of 3", "3 of 3", "4 > of 3" on some documents. -- Mike Microsoft MVP Visual Basic "MikeD" <nob***@nowhere.edu> wrote in message Yes. In many cases such a technique actually will come up with the correct news:unZd4xdLIHA.5468@TK2MSFTNGP05.phx.gbl... > All I can say is that I've used it for years and never > had any major issues. number of pages, but there are times when it will not, because of the sometimes different word wrapping points which can result in a different number of lines being printed on one device than on the other and also because of sometimes different height of each line of text. If the last line of text on the last "page" in the Picture Box happens to end up somewhere in the region from 5 percent to 95 per cent or so of the overall printing height then it is likely (but not certain) that the number of "pages" in the Picture Box will be the same as the number of pages on the printer, but otherwise (if it is in either the top or the bottom 5 per cent of the overall printing height) there is a fair chance that the number of pages will be different. So in most cases, as you have discovered, you can get away with it, but sooner or later you will end up printing and possibly sending out to a customer a document that has "1 of 7" etc for the page numbers but that actually has 6 pages, or perhaps 8. Mike
Show quote
"Mike Williams" <mi***@whiskyandCoke.com> wrote in message Never happened to me yet...or at least never reported to me yet. I'll stick news:%23Tzm8beLIHA.5360@TK2MSFTNGP03.phx.gbl... > "MikeD" <nob***@nowhere.edu> wrote in message > news:unZd4xdLIHA.5468@TK2MSFTNGP05.phx.gbl... > >> All I can say is that I've used it for years and never >> had any major issues. > > Yes. In many cases such a technique actually will come up with the correct > number of pages, but there are times when it will not, because of the > sometimes different word wrapping points which can result in a different > number of lines being printed on one device than on the other and also > because of sometimes different height of each line of text. If the last > line of text on the last "page" in the Picture Box happens to end up > somewhere in the region from 5 percent to 95 per cent or so of the overall > printing height then it is likely (but not certain) that the number of > "pages" in the Picture Box will be the same as the number of pages on the > printer, but otherwise (if it is in either the top or the bottom 5 per > cent of the overall printing height) there is a fair chance that the > number of pages will be different. So in most cases, as you have > discovered, you can get away with it, but sooner or later you will end up > printing and possibly sending out to a customer a document that has "1 of > 7" etc for the page numbers but that actually has 6 pages, or perhaps 8. with what I got for now and cross that bridge when and if I ever have to. But, what you say does indeed make sense. -- Mike Microsoft MVP Visual Basic "MikeD" <nob***@nowhere.edu> wrote in message Pre-counting the pages using the method I suggested (using GetTextExtent and news:%232d1dKkLIHA.5328@TK2MSFTNGP05.phx.gbl... > Never happened to me yet [incorrect page number > calculation] ...or at least never reported to me yet. > I'll stick with what I got for now and cross that bridge > when and if I ever have to. > But, what you say does indeed make sense. DrawText and stuff and simply adding up the coordinates on a dummy run without actually printing it) returns an accurate result and works well and does not require a great deal of extra code, but I must admit that I don't often use that approach myself any more. If I want to print a document in such a way that I can do things like "Page 1 of 7" etc and if the document is suitable for insertion in a RichTextBox (mostly text and not much graphics) then I draw the whole document into a RichTextBox and use the various RTB methods and messages to perform the task using my own modification of some RTB WYSYWIG code that I came across on MSDN somewhere. The WSYWIG part is a bit "messy" though and not very flexible for most purposes, and so these days I only use the RTB method when I want "Page 1 of 7" and headers and footers etc in a multipage document and I don't actually want any print preview. When printpreview is required I prefer to create the individual pages as metafiles (emf). This method allows you to easily print the pages when required by simply sending the "page metafiles" to the printer and it allows very flexible print preview because you can send the same metafiles to a Picture Box or whatever and they will draw as an exact copy of the page at any desired size you wish (full page, actual size with scrolling, reduced size, zoom and pan, or whatever you wish) and the lines of text on the display will wrap at exactly the same words as they do on the printer with each page having exactly the same number of lines as it does on the printer. I've only got the "bare bones" of that method going at the moment (although it works fine as far as I've taken it) but if you are interested in the RichTextBox method then here's an example. There are two blocks of code, one for a module and the other for a Form containing a RichTextBox and a Command Button. Run the program and paste a few pages worth of stuff (from a MS Word document or whatever) into the RTB and then click the button: Mike ' *** START OF FORM CODE *** Option Explicit ' (By Mike Williams) Code to print a multipage document ' from a RichTextBox with user selectable all round ' page margins and with page numbers and headers/footers Private Sub PrintRTB(RTB As RichTextBox, _ marginsize As Single, footer As String) Dim charsToPrint As Long, nextChar As Long Dim pageWide As Single, pageHigh As Single Dim margin As Single, printControl As Boolean Dim nPage As Long, totalPages As Long Dim header As String charsToPrint = Len(RichTextBox1.Text) If charsToPrint < 1 Then Exit Sub Printer.Orientation = vbPRORPortrait Printer.Print ' always start a print job with this With Printer .ScaleMode = vbInches .Font.Name = "Times new Roman" ' font for header/footer .Font.Size = 10 pageWide = .ScaleX(.Width, vbTwips, vbInches) pageHigh = .ScaleY(.Height, vbTwips, vbInches) End With margin = marginsize SetPrinterOrigin 0, 0 ' only required for VB methods nextChar = 0: totalPages = 0 printControl = False 'Don't print, just count the pages Do nextChar = PrintRTF(RichTextBox1, margin, margin, _ pageWide - margin * 2, pageHigh - margin _ * 2, nextChar, printControl) totalPages = totalPages + 1 Loop Until (nextChar > charsToPrint) Or nextChar = 0 nextChar = 0: nPage = 0 printControl = True ' actually print the stuff Do With Printer .Font.Italic = True .CurrentY = pageHigh - 0.5 - Printer.TextHeight(footer) ' I've had occasional problems with .TextWidth in ' a With Printer block in Vista, which is why I've ' used Printer.TextWidth below .CurrentX = pageWide / 2 - Printer.TextWidth(footer) / 2 Printer.Print footer; nPage = nPage + 1 header = "Page " & Format(nPage) & _ " of " & Format(totalPages) .Font.Italic = False .CurrentY = 0.5 'pageHigh - 0.6 .CurrentX = (pageWide - Printer.TextWidth(footer)) / 2 Printer.Print header; nextChar = PrintRTF(RichTextBox1, margin, margin, _ pageWide - margin * 2, pageHigh - _ margin * 2, nextChar, printControl) If nextChar <= charsToPrint Then Printer.NewPage End If End With Loop Until (nextChar > charsToPrint) Or nextChar = 0 Printer.EndDoc End Sub Private Sub Command1_Click() ' Print RTB with a one inch all round margin for the ' body (the header and footer positions are hard ' coded into the function at the moment, but that can ' of course be changed later). PrintRTB RichTextBox1, 1, "Drink rum responsibly." End Sub ' *** END OF FORM CODE *** ' ' ' ' *** START OF MODULE CODE *** Option Explicit Private Declare Function GetDeviceCaps Lib "gdi32" _ (ByVal hdc As Long, ByVal nIndex As Long) As Long Public Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" (ByVal hwnd As Long, _ ByVal msg As Long, ByVal wp As Long, lp As Any) As Long Private Type Rect Left As Long Top As Long Right As Long Bottom As Long End Type Private Type CharRange cpMin As Long cpMax As Long End Type Private Type FormatRange hdc As Long hdcTarget As Long rc As Rect rcPage As Rect chrg As CharRange End Type Private Const WM_USER As Long = &H400 Private Const EM_FORMATRANGE As Long = WM_USER + 57 Private Const EM_SETTARGETDEVICE As Long = WM_USER + 72 Private Const PHYSICALOFFSETX As Long = 112 Private Const PHYSICALOFFSETY As Long = 113 Public Sub SetPrinterOrigin(x As Single, y As Single) With Printer .ScaleLeft = .ScaleX(GetDeviceCaps(.hdc, PHYSICALOFFSETX), _ vbPixels, .ScaleMode) - x .ScaleTop = .ScaleY(GetDeviceCaps(.hdc, PHYSICALOFFSETY), _ vbPixels, .ScaleMode) - y .CurrentX = 0 .CurrentY = 0 End With End Sub Public Function PrintRTF(RTF As RichTextBox, x1 As Single, _ y1 As Single, Wide As Single, High As Single, _ charPos As Long, printControl As Boolean) As Long Dim LeftOffset As Long, TopOffset As Long Dim LeftMargin As Long, TopMargin As Long Dim RightMargin As Long, BottomMargin As Long Dim fr As FormatRange, rcDrawTo As Rect Dim rcPage As Rect Dim NextCharPosition As Long, r As Long LeftOffset = Printer.ScaleX(GetDeviceCaps(Printer.hdc, _ PHYSICALOFFSETX), vbPixels, vbTwips) TopOffset = Printer.ScaleY(GetDeviceCaps(Printer.hdc, _ PHYSICALOFFSETY), vbPixels, vbTwips) LeftMargin = Printer.ScaleX(x1, Printer.ScaleMode, _ vbTwips) - LeftOffset TopMargin = Printer.ScaleY(y1, Printer.ScaleMode, _ vbTwips) - TopOffset RightMargin = LeftMargin + Printer.ScaleX(Wide, _ Printer.ScaleMode, vbTwips) BottomMargin = TopMargin + Printer.ScaleY(High, _ Printer.ScaleMode, vbTwips) rcPage.Left = 0 rcPage.Top = 0 rcPage.Right = Printer.ScaleX(Printer.ScaleWidth, _ Printer.ScaleMode, vbTwips) rcPage.Bottom = Printer.ScaleY(Printer.ScaleHeight, _ Printer.ScaleMode, vbTwips) rcDrawTo.Left = LeftMargin rcDrawTo.Top = TopMargin rcDrawTo.Right = RightMargin rcDrawTo.Bottom = BottomMargin fr.hdc = Printer.hdc fr.hdcTarget = Printer.hdc fr.rc = rcDrawTo fr.rcPage = rcPage fr.chrg.cpMin = charPos fr.chrg.cpMax = -1 PrintRTF = True PrintRTF = SendMessage(RTF.hwnd, _ EM_FORMATRANGE, printControl, fr) r = SendMessage(RTF.hwnd, EM_FORMATRANGE, False, ByVal _ CLng(0)) End Function ' *** END OF MODULE CODE *** "Mike Williams" <mi***@whiskyandCoke.com> wrote in message Thanks Mike. Stashed away for future reference.news:OnBmrTqLIHA.5360@TK2MSFTNGP03.phx.gbl... > it) but if you are interested in the RichTextBox method then here's an > example. There are two blocks of code, one for a module and the other for > a Form containing a RichTextBox and a Command Button. Run the program and > paste a few pages worth of stuff (from a MS Word document or whatever) > into the RTB and then click the button: > -- Mike Microsoft MVP Visual Basic "MikeD" <nob***@nowhere.edu> wrote in message You're welcome. By the way, I've just noticed that I've got the horizontal news:%23NDhG6qLIHA.1184@TK2MSFTNGP04.phx.gbl... > Thanks Mike. Stashed away for future reference. alignment of the header (the page numbers) wrong because I've inadvertently used the width of the footer instead of the width header in the calculation. Here is the code modified to correct that fault (I'm posting only the second Do Loop block, modified so as to correct the problem, to save posting a lot of code again): Do With Printer .Font.Italic = True .CurrentY = pageHigh - 0.5 - Printer.TextHeight(footer) ' I've had occasional problems with .TextWidth in ' a With Printer block in Vista, which is why I've ' used Printer.TextWidth below .CurrentX = pageWide / 2 - Printer.TextWidth(footer) / 2 Printer.Print footer; nPage = nPage + 1 header = "Page " & Format(nPage) & _ " of " & Format(totalPages) .Font.Italic = False .CurrentY = 0.5 .CurrentX = (pageWide - Printer.TextWidth(header)) / 2 Printer.Print header; nextChar = PrintRTF(RichTextBox1, margin, margin, _ pageWide - margin * 2, pageHigh - _ margin * 2, nextChar, printControl) If nextChar <= charsToPrint Then Printer.NewPage End If End With Loop Until (nextChar > charsToPrint) Or nextChar = 0 Mike |
|||||||||||||||||||||||