C#
CustomPreviewControl
PrintDocumentで印刷中のダイアログを表示させない方法
印刷するときなら、印刷中のダイアログを表示させないのは簡単で、ただPrintControllerを入れ替えるだけ。
PrintController SavedController = Document.PrintController;
try
{
Document.PrintController = new StandardPrintController();
Document.Print();
}
finally
{
Document.PrintController = SavedController;
}
印刷は時間がかかるので、実際には印刷中のダイアログが出てくれたほうが都合が良い。動いていることがわかるので、ユーザーにとっても安心なはず。
問題はプレビューのほうで、PrintPreviewControlやPrintPreviewDialogを使うと、どうしても印刷中のダイアログが表示されてしまうが、うっとうしいのでやめてほしい場合がある。
例えば100ページの印刷ドキュメントがあるとして、何かのプロパティーを変えるだけで、毎回プレビューで100ページ表示されると、いちいち時間がかかって困るので、プレビューは最初の1ページだけで良いと言われることがある。そういうときの印刷中のダイアログは、これもうっとうしくてかなわないので、表示されないほうが良い。
カスタマイズしたいことはひとつだけなのに、これを実現するにはカスタムコントロールを作るしかない。だいたい、細かいところを直そうとすると、低レベルのところから作る羽目になるものだ。
印刷中のダイアログを表示させない方法は、プレビューでも基本的に同じ。簡単なサンプルを書いておく。CreatePreview()のところ。
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
public class CustomPreviewControl : Control
{
private PrintDocument _Document;
private PreviewPageInfo[] _Pages;
private int _PageCount;
private int _PageNo;
private float _Scaling;
private bool _IsCreatePreview;
[Description("印刷ドキュメントを取得または設定します。")]
public PrintDocument Document
{
get
{
return _Document;
}
set
{
_Document = value;
InvalidatePreview();
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int PageCount
{
get
{
return _PageCount;
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int PageNo
{
get
{
return _PageNo;
}
set
{
if ((_PageNo != value) && (value > 0) && (value <= _PageCount))
{
_PageNo = value;
Invalidate();
}
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public float Scaling
{
get
{
return _Scaling;
}
}
public CustomPreviewControl()
{
SetStyle(ControlStyles.Selectable, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
Padding = new Padding(10);
_Document = null;
_Pages = null;
_PageCount = 0;
_PageNo = 0;
_Scaling = 0.0f;
_IsCreatePreview = false;
}
public void InvalidatePreview()
{
_IsCreatePreview = (_Document != null);
Invalidate();
}
private void CreatePreview()
{
PrintController SavedController = _Document.PrintController;
try
{
PreviewPrintController PreviewController = new PreviewPrintController();
PreviewController.UseAntiAlias = true;
_Document.PrintController = PreviewController;
_Document.Print();
_Pages = PreviewController.GetPreviewPageInfo();
_PageCount = (_Pages != null) ? _Pages.Length : 0;
_PageNo = (_PageCount > 0) ? 1 : 0;
}
catch
{
_Pages = null;
_PageCount = 0;
_PageNo = 0;
throw;
}
finally
{
_Document.PrintController = SavedController;
_IsCreatePreview = false;
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
pevent.Graphics.FillRectangle(SystemBrushes.AppWorkspace, pevent.ClipRectangle);
}
protected override void OnPaint(PaintEventArgs pe)
{
if (_Document == null)
{
return;
}
if (_IsCreatePreview)
{
CreatePreview();
}
if ((_PageNo <= 0) || (_PageNo > _PageCount))
{
return;
}
RectangleF ClientRect = ClientRectangle;
ClientRect.X += Padding.Left;
ClientRect.Y += Padding.Top;
ClientRect.Width -= Padding.Horizontal;
ClientRect.Height -= Padding.Vertical;
Image PageImage = _Pages[_PageNo - 1].Image;
float WidthRate = ClientRect.Width / PageImage.Width;
float HeightRate = ClientRect.Height / PageImage.Height;
_Scaling = (WidthRate < HeightRate) ? WidthRate : HeightRate;
RectangleF Rect = new RectangleF();
Rect.Width = _Scaling * PageImage.Width;
Rect.Height = _Scaling * PageImage.Height;
Rect.X = ClientRect.Left + 0.5f * (ClientRect.Width - Rect.Width);
Rect.Y = ClientRect.Top + 0.5f * (ClientRect.Height - Rect.Height);
pe.Graphics.FillRectangle(Brushes.White, Rect);
pe.Graphics.DrawImage(PageImage, Rect);
}
}
印刷中のダイアログがうっとうしいだけで、本当は何ページ目を作っているかステータスバーにでも通知してくれるとありがたい。そうなっていればもっと汎用的に使えそうだ。つまり、プレビューを作るところを別スレッドにすれば、さらに良いかもしれない。
固定Scalingとか、スクロールバーやページ移動とか、実際に使うなら加えたい機能がいろいろあると思う。カスタムコントロールの開発はなかなか大変だ。
(2023/12/08 初稿)