65.9K
CodeProject 正在变化。 阅读更多。
Home

FormPrint 作为简单的类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.95/5 (8投票s)

2006年12月22日

CPOL

6分钟阅读

viewsIcon

105119

downloadIcon

2075

一篇关于如何打印(或另存为位图文件)WinForms 或任何其他控件的文章。

引言

“私有类”FormPrint 使您能够将任何窗体或其他控件硬编码打印到打印机或图像文件。为此,该类使用公共静态方法Print()Save()。这对于开发人员或用户的文档记录和调试目的可能很有用。

我在讨论区找到的其他解决方案太庞大和复杂,无法简单使用。因此,我决定创建自己的解决方案。

使用代码

代码是为 NET 2.0 编写的。适应 NET 1.1 的方法将在本文后面介绍。

在源代码中插入对该类的引用

using JThomas.Tools;

如果您将此类放入名为Tools 的单独程序集中,您当然需要在您的应用程序中引用Tools.Dll

在源代码中插入,例如,在按钮或ToolStripMenuItemClick 事件中,使用指定的窗体或控件调用该类的方法。

要打印的版本

以下是一些打印示例

/// print the actual form on the default printer with default settings
FormPrint.Print(this);

/// print another form that may not call a null reference, of course
FormPrint.Print(WinForm2);

/// print any control on the default printer with default settings, e.g.:
FormPrint.Print(panel1);

/// print using special settings: 8 bpp pixelformat, another printer, 
/// your own margins instead of the default ones, landscape orientation
Margins aMargins = new System.Drawing.Printing.Margins(80,50,40,40);
FormPrint.Print(this, ColorDepthReduction.Colored8bpp, 
  "PDF Printer", aMargins, false);

要保存的版本

以下是一些保存示例

/// Save: this version sets filename and uses png format
FormPrint.Save(this, "E:\\Temp\\MainForm.Png");
/// Save: this version sets ImageFormat and filename with standard folder
FormPrint.Save(listBox1, System.Drawing.Imaging
  .ImageFormat.Bmp, "Listbox.Bmp");

大多数参数都可以省略。

所有版本的参数

Control Ctrl 表示要打印或保存的窗体或任何其他控件。此参数是强制性的。

ImageFormat fImage 指定位图的保存方式;如果省略,则使用ImageFormat.Png。打印始终使用 png 格式。

打印参数

ColorDepthReduction f8bitPixel 说明如何打印位图:标准是None,即 PixelFormat.Canonical 作为 32 位颜色;Colored8bpp 将位图转换为 PixelFormat.Format8bppIndexed,而Grayscaled8bpp 转换为 8bpp 灰度。请参阅后面的“打印机问题”。

string sPrinterName 说明要使用标准打印机以外的其他打印机。如果省略,则使用标准打印机。

Margins aMargins 设置特殊的页边距。如果省略,则使用当前打印机的默认边距。

bool bPortrait 设置方向为纵向(true)或横向(false)。如果省略,则方向设置为纵向。

保存参数

string sFileName 包含完整的文件名。如果它只是一个没有路径的文件名,则位图保存在当前文件夹中。如果省略文件名,则会创建一个标准文件名,格式为:用户文件夹‘MyPictures’,控件名称,以及imageformat 的扩展名。

工作原理

FormPrint 类为所需的窗体或控件创建一个bitmap 对象。将其发送到标准打印机或以适当的格式保存到文件。您可以调用实际的窗体或其他应用程序中的窗体,也可以调用任何其他控件(例如,GroupBoxPanel 等)。所有这些都组合在一个简单的类FormPrint 中。

FormPrint 类包含以下私有变量

//  The FormPrint instance cls is used to execute printing resp. saving.
static FormPrint cls;
//  The bitmap bmp contains the copy of the control's graphics.
Bitmap bmp;
//  deciding whether to print or save
bool Printing;
//  additional: variables related to each of the parameters 
//  mentioned above

您可以使用重载的静态方法FormPrint.Print()FormPrint.Save() 并指定所需参数。如果省略某个参数,将使用默认值。

所有变体都调用一个私有静态方法FormPrint.Start() 来执行工作:首先,它检查所有必需的参数是否已设置。然后,创建FormPrint 类的一个私有实例cls,并将所有参数传递给它。最后,私有方法StartPrinting()StartSaving() 执行底层工作。

//  create the private formprint class cls
cls = new FormPrint(Ctrl, bPrint, fImage, f8bitPixel, 
        sPrinterName, aMargins,  bPortrait, sFileName);
//  execute the required printing resp. saving method
try {
    if (bPrint) {
        cls.StartPrinting();
    } else {
        cls.StartSaving();
    }        
} finally {
    //  free resources
    cls.bmp.Dispose();
    cls.bmp = null;
    //  in some situations, the next command is useful
    Ctrl.Refresh();
}

构造函数创建一个Bitmap 对象bmp,该对象的大小和图形与控件相同,并将控件的屏幕内容复制到Bitmap 对象bmp 中。

private FormPrint(Control Ctrl, bool bPrint,
    //      formatings, convertings
    ImageFormat fImage, ColorDepthReduction f8bitPixel
    //  additional parameters for printing
    string sPrinterName, Margins aMargins, bool bPortrait,
    //  additional parameter for saving
    string sFileName)
{
    //  call the bitmap in the propriate way - NET 1.1 or NET 2.0
    ctrl = Ctrl;
    bmp = GetBitmap(Ctrl);

    /*  set all other parameters ... these instructions are removed here  */

}

在 NET 2.0 下,可以使用一条指令复制控件的图像。

//  NET 2.0 - Copy the control's graphics directly to the bitmap
private Bitmap GetBitmap(Control Ctrl) {
    //  prepare the bitmap
    Graphics grCtrl = Ctrl.CreateGraphics();
    Bitmap Result = new Bitmap(Ctrl.Width, Ctrl.Height, 
    grCtrl);

    //  copy the control's graphics – not available 
    with NET 1.1
    Ctrl.DrawToBitmap( Result, new Rectangle(0, 0, 
    Ctrl.Width, Ctrl.Height));

    //  that's all work for the bmp using NET 2.0 
    //  instructions
    return Result;
}

在 NET 1.1 下,必须使用复杂的 Windows GDI 解决方法。因此,这项工作由一个单独的方法GetBitmap() 完成。如果您想了解更多信息,请查看源代码。

如果您想打印,bmp 会被发送到PrintDocument。如果需要,会使用一些指令(但在以下代码片段中未显示):应用打印机名称或页面设置,将大位图压缩到纸张大小,将 32bpp 位图转换为 8bpp 位图以避免打印机内存问题。

private void StartPrinting() {
    //  create a document; the event handler PrintPage
    //  will connect it with the bitmap
    using(PrintDocument doc = new PrintDocument()){
        doc.PrintPage += new PrintPageEventHandler(
            doc_PrintPage);

        //  setting printer name and page settings, 
        //  if required

        //  if margins are set, then check if bitmap has to
        //  be compressed
        if (PrinterMargins != null) {
            //  check if bmp size is larger than PaperSize
            if ( (bmp.Width > bmpX) || (bmp.Height > 
                  bmpY) ) 
                GetThumbnail((int)bmpX, (int)bmpY);
        }
        //  convert to 8-bit-pixel or grayscale to avoid 
        //  printer problems
        if (format8bitPixel != ColorDepthReduction.None) {
            ConvertBitmapTo8Bpp(15);

        //  now print
        doc.DocumentName = SaveFileName;
        doc.Print();
    }
}

如果您想保存,则直接通过

bmp.Save(SaveFileName, formatImage);

此外,代码包含一些try-catch 块,用于将bmp 连接到PrintDocumentPrintPageEventHandlerdoc,释放资源,以及用于压缩位图的实用工具GetThumbnail()ConvertBitmapTo8Bpp().

由于转换可能需要几秒钟,因此包含一个带有简单标签的ProgressForm。仅当打印的位图像素超过 40,000 个(例如 200x200)时才显示此内容。

附加使用提示

如果您通过MenuItem.Click 事件调用该方法,则应使用ShortCut;否则,打开的菜单也会被复制。请注意:始终打印或保存实际屏幕内容;如果窗体部分隐藏,则打印前景屏幕。不匹配的控件不总是能正确打印,例如工具栏上的普通按钮。如果设置了Control.AutoScroll,则必须注意 SDK 文档。

适应 NET 1.1

两条指令与 NET 1.1 不兼容;其中一条需要复杂的解决方法。要进行适应,请设置适当的#define 指令

/// with NET 2.0 use as follows:
#define NET_V20
#undef  NET_V11
/// with NET 1.1 use as follows:
#define NET_V11
#undef  NET_V20

打印机问题

在这两个版本中,全屏窗体都可能导致打印机问题,例如“内存不足”或“数据过多”。如果出现这种情况,请尝试使用 8 位像素格式,通过ColorDepthReduction f8bitPixel 参数。如果问题仍然存在,您应该打印一个较小的控件,例如面板或组框,而不是整个窗体。在这种情况下,我建议您将窗体与一些控制要打印的设置组合起来。

演示窗体

要创建演示应用程序,请使用FormPrintDemoForm.cs 作为主窗体,FormPrint.cs 作为附加类。该窗体包含一个列表框,用于选择FormPrint.Print()FormPrint.Save() 的任何变体,以及一个带有 256 色标签的面板。您需要在buttonStart_Click() 方法中更改常量值,并在构造函数中更改richTextBox1.LoadFile() 调用。

可能的扩展

我选择了比最初计划更多的参数。我省略了以下可能性

  • 页面设置对话框
  • 如果文件保存成功,则显示消息框

感谢帮助

最初,我采用了 MSDN 库中的方法 如何:打印 Windows 窗体

Tim van Wassenhove 告诉我使用DrawToBitmap()

“Programmierhans”在 NET 1.1 中演示了如何复制控件的图形,并在他 2005 年 8 月 2 日 19:49 的帖子中提到了GetThumbnail() 方法。

Robert Schmitz "robertico" 开发了将位图快速转换为 8bpp 像素格式和灰度图的方法ConvertBitmapTo8Bpp()。(使用 GetPixel/SetPixel 的 MSDN 解决方案需要不可接受的时间。)

我的目标是将所有这些结合成一个带有可变参数的简单类。

历史

  • 2006/12/17 - 第一个版本。

  • 12/19/2006
    1. 添加:清除资源(位图、图形)
    2. 添加:纵向或横向打印

  • 12/24/2006
    1. 更改:一种更短的将控件图形复制到位图中的方法
    2. 更改注释:目前没有适应 NET 1.1。

  • 12/25/2006
    1. 添加:使用 NET 1.1 将控件图形复制到位图中
    2. 更改:变量和方法重新分组,但没有其他功能
    3. 更改注释:适应 NET 1.1
    4. 添加注释:已知问题,感谢帮助

  • 01/13/2007
    1. NET 1.1 更改:窗体可包含标题和菜单栏进行打印
    2. 更改:公共方法 Execute() 分割为 Print() 和 Save()
    3. 更改:Print() 允许多个参数:PrinterName、Margins、Orientation
    4. 更改:打印可以根据需要压缩到纸张大小(带边距)
    5. 更改:大多数参数都可以省略
    6. 更改:通过转换为 PixelFormat.Format8bppIndexed 和灰度位图来管理打印机内存问题,而不是彩色 PixelFormat.Canonical
    7. 更改:Execute() 在打印大型控件(超过 40000 像素,例如 200x200)时使用进度标签
    8. 更改:私有方法 Execute() 分割为 StartPrinting() 和 StartSaving()

  • 01/22/2007
    1. 更改:通过 #define 适应 NET 1.1
    2. 更改:PixelFormat.Format8bppIndexed 和灰度图替换为 ColorDepthReduction 枚举

  • 03/22/2007
    NET 2.0 改进了 RichTextBox 或 WebBrowser 的显示(这些控件无法使用 DrawToBitmap)

© . All rights reserved.