开源:.NET环境下有关打印页面设置、打印机设置、打印预览对话框的实现

    技术2022-05-11  167

    作者:长江支流

    开源:.NET环境下有关打印页面设置、打印机设置、打印预览对话框的实现 

      我个人认为,开发MIS,首先就得解决网格的问题,而开发工具为我们提供了如DataGrid、MSHFlexGrid的控件。其次,是打印的问题,将业务单据与数据报表打印出来。可想而知,即使一个业务功能非常完美齐全的管理软件,没有打印的支持,也一定不算是一个完整的软件。

      对于打印,我们总是在用户打印之前可以看看打印的效果,这时,一般的软件都提供了打印预览;如果需要调整打印的效果如纸张的大小、边距的设置,又提供了页面设置对话框让用户选择和调整;如果系统有多个打印机,当用户单击打印按钮时还可以选择输出的对象。

      总之,对于打印,我们至少要提供打印页面设置、打印机设置、打印预览对话框,让用户有更多的机会参与交互。这一些,是一个打印模块比较重要也比较基本的东西,让我们一起来实现它们吧。

      进入Vs2003 IDE,从文件菜单上单击新建项目,项目类型为C#,在模板中选择类库,名称估且叫GoldPrinter,确定即可。在打开的开发环境中,删除解决方案资源管理器中默认生成的Class1.cs。

      现在,我们要考虑一下,对于打印,可能是在Windows下,也可能是Web下。如果将两者的方法统一起来,让调用者不用操心是什么方式下那该多好啊。因此,我们首先设计一个接口,提供两者共用的方法。    在项目上鼠标右键单击后添加一个新类,名称为:IPrinterPageSetting,由于是接口,将class改为interface,并去掉构造函数。看上去应类似如下:using System;namespace GoldPrinter{ /// <summary> /// IPrinterPageSetting 的摘要说明。 /// </summary> public class IPrinterPageSetting {   }}

    方法中至少包含三个声明即ShowPageSetupDialog()、ShowPrintSetupDialog()、ShowPrintPreviewDialog(),也就是打开打印页面设置、打印机设置、打印预览对话框。    Vs2003为我们提供了一个PrintDocument,名字空间是System.Drawing.Printing。PrintDocument是为打印而提供的一个类,它的概述(summary)是这样的:定义一个可再次使用的对象,该对象将输出发送到打印机。

      PrintDocument为我们封装了很多复杂的细节,它有一个至关重要的事件叫PrintPage,PrintPage的概述是:当需要为当前页打的输出时发生。因此,我们只要引发了打印事件,把打印的具体输出的对象交给PrintPage,别的我们就不用操心了。

      那么,我们怎么实现具体输出的过程呢?由于是封装,我们也不可能知道最终用户具体怎么去实现,这时,委托(Delegate)为我们起了大的作用。大家都知道一个函数实现某个功能的时候往往需要一些输入的数据,但是函数本身并不知道这些数据到底是哪个具体的值,只知道这个值的数据类型,这时引入了参数,调用者调用函数据的时候传入相应类型的具体值就行了。大家应该意识到了我的用意,与函数类似,我们为打印提供了关联打印机的方法,但是具体的实现只有由调用者去实现,不同之处是函数传递的是参数,而我们要做的委托传递的是方法。这时,我们只要为两者建立对应关系就可以了,这就是委托。我们需要定义一个委托,参数类型与PrintPage的一致就可以了,即(Object obj,System.Drawing.Printing.PrintPageEventArgs ev)。

      由此可见,我们需要做下面的一些事情:  1、在项目的引用处添加引用,在弹出的对话框的.NET标签中选择System.Drawing.dll,     原因是PrintDocument的名字空间是System.Drawing.Printing,在System.Drawing.dll实现;  2、在IPrinterPageSetting接口中增加PrintDocument属性的声明;  3、定义委托  4、在IPrinterPageSetting接口中增加PrintPage属性的声明,类型为定义的委托;

    以下是IPrinterPageSetting接口文件内容:

    using System;using System.Drawing;using System.Drawing.Printing;

    namespace GoldPrinter{ /// <summary> /// PrintDocument.PrintPage的委托定义 /// </summary> public delegate void PrintPageDelegate(Object obj,System.Drawing.Printing.PrintPageEventArgs ev) ;

     /// <summary> /// IPrinterPageSetting 的接口,显示打印纸张设置、打印机设置、打印预览对话框。 /// 程序提供:周方勇;Email:flygoldfish@sina.com。 /// </summary> public interface IPrinterPageSetting {  /// <summary>  /// 获取或设置打印文档  /// </summary>  System.Drawing.Printing.PrintDocument PrintDocument  {   get;   set;  }

      /// <summary>  /// 关联一个方法,目的是让具体的打印由实例化者来操作  /// 如PrinterPageSetting1.PrintPage += new PrintPageDelegate(this.PrintPageEventHandler);  /// </summary>  PrintPageDelegate PrintPage  {   get;   set;  }

      /// <summary>  /// 显示页面设置对话框,并返回PageSettings  /// </summary>  /// <returns></returns>  System.Drawing.Printing.PageSettings ShowPageSetupDialog();

      /// <summary>  /// 显示打印机设置对话框,并返回PrinterSettings  /// </summary>  /// <returns></returns>  System.Drawing.Printing.PrinterSettings ShowPrintSetupDialog();

      /// <summary>  /// 显示打印预览对话框  /// </summary>  void ShowPrintPreviewDialog();

     }//End Interface}//End NameSpace

      下面,我们以Windows下的编程方式实现,同时也列Web编程下的框架。由于是Windows下的编程,我们可能用到对话框什么的作为错误提示,因此,我们同理要加入System.Windows.Forms.dll引用。再建立一个类文件,名称为WinPrinterPageSetting。进入文件后,在类声明后面加上:IPrinterPageSetting,实现接口功能。程序清单如下,程序中有很多注释,这里不再多说。

    using System;using System.Drawing;using System.Drawing.Printing;using System.Windows.Forms;

    namespace GoldPrinter{ /// <summary> /// WinForm下的打印纸张设置、打印机设置、打印预览对话框。 /// </summary> public class WinPrinterPageSetting:IPrinterPageSetting {  //把PrintPage委托声明为类的一个成员变量  private PrintPageDelegate _printPage;    // 打印文档  private PrintDocument _printDocument;

      #region 构造函数  public WinPrinterPageSetting():this(null)  {     }

      /// <summary>  /// 使用printDocument来初始化类的新实例,当printDocument为null时自动创建一个printDocument的实例  /// </summary>  /// <param name="printDocument"></param>  public WinPrinterPageSetting(PrintDocument printDocument)  {   if (printDocument != null)   {    _printDocument = printDocument;   }   else   {    _printDocument = new PrintDocument();   }  }  #endregion

      #region IPrinterPageSetting 成员

      /// <summary>  /// 获取或设置打印文档  /// </summary>  public PrintDocument PrintDocument  {   get   {    return this._printDocument;   }   set   {    this._printDocument = value;   }  }

      /// <summary>  /// 一定要实例化此类后在调用打印/预览之前设置此属性,使之关联一个方法,目的是让具体的打印由实例化者来操作  /// 如PrinterPageSetting1.PrintPage += new PrintPageDelegate(this.PrintPageEventHandler);  /// </summary>  public PrintPageDelegate PrintPage  {   set   {     //初始委托变量,关联方法    _printPage = value;        if (_printDocument==null)    {     throw new Exception("关联的打印文档不能为空!");    }    _printDocument.PrintPage +=new System.Drawing.Printing.PrintPageEventHandler(this._printPage);   }   get   {    return _printPage;   }    }

      /// <summary>  /// 显示页面设置对话框,并返回PageSettings  /// </summary>  /// <returns></returns>  public PageSettings ShowPageSetupDialog()  {   return ShowPageSetupDialog(this._printDocument);  }

      /// <summary>  /// 显示打印机设置对话框,并返回PrinterSettings  /// </summary>  /// <returns></returns>  public PrinterSettings ShowPrintSetupDialog()  {   return ShowPrintSetupDialog(this._printDocument);  }

      /// <summary>  /// 显示打印预览对话框  /// </summary>  public void ShowPrintPreviewDialog()  {   ShowPrintPreviewDialog(this._printDocument);  }

      #endregion

       //***************注意:以下几个对话框方法可以独立使用***************  #region 页面设置对话框 protected virtual PageSettings ShowPageSetupDialog(PrintDocument printDocument)  /// <summary>  /// 页面设置对话框,可以独立使用  /// </summary>  /// <param name="printDocument"></param>  /// <returns></returns>  /// <remarks>  /// 作    者:周方勇  /// 修改日期:2004-08-07  /// </remarks>  protected virtual PageSettings ShowPageSetupDialog(PrintDocument printDocument)  {   //声明返回值的PageSettings   PageSettings ps = new PageSettings();

       if (printDocument==null)   {    throw new Exception("关联的打印文档不能为空!");   }

       try   {    //申明并实例化PageSetupDialog    PageSetupDialog psDlg = new PageSetupDialog();        //相关文档及文档页面默认设置    psDlg.Document = printDocument;    psDlg.PageSettings = printDocument.DefaultPageSettings;

        //显示对话框    DialogResult result = psDlg.ShowDialog();    if (result == DialogResult.OK)    {     ps = psDlg.PageSettings;     printDocument.DefaultPageSettings = psDlg.PageSettings;    }

       }   catch(System.Drawing.Printing.InvalidPrinterException e)   {    MessageBox.Show("未安装打印机,请进入系统控制面版添加打印机!","打印",MessageBoxButtons.OK,MessageBoxIcon.Warning);   }   catch(Exception ex)   {    MessageBox.Show(ex.Message,"打印",MessageBoxButtons.OK,MessageBoxIcon.Warning);   }

       return ps;  }  #endregion

      #region 打印设置对话框 protected virtual PrinterSettings ShowPrintSetupDialog(PrintDocument printDocument)  /// <summary>  /// 打印设置对话框,可以独立使用  /// </summary>  /// <param name="printDocument"></param>  /// <returns></returns>  /// <remarks>  /// 作    者:周方勇  /// 修改日期:2004-08-07  /// </remarks>  protected virtual PrinterSettings ShowPrintSetupDialog(PrintDocument printDocument)  {   //声明返回值的PrinterSettings   PrinterSettings ps = new PrinterSettings();   if (printDocument==null)   {    throw new Exception("关联的打印文档不能为空!");   }

       try   {    //申明并实例化PrintDialog    PrintDialog pDlg = new PrintDialog();        //可以选定页    pDlg.AllowSomePages = true;

        //指定打印文档    pDlg.Document = printDocument;

        //显示对话框    DialogResult result = pDlg.ShowDialog();    if (result == DialogResult.OK)    {     //保存打印设置     ps = pDlg.PrinterSettings;     //打印     printDocument.Print();    }

       }   catch(System.Drawing.Printing.InvalidPrinterException e)   {    MessageBox.Show("未安装打印机,请进入系统控制面版添加打印机!","打印",MessageBoxButtons.OK,MessageBoxIcon.Warning);   }   catch(Exception ex)   {    MessageBox.Show(ex.Message,"打印",MessageBoxButtons.OK,MessageBoxIcon.Warning);   }

       return ps;  }  #endregion

      #region 打印预览对话框 protected virtual void ShowPrintPreviewDialog(PrintDocument printDocument)  /// <summary>  /// 打印预览对话框,可以独立使用  /// </summary>  /// <param name="printDocument"></param>  /// <returns></returns>  /// <remarks>  /// 作    者:周方勇  /// 修改日期:2004-08-07  /// </remarks>  protected virtual void ShowPrintPreviewDialog(PrintDocument printDocument)  {   if (printDocument==null)   {    throw new Exception("关联的打印文档不能为空!");   }

       try   {    //申明并实例化PrintPreviewDialog    PrintPreviewDialog ppDlg = new PrintPreviewDialog();        //指定打印文档    ppDlg.Document = printDocument; 

          //显示对话框    DialogResult result = ppDlg.ShowDialog();    if (result == DialogResult.OK)    {     //...    }

       }   catch(System.Drawing.Printing.InvalidPrinterException e)   {    MessageBox.Show("未安装打印机,请进入系统控制面版添加打印机!","打印",MessageBoxButtons.OK,MessageBoxIcon.Warning);   }   catch(Exception ex)   {    MessageBox.Show(ex.Message,"打印",MessageBoxButtons.OK,MessageBoxIcon.Warning);   }  }  #endregion

     }//End Class}//End NameSpace

      大家可以看到了#region指定,它与#endregion一起使用,可以把中间的文本折叠起来,很方便,需要查看的时候就单击前面的展开符号。后三个函数是比较重要的方法,同时提供它们的重载函数。ShowPageSetupDialog()与ShowPrintSetupDialog()返回用户确认的当前设置选择。

      再建立一个类文件,名称为WebPrinterPageSetting。进入文件后,在类声明后面加上:IPrinterPageSetting,实现接口功能。程序清单如下:

    using System;

    namespace GoldPrinter{ /// <summary> /// WebForm下的打印纸张设置、打印机设置、打印预览对话框。(***暂无具体实现***) /// </summary> public class WebPrinterPageSetting:IPrinterPageSetting {  public WebPrinterPageSetting()  {   //   // TODO: 在此处添加构造函数逻辑   //  }

      #region IPrinterPageSetting 成员

      public System.Drawing.Printing.PrintDocument PrintDocument  {   get   {    // TODO:  添加 WebPrinterPageSetting.PrintDocument getter 实现    return null;   }   set   {    // TODO:  添加 WebPrinterPageSetting.PrintDocument setter 实现   }  }

      public PrintPageDelegate PrintPage  {   get   {    // TODO:  添加 WebPrinterPageSetting.PrintPage getter 实现    return null;   }   set   {    // TODO:  添加 WebPrinterPageSetting.PrintPage setter 实现   }  }

      public System.Drawing.Printing.PageSettings ShowPageSetupDialog()  {   // TODO:  添加 WebPrinterPageSetting.ShowPageSetupDialog 实现   return null;  }

      public System.Drawing.Printing.PrinterSettings ShowPrintSetupDialog()  {   // TODO:  添加 WebPrinterPageSetting.ShowPrintSetupDialog 实现   return null;  }

      public void ShowPrintPreviewDialog()  {   // TODO:  添加 WebPrinterPageSetting.ShowPrintPreviewDialog 实现  }

      #endregion

     }//End Class

    }//End NameSpace

      做到了这一步,大家可能说已经可以了,确实如此。因为在调用的时候实例化WinPrinterPageSetting/WebPrinterPageSetting并调用它的方法或属性就可以了。大家再想想我为什么要提供IPrinterPageSetting呢?如果我现在调用打印对话框,我也不管是Windows下还是Web下的,这时,IPrinterPageSetting就发挥了作用。

    例如:IPrinterPageSetting _printerPageSetting;申明了一个打印接口对象,以后就可以直接调用它的方法了,但是到底是Windows模式还是Web模式呢,我们只需要让程序自己去根据系统去实例为真正的WinPrinterPageSetting或WebPrinterPageSetting了。如:

    //创建接口对象的新实例,使其指象真正的实现其接口的对象if (Windows模式){ _printerPageSetting = new WinPrinterPageSetting();}else if(Web模式){ _printerPageSetting = new WebPrinterPageSetting();}在接下来的程序清单中我们可以看到这个效果。我们再建立一个PrinterPageSetting类,将WinPrinterPageSetting与WebPrinterPageSetting合二为一。在类的构造函数中增加自动判断Windows模式还是Web模式,同时也提供PrintMode属性可以让用户修改。程序清单如下:

    using System;using System.Drawing;using System.Drawing.Printing;using System.Windows.Forms;

    namespace GoldPrinter{

     /// <summary> /// 打印方式 /// </summary> public enum PrintModeFlag {  /// <summary>  /// Windows窗口打印方式  /// </summary>  Win   ,  /// <summary>  /// Web窗口打印方式  /// </summary>  Web  }

     

     /// <summary> /// 封装页面设置、打印机设置、打印预览,适合于Window和Asp.Net。 /// 程序提供:周方勇;Email:flygoldfish@sina.com。 /// </summary> public class PrinterPageSetting {  //申明一个封装页面设置、打印机设置、打印预览的接口  private IPrinterPageSetting _printerPageSetting;

      //打印方式  private PrintModeFlag _printModeFlag;

      public PrintModeFlag PrintMode  {   get   {    return this._printModeFlag;   }   set   {    this._printModeFlag = value;    //运用了抽象模式,创建接口对象的新实例,使其指象真正的实现其接口的对象   if (this._printModeFlag == PrintModeFlag.Win)   {    _printerPageSetting = new WinPrinterPageSetting();   }   else if(this._printModeFlag == PrintModeFlag.Web)   {    _printerPageSetting = new WebPrinterPageSetting();   }   }  }

      /// <summary>  /// 获取或设置打印文档  /// </summary>  public PrintDocument PrintDocument  {   get   {    return _printerPageSetting.PrintDocument;   }   set   {    _printerPageSetting.PrintDocument = value;   }  }

      /// <summary>  /// 一定要实例化此类后在调用打印/预览初始此变量,使之关联一个方法,目的是让具体的打印由实例化者来操作  /// 如PrinterPageSetting1.PrintPage += new PrintPageDelegate(this.PrintPageEventHandler);  /// </summary>  public PrintPageDelegate PrintPage  {   set   {     _printerPageSetting.PrintPage = value;   }   get   {    return _printerPageSetting.PrintPage;   }  }

     

      #region 构造函数  /// <summary>  ///  封装页面设置、打印机设置、打印预览,适合于Window和Asp.Net,Web方式下请在配置文件中增加键PrintMode及值Web,也可以实例化后设置PrintMode属性为PrintModeFlag.Web。  /// </summary>  public PrinterPageSetting():this(null)  {     }

      /// <summary>  ///  封装页面设置、打印机设置、打印预览,适合于Window和Asp.Net,Web方式下请在配置文件中增加键PrintMode及值Web,也可以实例化后设置PrintMode属性为PrintModeFlag.Web。  /// </summary>  /// <param name="printDocument"></param>  public PrinterPageSetting(PrintDocument printDocument)  {   string strPrintMode = "";

       //配置文件中键PrintMode   strPrintMode = System.Configuration.ConfigurationSettings.AppSettings["PrintMode"];

       if (strPrintMode == null)   {    //默认为Win方式       strPrintMode = "Win";   }

       //配置文件中键PrintMode的值Win/Web   if (strPrintMode.ToUpper() == "WIN")   {    this.PrintMode = PrintModeFlag.Win;   }   else   {    this.PrintMode = PrintModeFlag.Web;      }

       /*  //配置文件中添加键值的写法    <?xml version="1.0" encoding="utf-8" ?>    <configuration>     <appSettings>       <add key="PrintMode" value="Web"/>      </appSettings>    </configuration>   */

       _printerPageSetting.PrintDocument = printDocument;

      }  #endregion

      /// <summary>  /// 显示页面设置对话框,并返回PageSettings  /// </summary>  /// <returns></returns>  public PageSettings ShowPageSetupDialog()  {   return _printerPageSetting.ShowPageSetupDialog();  }

      /// <summary>  /// 显示打印机设置对话框,并返回PrinterSettings  /// </summary>  /// <returns></returns>  public PrinterSettings ShowPrintSetupDialog()  {   return _printerPageSetting.ShowPrintSetupDialog();    }

      /// <summary>  /// 显示打印预览对话框  /// </summary>  public void ShowPrintPreviewDialog()  {   _printerPageSetting.ShowPrintPreviewDialog();  }

     }//End Class}//End NameSpace

      在这个类的构造函数中,提到了配置文件。在建立Asp.Net应用程序的时候自动会生成一个名为WebMIS.Config的文件,文件里有一些环境和其它信息的设置,可以简单的理解为为程序提供一个外部设置的接口,提高应用程序的灵活性。在建立Windows应用程序的时候默认情况下没有这样的文件,但是可以在项目上单击鼠标右键添加新项,选择应用程序配置,默认的配置文件名为App.config。在构造函数中我们默认为Win下的打印,如果是Web方式下,可以在配置文件中增加键PrintMode及值Web,也可以实例化后设置PrintMode属性为PrintModeFlag.Web。下面是在配置文件中添加键值的写法    <?xml version="1.0" encoding="utf-8" ?>    <configuration>     <appSettings>       <add key="PrintMode" value="Web"/>      </appSettings>    </configuration>

      至此,关于NET环境下有关打印页面设置、打印机设置、打印预览对话框的实现全部结束,我们可以将程序编译成一个动态库了。在接下来的文章中,我们一起看看怎么应用这个动态库,并且以一个完整的单据、报表打印程序为例进一步说明。

    本文全部源码及各种打印免费下载:www.webmis.com.cn 

    声明:本文版权为周方勇所有,如需转载,请保留完整的内容及出处。


    最新回复(0)