none
VS2008(VB)でプリンターで改ページするには? RRS feed

  • 質問

  • こんにちは

    初心者のためわかりません。教えてください。

    プリンターで次のページに印刷しようと思っても改ページせずにドキュメントが

    つながってしまいます。きちんと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回と決まってはいないためほとほと困り果てています。

    2008年11月11日 8:31

回答

  • こんにちは。

     

     しげちゃん さんからの引用

    このようにすると改ページせずに続けて印刷してしまいます。

     

    i の値が 5 ではないからではないでしょうか。 デバッグしてみてください。 6 になっていませんか。

     

    書籍の通りにすると5回も同じコードを書かなくてはなりません。毎回5回と決まってはいないためほとほと困り果てています。

     

    よくわかりませんが、5 である必要はないと思います。

    2008年11月11日 8:35
  • 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

    2008年11月11日 8:53
  • 外池と申します。

     

    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にして抜ければ、そこで印刷は終了です。

     

     

     

    2008年11月11日 9:18
  • 外池です。メチャ簡単な例を書いてみました。参考にしてください。通常使うプリンターに5枚出力します。各ページの左上にページ番号のように1~5を印刷します。(VB2005で動作確認ずみ)

     

    Code Snippet

    Public Class Form1
        Private _PageCount As Integer = 0

        Private 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 Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            PrintDocument1.Print()
        End Sub
    End Class

     

     

     

    2008年11月11日 9:29
  • 外池です。印刷したいものが複雑になればなるほど、「外から与える」ものが多くなると思います。で、そのようにすべきです。

     

    と言いますのも、いろんな形態の資料を印刷したい場合、PrintPageイベントのプロシージャーの中に全ての形態をカバーするようにプログラムを書き下すとなると、とてもとても無理です。ここが、VB6に比べてVB.NETがオブジェクト指向を一層強力になっていることを利用すべきところです。が、オブジェクト指向の話を深入りするのは、今は、面倒なので、やめておきましょう。

     

    それよりも、こんな風に考えてください。PrintPageイベントの中には、ほとんど何も書かないようにするのです。印刷の複雑な作業を管理する別のプロシージャーを作る(外部に出してしまう)わけです。例えば・・・、

    Code Snippet

    Sub 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ページごとに描画を完結させる(まとめる)。」という感覚です。

    2008年11月11日 14:04
  •  しげちゃん さんからの引用

    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 DialogResult

            PrintDialog1.PrinterSettings = New Printing.PrinterSettings

            Ret = PrintDialog1.ShowDialog

            If Ret = Windows.Forms.DialogResult.OK Then
                PrintDocument1.PrinterSettings = PrintDialog1.PrinterSettings
                PrintDocument1.Print()
            End If
        End Sub

     

        Private 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()を実行する前になんらかの処理をしたほうがいいように思います。

    2008年11月11日 19:54

すべての返信

  • こんにちは。

     

     しげちゃん さんからの引用

    このようにすると改ページせずに続けて印刷してしまいます。

     

    i の値が 5 ではないからではないでしょうか。 デバッグしてみてください。 6 になっていませんか。

     

    書籍の通りにすると5回も同じコードを書かなくてはなりません。毎回5回と決まってはいないためほとほと困り果てています。

     

    よくわかりませんが、5 である必要はないと思います。

    2008年11月11日 8:35
  • 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

    2008年11月11日 8:53
  • ご指示の通り調べてみましたがきちんと1~4までは確かにHasMorePagesはTrueで

    I が5のときはきちんとFalseに変化しているのですが、やはり改ページをせずにドキュメントはつながったままで、5ページ分が1ぺージになってしまいます。HasMorePages の指定がループの中にあるといけないのでしょうか?? う~ん わからんよ~

     

    2008年11月11日 9:04
  • Wm-t さんのおっしゃるとおりでは果てしなく同じものをいんさつしてしまいます。困りました。

     

    2008年11月11日 9:10
  • 外池と申します。

     

    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にして抜ければ、そこで印刷は終了です。

     

     

     

    2008年11月11日 9:18
  • 外池です。メチャ簡単な例を書いてみました。参考にしてください。通常使うプリンターに5枚出力します。各ページの左上にページ番号のように1~5を印刷します。(VB2005で動作確認ずみ)

     

    Code Snippet

    Public Class Form1
        Private _PageCount As Integer = 0

        Private 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 Sub

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            PrintDocument1.Print()
        End Sub
    End Class

     

     

     

    2008年11月11日 9:29
  • 外池さん ありがとうございます。確かにおっしゃるとおりです。従って「I」に伴って変わる変数などはPrintDocument の外から与えないといけないことになりますね。

    決まった長さの内容であればいいのですが、時に印刷内容が1ページに収まらないようなときは

    VB6であれば決まった行数を印刷した段階で改ページができた(たとえばループ変数(行数の)が50を超えた場合には続きを、つまり51行以上になったら改ページということ)と思います。

     

    VS2008の場合はこの処理も変数として次のページのためにPrintDocument の外から与えなくてはいけない(次は51行目の内容だぞとの指示)のでしょうか??

    VS2008(私はVS.NETは初めてです)は確かに親切なところもたくさんあってすばらしいとは思いますが、こと印刷関係は非常に使いにくいと思います。

     

    他に名案はないものでしょうかねぇ・・・・・・・・ ふぅ~

     

     

    2008年11月11日 11:31
  • 外池です。印刷したいものが複雑になればなるほど、「外から与える」ものが多くなると思います。で、そのようにすべきです。

     

    と言いますのも、いろんな形態の資料を印刷したい場合、PrintPageイベントのプロシージャーの中に全ての形態をカバーするようにプログラムを書き下すとなると、とてもとても無理です。ここが、VB6に比べてVB.NETがオブジェクト指向を一層強力になっていることを利用すべきところです。が、オブジェクト指向の話を深入りするのは、今は、面倒なので、やめておきましょう。

     

    それよりも、こんな風に考えてください。PrintPageイベントの中には、ほとんど何も書かないようにするのです。印刷の複雑な作業を管理する別のプロシージャーを作る(外部に出してしまう)わけです。例えば・・・、

    Code Snippet

    Sub 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ページごとに描画を完結させる(まとめる)。」という感覚です。

    2008年11月11日 14:04
  •  しげちゃん さんからの引用

    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 DialogResult

            PrintDialog1.PrinterSettings = New Printing.PrinterSettings

            Ret = PrintDialog1.ShowDialog

            If Ret = Windows.Forms.DialogResult.OK Then
                PrintDocument1.PrinterSettings = PrintDialog1.PrinterSettings
                PrintDocument1.Print()
            End If
        End Sub

     

        Private 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()を実行する前になんらかの処理をしたほうがいいように思います。

    2008年11月11日 19:54
  • 外池さん たびたびの回答ありがとうございます。よく考えてみれば確かに考え方次第だと思います。一つのパーツに何でも詰め込むということは使用する側としては使いにくいものかもしれません。むしろ汎用的な小回りのきくパーツをたくさん用意して組み合わせてくださいということですよね。

     

    私も外池さんのおっしゃるとおり,PrintDocumentは単純に1ページを外からの指示で印刷するルーチンと考えることでやっと納得できました。(あきらめかも(笑)),結局昔ながらの頭で考えていたんだと思います。(でも最近はついて行けない部分が多すぎますが・・・・・??) ,実をいいますと,どうしてもPrintDocumentの中ではできなかったもので,外からループをかけていたのです。でもきっとその中でも何か隠れた方法があるのではないか(隠しコマンドみたいに)と思っていたので投稿させていただきました。

    ご迷惑だったかとは思いますが,今後ともご指導ください。ありがとうございました。(還暦を過ぎたしげちゃんでした。)

     

    2008年11月12日 10:26
  • と歩さん ありがとうございます。たびたびのご回答本当に感謝いたしております。いろいろなコードを含めて大変参考になりました。外池さんのように考えた方が後々のことを考えるといいのだろうと思います。古く凝り固まった頭の私としては何でも詰まっていた方がいいという考えでしたから・・・・・

    少し頭や発想を柔軟にしたいと思っています。

    ちなみに投稿するのは今回初めてです。いろいろ書籍を見たりするのですが,なかなかねぇ・・・ 高い本を買っても知りたいことはなかなかです。

    今後もよろしく指導ください

    2008年11月12日 10:38
  • こんにちは。中川俊輔 です。

     

    皆様、回答ありがとうございます。

     

    しげちゃんさん、はじめまして。フォーラムのご利用ありがとうございます。

    勝手ながら、有用な情報と思われる回答へ回答済みチェックをつけさせていただきました。

     

    今後ともフォーラムをよろしくお願いします。

    それでは!

    2008年11月19日 8:59