トップ回答者
VS2008(VB)でプリンターで改ページするには?

質問
-
こんにちは
初心者のためわかりません。教えてください。
プリンターで次のページに印刷しようと思っても改ページせずにドキュメントが
つながってしまいます。きちんと1ページごとに改ページをするにはどうしたらいいでしょうか
例(PrintDocument1.print)で
For i=1 to 5
e.Graphics.DrawStrings(・・・・・・・・・・)
・ (印刷内容はI の値で少しずつ変化させる)
・
1ページの印刷が終了して
If i=5 then
e.HasMorePages=False
Else
e.HasMorePages=True
End if
next i
このようにすると改ページせずに続けて印刷してしまいます。
I の値ごとに改ページをするにはどうすればできますか。
書籍の通りにすると5回も同じコードを書かなくてはなりません。
毎回5回と決まってはいないためほとほと困り果てています。
回答
-
For i=1 to 5
e.Graphics.DrawStrings(・・・・・・・・・・)
・ (印刷内容はI の値で少しずつ変化させる)
・
1ページの印刷が終了して
If i=5 then
e.HasMorePages=False
Else
e.HasMorePages=True
End if
next i
このようにすると改ページせずに続けて印刷してしまいます。
I の値ごとに改ページをするにはどうすればできますか。
逆ではありませんか?
If i=5 then
e.HasMorePages=True
Else
e.HasMorePages=False
End if
というより、常にでよくありませんか?
e.HasMorePages=False
-
外池と申します。
For文で5回繰り返そうとしているのは、PrintDocumentの1回のPrintPageイベントの実行の中ですよね? (ここを確認してプログラムを見せて頂きたいのですが)
1回のPrintPageイベントで、1ページの紙に印刷されると理解してください。ですので、For文で5回くりかえしても、確かに、1ページの中に5回分の印刷がゴッチャになって出てきます。
HasMorePagesをFalseにしてPrintPageイベントの実行から抜けると、もうPrintPageイベントは発生しません。
HasMorePagesをTrueにしてPrintPageイベントの実行から抜けると、繰り返してPrintPageイベントが発生します。そして、次のページの印刷に必要な操作を行うことになります。ですので、考え方として、For文の数え上げる変数「i」に相当する変数を、PrintPageのプロシージャーの外に(おそらくFormの変数かな?)おきます。PrintPageイベントを抜ける前に「i」を+1します。そうすると、PrintPageイベントが再度発生したときに、今、何ページ目かがわかります。i=5ならば、HasMorePagesをFalseにして抜ければ、そこで印刷は終了です。
-
外池です。メチャ簡単な例を書いてみました。参考にしてください。通常使うプリンターに5枚出力します。各ページの左上にページ番号のように1~5を印刷します。(VB2005で動作確認ずみ)
Code SnippetPublic Class Form1
Private _PageCount As Integer = 0Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim f As New Font(FontFamily.GenericMonospace, 11, FontStyle.Regular)
_PageCount += 1
e.Graphics.DrawString(_PageCount.ToString, f, Brushes.Black, 100, 100)
f.Dispose()If _PageCount < 5 Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End SubPrivate Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
PrintDocument1.Print()
End Sub
End Class -
外池です。印刷したいものが複雑になればなるほど、「外から与える」ものが多くなると思います。で、そのようにすべきです。
と言いますのも、いろんな形態の資料を印刷したい場合、PrintPageイベントのプロシージャーの中に全ての形態をカバーするようにプログラムを書き下すとなると、とてもとても無理です。ここが、VB6に比べてVB.NETがオブジェクト指向を一層強力になっていることを利用すべきところです。が、オブジェクト指向の話を深入りするのは、今は、面倒なので、やめておきましょう。
それよりも、こんな風に考えてください。PrintPageイベントの中には、ほとんど何も書かないようにするのです。印刷の複雑な作業を管理する別のプロシージャーを作る(外部に出してしまう)わけです。例えば・・・、
Code SnippetSub DrawPage(ByVal e as PrintPageEventHandler)
'ページ数を管理する変数や、印刷すべき行数を管理する変数をStaticで宣言する。
'印刷対象のデータは、Formレベルの変数のデータから読み出す。
'e.Graphicsに対して、描画する。
'改ページが必要な場合には、e.HasMorePages = TrueをセットしてReturn
'そうでなければ、e.HasMorePages = FalseをセットしてReturn
End Sub
んで、PrintPageイベントからは、このDrawPageを呼び出すダケにするわけです。
もし、複数種類の印刷を行わないといけない場合には、同じようなプロシージャーをDrawPage1とか、DrawPage2とか作って、PrintPageイベントの中で分岐して呼び出すようにすればよいかと思います。
まぁ・・・、ここは、慣れると、VB.NETの方がはるかに柔軟性がありますから、頑張ってください。「1ページごとに描画を完結させる(まとめる)。」という感覚です。
-
しげちゃん さんからの引用 VB6であれば決まった行数を印刷した段階で改ページができた(たとえばループ変数(行数の)が50を超えた場合には続きを、つまり51行以上になったら改ページということ)と思います。
VS2008の場合はこの処理も変数として次のページのためにPrintDocument の外から与えなくてはいけない(次は51行目の内容だぞとの指示)のでしょうか??
単純に上記のような印刷をPrintDocument1_PrintPage内だけで済ませたいなら
TextBox1、Button1、PrintDocument1,PrintDialog1がフォームに貼り付けてあるとして
--------------------------------------------------------------------------------------------------------------------------------------------------------
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Ret As DialogResultPrintDialog1.PrinterSettings = New Printing.PrinterSettings
Ret = PrintDialog1.ShowDialog
If Ret = Windows.Forms.DialogResult.OK Then
PrintDocument1.PrinterSettings = PrintDialog1.PrinterSettings
PrintDocument1.Print()
End If
End SubPrivate Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim PageLines As Integer = 50 '1ページに印刷したい行数Static EndPage As Boolean = False '最後のページか?
Static Page As Integer = 1 'ページの番号
Dim PrintText() As String = TextBox1.Lines 'テキストを行ごとに配列に格納
Dim LineStart As Integer = (Page - 1) * PageLines '印刷開始行
Dim LineEnd As Integer = Page * PageLines - 1 '印刷終了行
Dim j As Integer 'Forループ用'印刷終了行がテキストボックスの行数を超えていたら終了ページ
If TextBox1.Lines.Length - LineEnd <= 1 Then
LineEnd = TextBox1.Lines.Length - 1
EndPage = True
End If'印刷処理
For j = LineStart To LineEnd
e.Graphics.DrawString(PrintText(j), New Font("MS Pゴシック", 11), Brushes.Black, e.MarginBounds.Left, e.MarginBounds.Top + ((j - LineStart) * 11 *2))
Next'印刷を続けるか、終了するか
If EndPage Then
e.HasMorePages = False
Page = 1
EndPage = False
Else
e.HasMorePages = True
Page += 1
End If
End Sub
End Class--------------------------------------------------------------------------------------------------------------------------------------------------------
こんな感じでもいけるとは思いますが・・・
のちのちのことを考えると、んーって感じです。
外池さんのおっしゃるような方法や、 PrintDocument1.Print()を実行する前になんらかの処理をしたほうがいいように思います。
すべての返信
-
For i=1 to 5
e.Graphics.DrawStrings(・・・・・・・・・・)
・ (印刷内容はI の値で少しずつ変化させる)
・
1ページの印刷が終了して
If i=5 then
e.HasMorePages=False
Else
e.HasMorePages=True
End if
next i
このようにすると改ページせずに続けて印刷してしまいます。
I の値ごとに改ページをするにはどうすればできますか。
逆ではありませんか?
If i=5 then
e.HasMorePages=True
Else
e.HasMorePages=False
End if
というより、常にでよくありませんか?
e.HasMorePages=False
-
外池と申します。
For文で5回繰り返そうとしているのは、PrintDocumentの1回のPrintPageイベントの実行の中ですよね? (ここを確認してプログラムを見せて頂きたいのですが)
1回のPrintPageイベントで、1ページの紙に印刷されると理解してください。ですので、For文で5回くりかえしても、確かに、1ページの中に5回分の印刷がゴッチャになって出てきます。
HasMorePagesをFalseにしてPrintPageイベントの実行から抜けると、もうPrintPageイベントは発生しません。
HasMorePagesをTrueにしてPrintPageイベントの実行から抜けると、繰り返してPrintPageイベントが発生します。そして、次のページの印刷に必要な操作を行うことになります。ですので、考え方として、For文の数え上げる変数「i」に相当する変数を、PrintPageのプロシージャーの外に(おそらくFormの変数かな?)おきます。PrintPageイベントを抜ける前に「i」を+1します。そうすると、PrintPageイベントが再度発生したときに、今、何ページ目かがわかります。i=5ならば、HasMorePagesをFalseにして抜ければ、そこで印刷は終了です。
-
外池です。メチャ簡単な例を書いてみました。参考にしてください。通常使うプリンターに5枚出力します。各ページの左上にページ番号のように1~5を印刷します。(VB2005で動作確認ずみ)
Code SnippetPublic Class Form1
Private _PageCount As Integer = 0Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim f As New Font(FontFamily.GenericMonospace, 11, FontStyle.Regular)
_PageCount += 1
e.Graphics.DrawString(_PageCount.ToString, f, Brushes.Black, 100, 100)
f.Dispose()If _PageCount < 5 Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End SubPrivate Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
PrintDocument1.Print()
End Sub
End Class -
外池さん ありがとうございます。確かにおっしゃるとおりです。従って「I」に伴って変わる変数などはPrintDocument の外から与えないといけないことになりますね。
決まった長さの内容であればいいのですが、時に印刷内容が1ページに収まらないようなときは
VB6であれば決まった行数を印刷した段階で改ページができた(たとえばループ変数(行数の)が50を超えた場合には続きを、つまり51行以上になったら改ページということ)と思います。
VS2008の場合はこの処理も変数として次のページのためにPrintDocument の外から与えなくてはいけない(次は51行目の内容だぞとの指示)のでしょうか??
VS2008(私はVS.NETは初めてです)は確かに親切なところもたくさんあってすばらしいとは思いますが、こと印刷関係は非常に使いにくいと思います。
他に名案はないものでしょうかねぇ・・・・・・・・ ふぅ~
-
外池です。印刷したいものが複雑になればなるほど、「外から与える」ものが多くなると思います。で、そのようにすべきです。
と言いますのも、いろんな形態の資料を印刷したい場合、PrintPageイベントのプロシージャーの中に全ての形態をカバーするようにプログラムを書き下すとなると、とてもとても無理です。ここが、VB6に比べてVB.NETがオブジェクト指向を一層強力になっていることを利用すべきところです。が、オブジェクト指向の話を深入りするのは、今は、面倒なので、やめておきましょう。
それよりも、こんな風に考えてください。PrintPageイベントの中には、ほとんど何も書かないようにするのです。印刷の複雑な作業を管理する別のプロシージャーを作る(外部に出してしまう)わけです。例えば・・・、
Code SnippetSub DrawPage(ByVal e as PrintPageEventHandler)
'ページ数を管理する変数や、印刷すべき行数を管理する変数をStaticで宣言する。
'印刷対象のデータは、Formレベルの変数のデータから読み出す。
'e.Graphicsに対して、描画する。
'改ページが必要な場合には、e.HasMorePages = TrueをセットしてReturn
'そうでなければ、e.HasMorePages = FalseをセットしてReturn
End Sub
んで、PrintPageイベントからは、このDrawPageを呼び出すダケにするわけです。
もし、複数種類の印刷を行わないといけない場合には、同じようなプロシージャーをDrawPage1とか、DrawPage2とか作って、PrintPageイベントの中で分岐して呼び出すようにすればよいかと思います。
まぁ・・・、ここは、慣れると、VB.NETの方がはるかに柔軟性がありますから、頑張ってください。「1ページごとに描画を完結させる(まとめる)。」という感覚です。
-
しげちゃん さんからの引用 VB6であれば決まった行数を印刷した段階で改ページができた(たとえばループ変数(行数の)が50を超えた場合には続きを、つまり51行以上になったら改ページということ)と思います。
VS2008の場合はこの処理も変数として次のページのためにPrintDocument の外から与えなくてはいけない(次は51行目の内容だぞとの指示)のでしょうか??
単純に上記のような印刷をPrintDocument1_PrintPage内だけで済ませたいなら
TextBox1、Button1、PrintDocument1,PrintDialog1がフォームに貼り付けてあるとして
--------------------------------------------------------------------------------------------------------------------------------------------------------
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Ret As DialogResultPrintDialog1.PrinterSettings = New Printing.PrinterSettings
Ret = PrintDialog1.ShowDialog
If Ret = Windows.Forms.DialogResult.OK Then
PrintDocument1.PrinterSettings = PrintDialog1.PrinterSettings
PrintDocument1.Print()
End If
End SubPrivate Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Dim PageLines As Integer = 50 '1ページに印刷したい行数Static EndPage As Boolean = False '最後のページか?
Static Page As Integer = 1 'ページの番号
Dim PrintText() As String = TextBox1.Lines 'テキストを行ごとに配列に格納
Dim LineStart As Integer = (Page - 1) * PageLines '印刷開始行
Dim LineEnd As Integer = Page * PageLines - 1 '印刷終了行
Dim j As Integer 'Forループ用'印刷終了行がテキストボックスの行数を超えていたら終了ページ
If TextBox1.Lines.Length - LineEnd <= 1 Then
LineEnd = TextBox1.Lines.Length - 1
EndPage = True
End If'印刷処理
For j = LineStart To LineEnd
e.Graphics.DrawString(PrintText(j), New Font("MS Pゴシック", 11), Brushes.Black, e.MarginBounds.Left, e.MarginBounds.Top + ((j - LineStart) * 11 *2))
Next'印刷を続けるか、終了するか
If EndPage Then
e.HasMorePages = False
Page = 1
EndPage = False
Else
e.HasMorePages = True
Page += 1
End If
End Sub
End Class--------------------------------------------------------------------------------------------------------------------------------------------------------
こんな感じでもいけるとは思いますが・・・
のちのちのことを考えると、んーって感じです。
外池さんのおっしゃるような方法や、 PrintDocument1.Print()を実行する前になんらかの処理をしたほうがいいように思います。
-
外池さん たびたびの回答ありがとうございます。よく考えてみれば確かに考え方次第だと思います。一つのパーツに何でも詰め込むということは使用する側としては使いにくいものかもしれません。むしろ汎用的な小回りのきくパーツをたくさん用意して組み合わせてくださいということですよね。
私も外池さんのおっしゃるとおり,PrintDocumentは単純に1ページを外からの指示で印刷するルーチンと考えることでやっと納得できました。(あきらめかも(笑)),結局昔ながらの頭で考えていたんだと思います。(でも最近はついて行けない部分が多すぎますが・・・・・??) ,実をいいますと,どうしてもPrintDocumentの中ではできなかったもので,外からループをかけていたのです。でもきっとその中でも何か隠れた方法があるのではないか(隠しコマンドみたいに)と思っていたので投稿させていただきました。
ご迷惑だったかとは思いますが,今後ともご指導ください。ありがとうございました。(還暦を過ぎたしげちゃんでした。)