トップ回答者
テキストファイル印刷時の改ページ処理

質問
-
いつもお世話になっております。arubi-momoと申します。
Windows7 64bit Visual Studio2010 C#で開発をしております。
PrintDocumentを使用してテキストファイルを印刷しようとしているのですが、改ページがされずに困っています。
調べたところ、HasMorePagesプロパティをTrueに設定すればできるようなのですが、うまく行きません。
private void Print_Click(object sender, EventArgs e) { //印刷の選択ダイアログを表示する if (pdlg.ShowDialog() == DialogResult.OK) { //PrintPageイベントハンドラの追加 pd.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage); //OKがクリックされた時は印刷する pd.Print(); } } private void pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { string strLine = ""; string strPage = ""; // ファイルオープン System.IO.StreamReader sr = new System.IO.StreamReader(m_PrintFilePath, Encoding.GetEncoding("Shift-JIS")); x = e.MarginBounds.Left; y = e.MarginBounds.Top; while (strLine.IndexOf(clsConstants.STR_RESULT_CONTENTS) < 0) { strPage = ""; strPage = strPage + strLine + "\n"; //ページの作成 while (strLine.IndexOf(clsConstants.STR_PAGE_TERM) < 0) { strLine = sr.ReadLine(); strPage = strPage + strLine + "\n"; } //印刷処理 DrawPage(e.Graphics, strPage); // 最終ページかどうか判断 if (最終ページの場合) { e.HasMorePages = false; } else { e.HasMorePages = true; } } sr.Close(); } private void DrawPage(System.Drawing.Graphics g, string strPage) { g.DrawString(strPage, m_Font, Brushes.Black, 10, 10); }
これで実行すると1ページに2ページ分のデータが重なって出力されました。
ためしに1ページ分の情報を越える行数の印刷も行ってみたのですが、やはり1ページしか出力されませんでした。
原因お心当たりの方がいらっしゃいましたら、ご教示いただけますようお願いいたします。
何卒、よろしくお願いいたします。
回答
-
PrintPageイベントは、文字通り1ページ分を印刷するイベントです。複数ページを印刷する場合、このイベントを複数回発生させる必要があります。
で、2ページ目以降用のPrintPageイベントを再度発生させるために、最終ページ以外は、そのページの描画が終わった(=PrintPageイベントを終了させる)ときに、e.HasMorePagesをtrueに設定します。
つまり、STR_RESULT_CONTENTSでのループの内部だけをPrintPageに記述する必要があります。ループ外部は、フィールドに配置するなりすることになります。
- 回答としてマーク arubi_momo 2014年7月4日 4:03
-
PrintPage +=は、イベントハンドラの関連づけです。PrintDocumentオブジェクトがPrintPageイベントを発生させたときに呼び出すメソッドを登録する処理です。これは普通PrintDocumentオブジェクト1つについて1度だけで十分です。
Printメソッドが呼び出されると、PrintDocumentオブジェクトはPrintPageイベントに+=されているメソッドを呼び出し、そのメソッドで1ページ目を描画させます。メソッドから返ってきたら、PrintDocumentオブジェクトはHasMorePagesを調べ、trueであればもう一度同じメソッドを呼び出して2ページ目を描画させます。これをHasMorePagesがfalseになるまで続けます。
MSDNのPrintDocument.PrintPage イベントのサンプルコードがちょうどarubi_momoさんが書こうとなさっている内容にほぼ一致しているようです。(サンプルにするにはwhileの条件とかが少しサンプル向けの記述じゃありませんが)
読み込む対象のStreamReaderがローカル変数ではなく、pd_PrintPageメソッドをもっているクラスのフィールド(メンバ変数)であるのが分かります。
- 回答としてマーク arubi_momo 2014年7月4日 4:03
すべての返信
-
PrintPageイベントは、文字通り1ページ分を印刷するイベントです。複数ページを印刷する場合、このイベントを複数回発生させる必要があります。
で、2ページ目以降用のPrintPageイベントを再度発生させるために、最終ページ以外は、そのページの描画が終わった(=PrintPageイベントを終了させる)ときに、e.HasMorePagesをtrueに設定します。
つまり、STR_RESULT_CONTENTSでのループの内部だけをPrintPageに記述する必要があります。ループ外部は、フィールドに配置するなりすることになります。
- 回答としてマーク arubi_momo 2014年7月4日 4:03
-
PrintDocumentは普段使わないので詳しくないのですが、overrideしたOnPrintPageメソッド内でHasMorePagesを設定しないといけないようです。
PrintDocument で改頁する方法
http://www1.yel.m-net.ne.jp/oss/Tips/WinApp/Tips_30003.htm以下にサンプルコードがあります。
Printing In C#
http://www.dreamincode.net/forums/topic/44330-printing-in-c%23/#(追記)あれ、外したかな?
#(追記)本題とは直接関係ありませんが、usingを使って名前空間を省略した方が見やすいですね。また、
pd.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage)
は、
pd.PrintPage += pd_PrintPage
と省略できます。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
- 編集済み trapemiyaModerator 2014年7月3日 7:14 追記
-
Hongliangさま
お世話になっております。
早速のご回答ありがとうございました。
PrintPageを印刷するページ分呼び出すように修正してみましたが、まだうまく行きません。今度は1ページに重なって出力されることはなくなりましたが、一番最後に呼ばれたページしか印刷されないようになってしまいました。何か間違えているのだと思うのですが。。。
private void Print_Click(object sender, EventArgs e) { //印刷の選択ダイアログを表示する if (pdlg.ShowDialog() == DialogResult.OK) { m_StartPage = pdlg.PrinterSettings.FromPage; m_EndPage = pdlg.PrinterSettings.ToPage; doPrintText(pd); //OKがクリックされた時は印刷する pd.Print(); } } private void doPrintText(System.Drawing.Printing.PrintDocument pd) { string strLine = ""; // ファイルオープン System.IO.StreamReader sr = new System.IO.StreamReader(m_PrintFilePath, Encoding.GetEncoding("Shift-JIS")); while (strLine.IndexOf(clsConstants.STR_RESULT_CONTENTS) < 0) { m_PageData = ""; m_PageData = m_PageData + strLine + "\n"; //ページ区切りまで読込 while (strLine.IndexOf(clsConstants.STR_PAGE_TERM) < 0) { strLine = sr.ReadLine(); m_PageData = m_PageData + strLine + "\n"; } //現在のページを取得 m_CurrentPage = 現在ページ取得 //ページ範囲内であれば書き出し if (m_CurrentPage >= m_StartPage && m_CurrentPage <= m_EndPage) { //PrintPageイベントハンドラの追加 pd.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage); } } sr.Close(); } private void pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { DrawPage(e.Graphics, m_PageData); if (m_CurrentPage == m_EndPage) { e.HasMorePages = false; } else { e.HasMorePages = true; } } private void DrawPage(System.Drawing.Graphics g, string strPage) { g.DrawString(strPage, m_Font, Brushes.Black, 10, 10); }
「pd.PrintPage += 」の「+=」は、印刷するページをプールしていて、最後にpd.Printでプールしたページを全て印刷しているのだと思っていたのですが、そこの認識が違うのでしょうか。。。都度printを呼び出す必要があるのでしょうか。
何度も恐れ入りますが、よろしくお願いいたします。
-
PrintPage +=は、イベントハンドラの関連づけです。PrintDocumentオブジェクトがPrintPageイベントを発生させたときに呼び出すメソッドを登録する処理です。これは普通PrintDocumentオブジェクト1つについて1度だけで十分です。
Printメソッドが呼び出されると、PrintDocumentオブジェクトはPrintPageイベントに+=されているメソッドを呼び出し、そのメソッドで1ページ目を描画させます。メソッドから返ってきたら、PrintDocumentオブジェクトはHasMorePagesを調べ、trueであればもう一度同じメソッドを呼び出して2ページ目を描画させます。これをHasMorePagesがfalseになるまで続けます。
MSDNのPrintDocument.PrintPage イベントのサンプルコードがちょうどarubi_momoさんが書こうとなさっている内容にほぼ一致しているようです。(サンプルにするにはwhileの条件とかが少しサンプル向けの記述じゃありませんが)
読み込む対象のStreamReaderがローカル変数ではなく、pd_PrintPageメソッドをもっているクラスのフィールド(メンバ変数)であるのが分かります。
- 回答としてマーク arubi_momo 2014年7月4日 4:03
-
Hongliangさま
お世話になっております。
Hongliangさまのご説明と、提示いただいたページのサンプルで、複数ページの印刷を行うことができました!
本当に本当にありがとうございました。
まだこれから修正するところもあるのですが、とりあえず最終的なコードを載せておきます。
private int m_StartPage = 1; private int m_EndPage = 1; private long m_CurrentPage = 1; private string m_PageData = ""; private string m_PrintFilePath = ""; private Font m_Font; System.IO.StreamReader sr; string m_LineData = ""; private void Print_Click(object sender, EventArgs e) { // ファイルオープン sr = new System.IO.StreamReader(m_PrintFilePath, Encoding.GetEncoding("Shift-JIS")); //PrintDocumentオブジェクトの作成 System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument(); //PrintControllerプロパティをStandardPrintControllerに pd.PrintController = new System.Drawing.Printing.StandardPrintController(); //PrintPageイベントハンドラの追加 pd.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage); //PrintDialogクラスの作成 PrintDialog pdlg = new PrintDialog(); //PrintDocumentを指定 pdlg.Document = pd; //印刷の選択ダイアログを表示する if (pdlg.ShowDialog() == DialogResult.OK) { //OKがクリックされた時は印刷する pd.Print(); } sr.Close(); } private void pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { e.HasMorePages = true; m_PageData = ""; m_PageData = m_PageData + m_LineData + "\n"; //ページ区切りまで読込 while (m_LineData.IndexOf(clsConstants.STR_PAGE_TERM) < 0) { m_LineData = sr.ReadLine(); m_PageData = m_PageData + m_LineData + "\n"; } m_CurrentPage = 現在ページ取得; //ページ範囲内であれば書き出し if (m_CurrentPage >= m_StartPage && m_CurrentPage <= m_EndPage) { DrawPage(e.Graphics, m_PageData); if (m_CurrentPage == m_EndPage) { e.HasMorePages = false; } else { e.HasMorePages = true; } } } private void DrawPage(System.Drawing.Graphics g, string strPage) { g.DrawString(strPage, m_Font, Brushes.Black, 10, 10); }
今後ともよろしくお願いいたします。