質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

1回答

225閲覧

【C#】印刷プレビューには正常に表示されているのに印刷が出来ない

YaMaKaWa

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

1グッド

0クリップ

投稿2025/03/28 12:37

質問内容

C#でテキストファイルをPrintPreviewDialogを使用して印刷するプログラムを組もうとしました。
色々なサイトを回って参考にしながら一旦完成したのですが、プレビュー画面にはテキストファイルの内容が複数ページで正常に表示されているのに、印刷ボタンを押して印刷(今回はPDFに出力)したところ、何も出力されず真っ白な画面1枚分しか出てきませんでした。

該当のソースコード

C#

1public partial class Form1 : Form 2{ 3 const string FilePath = @"C:\DATA\Temp\TestFile.txt"; 4 const decimal Inch = (decimal)25.4; 5 6 int PageMarginTop; 7 int PageMarginBottm; 8 int PageMarginLeft; 9 int PageBottomPositionY; 10 int TextHight; 11 int TextMarginTop; 12 int TextMarginBottom; 13 14 Encoding ShiftJis = Encoding.GetEncoding(932); 15 16 StreamReader sr; 17 18 Font DefFont = new Font("MS ゴシック", 9); 19 Brush DefBrush = new SolidBrush(Color.Black); 20 21 public Form1() 22 { 23 InitializeComponent(); 24 25 PageMarginTop = MmToInch(15); //上余白15mm 26 PageMarginBottm = MmToInch(15); //下余白15mm 27 PageMarginLeft = MmToInch(15); //左余白15mm 28 PageBottomPositionY = MmToInch(297) - PageMarginBottm; //印刷範囲外となるY座標 29 TextHight = MmToInch(5); //テキストの高さ5mm 30 TextMarginTop = MmToInch((decimal)0.5); //テキスト上の余白0.5mm 31 TextMarginBottom = MmToInch((decimal)0.5); //テキスト下の余白0.5mm 32 } 33 34 private void button1_Click(object sender, EventArgs e) 35 { 36 PrintDocument PrtDoc = new PrintDocument(); 37 foreach (PaperSize ps in PrtDoc.PrinterSettings.PaperSizes) 38 { 39 if (ps.Kind == PaperKind.A4) 40 { 41 PrtDoc.DefaultPageSettings.PaperSize = ps; 42 break; 43 } 44 } 45 46 PrtDoc.DefaultPageSettings.Landscape = false; 47 sr = new StreamReader(FilePath, ShiftJis); 48 49 PrtDoc.PrintPage += new PrintPageEventHandler(DocWtr); 50 51 PrintPreviewDialog ppd = new PrintPreviewDialog(); 52 ppd.Document = PrtDoc; 53 ppd.PrintPreviewControl.Zoom = 0.75; 54 ppd.ShowDialog(); 55 56 sr.Close(); 57 } 58 59 private void DocWtr(object sender, PrintPageEventArgs e) 60 { 61 int NowPositionY = PageMarginTop; 62 while (sr.Peek() >= 0) 63 { 64 string rec = sr.ReadLine(); 65 66 e.Graphics.DrawString(rec, DefFont, DefBrush, new PointF(PageMarginLeft, NowPositionY + TextMarginTop)); 67 NowPositionY = NowPositionY + TextMarginTop + TextHight + TextMarginBottom; 68 69 if (NowPositionY >= PageBottomPositionY) 70 { 71 e.HasMorePages = true; 72 break; 73 } 74 else 75 { 76 e.HasMorePages = false; 77 } 78 } 79 } 80 81 int MmToInch(decimal Mm) 82 { 83 decimal a = (Mm / Inch); 84 int b = (int)(a * 100); 85 86 return b; 87 } 88}

テスト用に使用したテキストファイルは別口で以下の記述で100行分作りました。

C#

1const string FilePath = @"C:\DATA\Temp\TestFile.txt"; 2 3if(!File.Exists(FilePath)) 4{ 5 StreamWriter sw = File.CreateText(FilePath); 6 sw.Close(); 7} 8 9using(StreamWriter sw = new StreamWriter(FilePath,false,ShiftJis)) 10{ 11 for (int i = 0; i < 100; i++) 12 sw.WriteLine($"テストデータ:{i:000}"); 13}

試したこと

上記のPrintPreviewDialogを使用した部分(51行目~54行目)をPageSetupDialogやPrintDialogに変更して試しに動かしたところ、どちらも正常にPDFに出力されました。

C#

1//ページ設定ダイアログ 2PageSetupDialog psd = new PageSetupDialog(); 3psd.Document = PrtDoc; 4if (psd.ShowDialog() == DialogResult.OK) 5 PrtDoc.Print(); 6 7//プリンター選択ダイアログ 8PrintDialog pd = new PrintDialog(); 9pd.Document = PrtDoc; 10if (pd.ShowDialog() == DialogResult.OK) 11 PrtDoc.Print();

補足情報(FW/ツールのバージョンなど)

・Visual Studio Community 2022 (64 ビット)
・.Net Framework 4.8

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

何も出力されず真っ白な画面1枚分しか出てきませんでした。

すっごい罠っぽいですがPrintPreviewDialogを使用すると、PrintPageイベント(DocWtr)がダイアログ表示時と実際の印刷時の2セット走ります。
現在の実装ですと印刷時にはStreamReaderを読み終わっているので、(while内を通らず)なにも印刷されません。

一番変更が少ない修正はサンプルのように、最終ページでStreamReaderを頭に戻すことでしょうか。

cs

1private void DocWtr(object sender, PrintPageEventArgs e) 2{ 3 System.Diagnostics.Debug.WriteLine("DocWtr"); 4 var NowPositionY = PageMarginTop; 5 while (sr.Peek() >= 0) 6 { 7 var rec = sr.ReadLine(); 8 9 e.Graphics.DrawString(rec, DefFont, DefBrush, new PointF(PageMarginLeft, NowPositionY + TextMarginTop)); 10 NowPositionY = NowPositionY + TextMarginTop + TextHight + TextMarginBottom; 11 12 if (NowPositionY >= PageBottomPositionY) 13 { 14 e.HasMorePages = true; 15 break; 16 } 17 else 18 { 19 e.HasMorePages = false; 20 } 21 } 22 23 if (!e.HasMorePages) 24 { 25 sr.DiscardBufferedData(); 26 sr.BaseStream.Seek(0, SeekOrigin.Begin); 27 } 28}

知っている人からすれば当たり前なのかもしれませんが、何か注意書きくらい欲しいですね(わたしは知りませんでしたw
ここのさらにサンプルコードの英語コメント中で、さらっと書いてあるのしか見つけられませんでした^^;
印刷プレビューを使用して印刷する - Windows Forms .NET Framework | Microsoft Learn

cs

1// If there are no more pages, reset the string to be printed. 2if (!e.HasMorePages) 3 stringToPrint = documentContents;

投稿2025/03/28 14:25

編集2025/03/29 12:36
TN8001

総合スコア10004

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YaMaKaWa

2025/03/29 13:25

試したところ無事PDFに出力されました!有難うございます。 自分が確認した範囲だと2回通ることは書いてなかったので下手したら一生気づかなかったかも……
TN8001

2025/03/29 14:13

> 試したところ無事PDFに出力されました!有難うございます。 よかったです^^ > 自分が確認した範囲だと2回通ることは書いてなかったので下手したら一生気づかなかったかも…… わたしが気が付いたのは、srがShowDialogを挟んで生存している理由が分からなくて一旦ローカル変数に変更したんですよ。 そうしたらページが生成が止まらなくなって、「なるほどそういうわけね」と仕組みが理解できました^^; この時点で何となく想像はできましたが、検証のためDebug.WriteLineを入れました。 プレビュー時に2回、印刷時に1回表示され確信できました。 理由はわかったけど「これどうやってページ数やプレビュー時・印刷時の判断すりゃいいんだ?」となりましたが、回答中リンクのコードを丁寧に読んでいくと解法がそのまま書いてありましたw わたしのような凡人でも段階を追って順に仮定検証とやっていけば解決できることも多いです^^
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問