none
複数の印刷を同時に行う方法について RRS feed

  • 質問

  • こんにちは。

    VB2005Express+SQLServerExpressにて開発を行っています。

    ボタンをクリックすることにより、DBから取得したデータを印刷することができるようになったのですが、
    いくつかの印刷を同時に行う方法を考えています。

    イメージとしては、印刷物の一覧をチェックボックスで用意をして、印刷したいものにチェックを入れ、
    印刷ボタンをクリックすることで、それらすべてを印刷する。ということをしたいと考えています。

    まずは、そもそもこのようなことはしないほうがよいというのであれば、現時点であきらめます。

    現在、実現できたことは、ボタンのクリックイベントに印刷を行うプロシージャを関連付けて、
    ボタンをクリックすることで印刷を実現できています。

    しかし、イベントの関連付けは一つしかできないため、複数の印刷をここに関連付けることは
    できないと思います。

    そこで、チェックボックスのチェックのアル分だけ、印刷する内容ごとにクリックイベントに関連付け、
    印刷、ないしはプレビューの表示ということを繰り返しても問題はないのでしょうか。

    印刷の勉強を始めて、間もないので、基本というものがよくわかっていません。
    (参考書なども単一内容の印刷はのっているのですが、複数の内容を一度に印刷するということは
    のっていませんでした。)

    また、複数の印刷を一度に行う場合、データを取得するDataTableなどはひとつだけ宣言をしておき、
    汎用的に使用することができるのか、印刷ごとにそれぞれ宣言をしなければならないものなのでしょうか。

    漠然とした質問で申し訳ありませんが、どうかお知恵を貸してください。
    よろしくお願いいたします。
    2009年9月23日 9:10

回答

  • PrintPageイベントハンドラで処理するのでしたね。すみません。わたしもうっかりしていました。イベントハンドラで処理しますので、印刷プロシージャ(メソッド)内にプライベートでDataTableを持つことができません。
    なので、DataTableや行カウンタも含めて保持するクラスを帳票毎に用意されると良いと思います。

    (参考)
    ReportDocument
    http://yan-note.blogspot.com/2007/06/blog-post_5424.html

    #ReportDocumentと記載されていますが、PrintDocumentoの間違いだと思います。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク TI-cb400 2009年9月24日 21:54
    2009年9月24日 2:28
    モデレータ
  • ということを繰り返しても良いかなとも考えたのですが、その場合に一回のボタンのクリックで、帳票の数だけボタンのクリックイベントを
    呼び出せるのか?という疑問に突き当たりました。
    クリックイベントを呼び出す必要はなく、印刷処理を実行すれば良いので、クリックイベントハンドラから印刷処理部分をメソッドとして抜き出し、それを実行すれば良いと思います。
    ちなみにボタンのクリックイベントを発生させるのであれば、Button1.PerformClick()のようにしてできますが、前述したように印刷処理部分をメソッドとして切り出した方が良いでしょう。


    浅はかな知識で申し訳ないのですが、クラスというのは汎用的な機能を持つものというイメージがあるので、単一の目的のために
    作るというものに違和感を感じてしまいます。
    クラスに汎用的かどうかは関係ありません。サブルーチンとそれに付随する値をくくるための入れ物と考えても良いと思います。今回はプリントに関するメソッドやイベントハンドラ、それに付随するデータテーブルやカレント行を覚えておくためのindexなどを一まとめにすると管理しやすくなります。そこでクラスという入れ物でくくるのです。もし汎用的ということであれば、そのクラスを抽象化して作成した継承元のクラスがそのように言えるかもしれません。
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク TI-cb400 2009年9月24日 21:54
    2009年9月24日 14:42
    モデレータ

すべての返信

  • イメージとしては、印刷物の一覧をチェックボックスで用意をして、印刷したいものにチェックを入れ、
    印刷ボタンをクリックすることで、それらすべてを印刷する。ということをしたいと考えています。

    まずは、そもそもこのようなことはしないほうがよいというのであれば、現時点であきらめます。

    ユーザが指定する内容をまとめて印刷するという考え方自体はよくある話なので、問題ないと思います。

    そこで、チェックボックスのチェックのアル分だけ、印刷する内容ごとにクリックイベントに関連付け、
    印刷、ないしはプレビューの表示ということを繰り返しても問題はないのでしょうか。

    ユーザが許すのであれば良いかもしれませんが、私がユーザなら許しません。
    組み方次第ですが、今の様子だと、複数の項目の印刷プレビューを要求したとき、印刷プレビューが数回開くということになりませんか?
    ユーザから見ると、1回の印刷でまとめて印刷することを期待しているのに、印刷プレビューが複数回開くのは納得ができません。

    印刷の勉強を始めて、間もないので、基本というものがよくわかっていません。
    (参考書なども単一内容の印刷はのっているのですが、複数の内容を一度に印刷するということは
    のっていませんでした。)

    PrintPage イベントの中で「今印刷しているものはページが残っているか」「今印刷しているものが印刷終了の場合、次に印刷するべきものがあるか」等の判断を加えて、連続して印刷できるようにしたら良さそうに思えます。(試していません)

    なお、今回のように、応用例は参考書やサイト等に載っていないことも多いと思います。
    基礎として学んだことをどのように組み合わせれば実現できるかを考えていく力が今後求められるでしょう。

    また、複数の印刷を一度に行う場合、データを取得するDataTableなどはひとつだけ宣言をしておき、
    汎用的に使用することができるのか、印刷ごとにそれぞれ宣言をしなければならないものなのでしょうか。

    印刷内容や今後の組み方次第だと思います。
    同じデータを異なる様式で印刷するだけであれば、1つのインスタンスを使い回すこともできるでしょう。


    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年9月23日 10:24
    モデレータ
  • ご回答ありがとうございます。

    現在、以下のように印刷を記述しています。

    Dim DT as DataTable

    Private Sub btn_Test_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Test.Click

    'PrintDocumentの宣言、DataTableへデータの取得  ←ここ

    End sub

    Private Sub pd_test(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)

    'DTを参照して、その内容の印字処理

    End Sub

    といった処理をしています。

    そこで、矢印の部分を

    Private Sub TestPrint

    'PrintDocumentの宣言、DataTableへデータの取得

    End Sub

    を呼び出す形に変更しようと考えています。

    ただ、DataTableへのデータの取得の際に

    DT = New DataTable

    DT=データ取得

    とした場合、2つ以上の印刷処理を矢印の部分で呼び出しをした際に、どのデータを参照にするのだろうと考えてしまいます。

    Newにより新しいインスタンスを作成するので、データ自体はそれぞれの処理の内容を取得できるとは思うのですが、
    どのDataTableにそれぞれの印刷処理に必要なデータが入っているかの判断ができないように思えます。

    ということから、一番最初のDataTableの宣言の時点で、必要な数のDataTableの宣言が必要になると思えます。

    同時に、異なる内容にデータを印刷する場合は上記のように行うしかないのでしょうか。

    今、試す環境が手元にないのですが、どうしても気になってしまったので、質問をさせていただきました。

    どうか、アドバイスお願いいたします。

    2009年9月23日 11:57
  • とした場合、2つ以上の印刷処理を矢印の部分で呼び出しをした際に、どのデータを参照にするのだろうと考えてしまいます。
    メンバー変数 DT を配列やリストにすれば良いのでは?
    そして、今処理しているのは何番目かを覚える変数も追加して、必要な位置に DataTable を作って代入していけば良いでしょう。
    そして、印刷する際も配列の何番目のものを参照するべきか判断して利用すると良いでしょう。

    配列だと最初の時点で数が決定している必要があります。ただ、今回の要求では印刷開始時点で最大数を決定できるので特に支障はないように思えます。
    リスト = List(Of T) の場合は最初に数を決めなくても良いです。
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    2009年9月23日 12:33
    モデレータ
  • しかし、イベントの関連付けは一つしかできないため、複数の印刷をここに関連付けることは
    できないと思います。
    ここの意味がよくわからなかったのですが、ボタンのクリックイベントに複数のイベントハンドラをセットできないということでしょうか? であれば、それは可能です。


    そこで、チェックボックスのチェックのアル分だけ、印刷する内容ごとにクリックイベントに関連付け、
    印刷、ないしはプレビューの表示ということを繰り返しても問題はないのでしょうか。
    私は良いと思いますよ。ただ、ロジックとしては、それぞれの帳票の印刷プロシージャがあって、それがクリックイベントに結びついているのが基本だと思います。例えば、

    'TestA印刷プロシージャ
    Private Sub TestAPrint

    End Sub

    'TestB印刷プロシージャ
    Private Sub TestBPrint

    End Sub

    Private Sub btn_TestA_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_TestA.Click

       TestAPrint()

    End sub

    Private Sub btn_TestB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_TestB.Click

       TestBPrint()

    End sub

    複数同時に印刷指示したい場合は、

    Private Sub btn_TestOnce_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_TestOnce.Click

         If TestAチェックボックスがチェックされていれば、 Then TestAprint()

         If TestBチェックボックスがチェックされていれば、 Then TestBprint()

    End sub

    帳票によって用意するDataTableの構造は違うのが普通ですから、それぞれの印刷プロシージャでプライベートで用意してしまえば良いと思います。
    また、ユーザーは印刷指示を何度も行うのが面倒で一度に行いたいだけであり、帳票毎に印刷プレビューが開くのは問題ないと思います。むしろ一つの印刷プレビューでつながっているのであれば、目的の帳票を画面で確認したい場合に探しにくいのではないでしょうか? 私が知る範囲では、一度に印刷指示したい場合は大抵が定型業務になっており、どの帳票を選択したかという情報も記憶できるようになっています。そして大抵は印刷プレビューを行いません。複数帳票を一度に指示したい場合は大抵がプレビューで確認したいわけではなく、一度に印刷したいからだからです。
    もちろん上記は私の個人的な思いであり、実際にどのような動作を求めているのかはユーザーに確認する以外はないというのは言うまでもありません。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年9月23日 15:02
    モデレータ
  • ご回答ありがとうございます。

    私の説明に一部不足が間違いがありました。

    Private Sub pd_test(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)

    'DTを参照して、その内容の印字処理

    End Sub

    上記の部分で印刷を行っていると書きましたが、その前のボタンのクリックイベントにおいて、PrintDocumentの宣言を
    行い、そのPrintDocumentのPrintPageイベントに追加をしておりました。

    'PrintDocumentオブジェクトの作成
            PD = New System.Drawing.Printing.PrintDocument

            'Printpageイベントハンドラの追加
            AddHandler PD.PrintPage, AddressOf pd_Test

    最初の私の質問はAddressOfのあとに、複数のイベントをセットできるのかどうかということでした。
    これはできるということなのですね。勝手に思い込んでおりました。

    Azulean様
    DataTableなども配列にできるのですね。このようなことはまったく考えておりませんでした。一度試してみたいと思います。

    trapemiya様
    印刷プロシージャにDataTableをプライベートで用意するというのはどのようなことをさすのでしょうか。

    現時点での私の理解としては、PrintPage内でデータの取得処理をすると複数舞の印刷にわたる場合、その都度データ取得
    処理が入るので非効率となる。
    そこで、どこからでも参照ができる形で、DataTableを宣言しておき、ボタンのクリック時にDataTableにデータを取得。
    その内容を持って、PrintDocumentのPrintPageに関連付けしたイベント内で印刷処理を行う。
    というもので、そのために最初に質問に記述してあるような書き方をしております。

    自分でこのような方法をとろうと思うといっておきながら、実は下記の方法だとどこで、PrintDocumentの宣言を行うかや
    DataTableの宣言、データの取得タイミングがわからず悩んでおります。

    'TestA印刷プロシージャ
    Private Sub TestAPrint

    End Sub

    もしよろしければ、その部分だけでも教えていただけませんでしょうか。
    どうか、よろしくお願いします。

    2009年9月23日 21:58
  • PrintPageイベントハンドラで処理するのでしたね。すみません。わたしもうっかりしていました。イベントハンドラで処理しますので、印刷プロシージャ(メソッド)内にプライベートでDataTableを持つことができません。
    なので、DataTableや行カウンタも含めて保持するクラスを帳票毎に用意されると良いと思います。

    (参考)
    ReportDocument
    http://yan-note.blogspot.com/2007/06/blog-post_5424.html

    #ReportDocumentと記載されていますが、PrintDocumentoの間違いだと思います。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク TI-cb400 2009年9月24日 21:54
    2009年9月24日 2:28
    モデレータ
  • ご回答ありがとうございます。

    私の現状の知識ではPrintPageイベントハンドラ内での処理しか思いつかないのですが、何か他に印刷を行う方法があるのでしょうか。

    参考の部分も拝見させていただきました。

    内容を見ると、trapemiya様がおっしゃっているように帳票の数だけクラスを作る必要がありそうですね

    自分が現在行っている方法で、取得するデータごとに別名のDataTableを宣言しておき、それぞれ印刷のプロシージャを用意して
    イベントハンドラにセット → 印刷
    ということを繰り返しても良いかなとも考えたのですが、その場合に一回のボタンのクリックで、帳票の数だけボタンのクリックイベントを
    呼び出せるのか?という疑問に突き当たりました。

    となると、クラスを複数作るほうが現実的かなとも思えます。

    浅はかな知識で申し訳ないのですが、クラスというのは汎用的な機能を持つものというイメージがあるので、単一の目的のために
    作るというものに違和感を感じてしまいます。

    このように感じるのはやはり、私の知識のなさのためなのでしょうか。
    2009年9月24日 4:25
  • ということを繰り返しても良いかなとも考えたのですが、その場合に一回のボタンのクリックで、帳票の数だけボタンのクリックイベントを
    呼び出せるのか?という疑問に突き当たりました。
    クリックイベントを呼び出す必要はなく、印刷処理を実行すれば良いので、クリックイベントハンドラから印刷処理部分をメソッドとして抜き出し、それを実行すれば良いと思います。
    ちなみにボタンのクリックイベントを発生させるのであれば、Button1.PerformClick()のようにしてできますが、前述したように印刷処理部分をメソッドとして切り出した方が良いでしょう。


    浅はかな知識で申し訳ないのですが、クラスというのは汎用的な機能を持つものというイメージがあるので、単一の目的のために
    作るというものに違和感を感じてしまいます。
    クラスに汎用的かどうかは関係ありません。サブルーチンとそれに付随する値をくくるための入れ物と考えても良いと思います。今回はプリントに関するメソッドやイベントハンドラ、それに付随するデータテーブルやカレント行を覚えておくためのindexなどを一まとめにすると管理しやすくなります。そこでクラスという入れ物でくくるのです。もし汎用的ということであれば、そのクラスを抽象化して作成した継承元のクラスがそのように言えるかもしれません。
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク TI-cb400 2009年9月24日 21:54
    2009年9月24日 14:42
    モデレータ
  • おはようございます。

    思い切り勘違いをしていたことに気付きました。

    ボタンをクリックすることで、PrindDocumentを作成し、PrintDocumentのPrintPageイベントに何を印刷するかということを
    関連付けていたのであり、ボタンのクリックイベントに関連をつけているわけではありませんでした。

    となると、印刷をする都度だけ、PrintDocumentのPrintPageイベントに関連付けをして印刷を実行することということも
    実現できそうです。

    ただ、クラスにしたほうがひとつの処理を一塊と見ることができるので、わかりやすくはなりそうです。

    まずは、クラスを利用する方法で検討してみたいと思います。

    共通のプロパティ(DataTableなど)を持つクラスをBaseクラスとして作っておき、個別の処理をそれぞれの印刷物ごとに
    行うという形をとりたいと思います。

    ありがとうございました。
    2009年9月24日 22:12