打印 
         打印对于许多 Windows 程序员来说是十分棘手的问题。

Delphi 简化了打印时用户所必须了解的大部分内容。用户可以很轻松地写出简单的打印程序来输出文本和位图化了的图像。
对于更为复杂的打印,仅需了解几个要领和技术,用户就可以实现任何类型的自定义打印。
当了解了这些后,打印也就不那么困难了。 
Delphi 的TPrinter对象封装了 Windows 的打印引擎,为程序员做了大量原本需要亲自做的工作。

本章告诉用户怎样用TPrinter来完成各种打印作业。用户可以看到一个简单的例子,
从中可以了解到创建高级打印程序的技术,而这些技术正是用户成为打印高手的起点。

5.1  TPrinter 对象 
        Delphi 中的 TPrinter类可以方便地实现通常的打印任务。通过Printer 全局函数可以返回TPrinter类的一个对象,该对象在Printers单元中定义。

可以把Printer 全局函数看作一个全局变量,并利用这个全局变量来与打印机进行打印操作。 
利用 Printer 来实现打印的一般过程如下: 
(1)调用BeginDoc 过程向打印机发送一个打印作业(此时还没有在打印机上开始打
印)。 
(2)通过一个 Text 变量或调用 Canvas 对象方法建立打印输出。 
(3)调用 EndDoc过程结束当前的打印作业,该打印作业开始在打印机上打印。 
(4)如果出现问题,调用 Abort过程取消当前打印的作业。 
表5-1 所示是 TPrinter对象的几个常用属性:

表5-1  TPrinter对象的常用属性 
属性  作用 
Aborted  判断是否中止打印作业 
Canvas  画布属性 
Capabilities  当前打印机驱动设备的设置信息 
Copies  打印的份数 
Fonts  字体属性 
Handle  打印机句柄 
Orientation  纸张的方向:横向或纵向 
PageHeight  纸张的高度 
PageNumber  当前打印的页数 
PageWidth  纸张的宽度 
Printers  系统中安装的所有打印机 
Printing  标识是否正在进行一个打印作业 
PrinterIndex  打印机属性中当前打印机的索引值

表5-2 所示是 TPrinter对象的几个常用方法 
表5-2  TPrinter的方法 
方法  作用 
Abort  中止正在打印的打印作业 
BeginDoc  向打印机发送一个打印作业 
EndDoc  结束当前的打印作业并关闭文本文件变量 
GetPrinter  获得当前打印机序号 
NewPage  开始新的一页并增加 PageNumber属性 
Refresh  更新字体和打印机的属性

通常,在打印前要进行打印预览。在打印预览的时候,往往要将打印的结果在屏幕上显示出来。

这时,就要注意屏幕的分辨率和打印机的分辨率的差别了。读取屏幕信息可以通过全局变量 Screen 来实现,Screen 为TScreen类的一个实例,在创建工程的时候就自动创建了,并在程序开始运行时读取了屏幕的一些设置信息。

值得注意的一点是 TPrinter.Canvas。TPrinter.Canvas 对于窗体来说像一个画布,在它上面可以显示文本和图形。

不同的是, TPrinter.Canvas 表示的是打印输出的画布,而非显示用的画布。大多数用来显示文本、图像和画图的程序可以用同一种方式来打印输出。

但是,在打印时必须考虑到其中的不同之处: 
        ¾  在屏幕上绘画是动态的,可以擦去在屏幕上输出的内容。而向打印机中输出则不那么灵活,凡是向 TPrinter.Canvas 输出的内容将被打印机打印出来。 
       ¾  在屏幕上显示文本和图是很快的,而向打印机输出,即使是高性能的激光打印机,也是较慢的。因此,必须允许用户能够终止打印作业或者采用其他办法来放弃打印作业。 
      ¾  由于用户运行的是 Windows,可以假定支持图形显示。但是,不能对他们的打印机做同样的假定。一些打印机也许具有非常低的分辨率,或者根本不支持图形打印。在打印程序中必须考虑到这些问题。 
       ¾  用户从来没有看到过诸如“显示超出屏幕空间”、“请插入更多的屏幕空间”此类的信息,但是肯定见过“打印纸不够”的信息。当这些错误发生时, Windows NT/2000 和Windows 95/98能够处理这些错误,但程序员应该向用户提供在发生这些问题时取消打印的办法。 
        ¾  对于屏幕上的文本和图形来说,硬拷贝操作看起来是不同的。打印机和显示器具有非常不同的分辨率。300×300 的位图在 640×480 的显示器中显得很漂亮。但是在300dpi 的激光打印机上,它仅仅是一个1×1 inch 的小方块。程序员必须负责调整打印程序,使用户不必用放大镜就可以看清他们的打印输出。

5.2   打印操作常用函数 
表5-3  Windows API打印操作常用函数 
函数  说明 
AbortPrinter  在假脱机的情况下删除打印缓冲文件 
AbortProc  当打印作业取消时调用的一个应用程序定义的回调函数 
AddForm  为指定的打印机从有效窗体列表中新增一个窗体 
AddJob  获取一个文件名用来保存打印缓冲工作 
AddMonitor  新安装一个打印机管理器 
AddPort  新增一个打印机端口 
AddPrinter  在指定的服务器上新安装一个打印机 
AddPrinterConnection  在当前用户和指定的打印机之间建立一个联系 
AddPrinterDriver  为本地或网络打印机安装打印机驱动程序 
AddPrintProcessor  在指定的打印服务器上安装一个打印处理器 
AddPrintProvidor  新增一个打印机支持器 
AdvancedDocumentProperties  设置打印机的高级属性 
ClosePrinter  关闭指定的打印机 
ConfigurePort  通过端口设置对话框来设置指定服务器上的端口 
ConnectToPrinterDlg  显示一个浏览对话并与网络打印机连接 
DeleteForm  从窗体列表中删除一个窗体名称 
DeleteMonitor  删除打印机监视器 
DeletePort  删除打印机端口 
DeletePrinter  删除指定的打印机对象 
DeletePrinterConnection  删除一个打印机连接 
DeletePrinterData  删除打印机的配置数据 
DeletePrinterDriver  删除指定打印机的驱动程序 
DeletePrintProcessor  删除一个打印机的处理器 
DeletePrintProvidor  删除一个打印机的支持器 
DocumentProperties  取得或设置打印机的初始化信息或显示打印机配置对话框 
EndDocPrinter  结束指定打印机上的打印作业 
EndPagePrinter  在指定打印机上结束一页并开始新的一页 
EnumForms  列举打印机支持的窗体信息 
EnumJobs  获取打印机的作业信息 
EnumMonitors  获取指定服务器上的打印监视器信息 
EnumMonitors  获取指定服务器上的打印监视器信息 
EnumPorts  列举指定服务器上支持的端口信息 
GetPrinter  获取指定打印机的信息 
GetPrinterData  获取指定打印机的配置信息 
GetPrinterDriver  获取指定打印机驱动程序的数据信息 
GetPrinterDriverDirectory  获取指定打印机驱动程序所在的目录 
GetPrintProcessorDirectory  获取指定服务器上打印处理器所在的目录 
OpenPrinter  获取指定打印机或服务器的句柄 
128   第5 章   打印 
  (续表) 
函数  说明 
PrinterMessageBox  显示打印异常信息对话框 
PrinterProperties  显示指定打印机的属性对话框 
ReadPrinter  从指定的打印机读取数据 
ResetPrinter  设置打印机的数据类型和设备模式等 
ScheduleJob  获取指定打印作业的打印缓冲时间表 
SetForm  设置指定打印机的窗体信息 
SetJob  暂停、继续、取消和重新开始指定打印机上的打印作业 
SetPort  设置打印机端口的状态 
SetPrinter  设置打印机的状态信息 
SetPrinterData  设置打印机的配置信息 
StartDocPrinter  通知打印缓冲器一个打印作业将被送往打印 
StartPagePrinter  通知打印缓冲器一个页面将送往打印 
WritePrinter  通知打印缓冲器数据将被写到指定的打印机

5.3   打印操作 
这一节我们为读者介绍实现简单的打印输出的方法。 
5.3.1   打印文本 
         在Delphi 中实现文本的打印功能需要做的只是取得打印参数,打开打印机,然后发送文本的每一行内容。

在 Delphi 中提供了一个 Printers程序单元,它说明了一个 TPrint 对象,封装了Windows 打印工作和输出打印机之间的接口,并提供常用的属性和方法,其中画布Canvas 是一个非常有用的属性,它代表了当前打印文件的表面,是以图形方式来工作的,整个的打印输出工作仅仅是将用户打印的内容输出到TPrinter的属性 Canvas 上,当全部的输出工作完成之后,打印对象(TPrinter)把 Canvas 的属性值送到打印机上。

一个例子:在 Form中加入 Memo,PrintDialog,PrintSetupDialog 和两个 Button 控件,两个Button 的Caption分别为“打印设置”和“打印”。然后编写Button 的事件驱动程序如下:

  1. implement
  2. uses printers;
  3. {$R *.DFM}
  4. procedure TForm1.BitBtn1Click(Sender:TObject);
  5. begin
  6. PrinterSetupDialog1.Execute;//选择输出的打印机以及其他打印控制选项
  7. end;
  8. procedure TForm1.BitBtn2Click(Sender:TObject);
  9. var
  10. lines:integer;
  11. prntext:system.text;
  12. // 将prntext 声明为一个在system 程序单元中定义的文本文件
  13. begin
  14. if PrintDialog1.Execute then
  15. assignprn(prntext);// 将prnsetup分配给打印机
  16. rewrite(prntext);// 调用rewrite 函数,为输出打开已分配的文件
  17. printer.Canvas.font:=memo1.font;
  18. // 把当前Memo1的字体指定给打印对象的Canvas 的字体属性
  19. for lines:=0 to memo1.lines.count-1 do
  20. writeln(prntext,memo1.lines[lines]);
  21. // 把Memo的内容写到打印机对象
  22. System.close(prntext);
  23. end;
  24. procedure Tform1.FormCreate(Sender:TObject);
  25. begin
  26. memo1.lines.loadfromfile(‘C:\dos\os2.txt’);
  27. // 在Form建立时读入文件C:\dos\os2.txt
  28. end;

5.3.2   打印位图 
打印位图也很简单。下面列出了相应代码。

  1. procedure TBMPForm.mmiPrintClick(Sender:TObject)
  2. begin
  3. inherited;
  4. with ImgMain.Picture.BitMap do
  5. begin
  6. Printer.BeginDoc;
  7. Printer.Cavas.StretchDraw(Cava s.ClipRect,ImgMain.Picture.Bitmap);
  8. Printer.EndCode;
  9. end;
  10. end;

调用 TCanvas.StretchDraw()来打印位图仅需三行代码。

在Delphi 中,位图的默认格式是DIB 格式,而 DIB 格式正是打印机驱动程序所需要的,这就大大简化了打印位图的工作。

如果遇到一个非DIB 格式的位图,可以把它复制给一个临时的TBitmap 对象,然后把TBitmap.HandleType 特性设为 bmDIB ,以强制把位图临时转化为 DIB 格式,这样就可以打印出DIB 格式的位图。 注意打印的关键之一是打印图像时能够以其与在屏幕上近似相同的尺寸打印。

例如,一个3×3inch的图像在 640×480 的屏幕上要比在 300dpi 的打印机上需要较少的像素。因此,在调用 StretchDIBits()时,把位图位伸以便与 TPrinter.Canvas 匹配。

5.3.3   打印 TMemo组件中的内容 
事实上,用 AssignPrn()来打印文本行相当简单。AssignPrn() 可以为当前打印机分配一个文本文件变量,它与 Rewrite() 和CloseFile()等过程一起使用。下面几行代码说明了用法: 
var 
f:TextFile; 
begin 
AssignPrn(f); 
try 
Rewrite(f); 
Writeln(f, 'Print the output'); 
finally 
CloseFile(f); 
end; 
end; 
向打印输出一行文字与向文件中输出一行文字一样,可以使用下面的语句: 
Writeln(f,'This is my line of text'); 
下面的一段程序演示了如何从 TMdiEditForm 打印窗体上的内容。用户可以用同样的技术来打印任何文本。

  1. procedure TForm1.mmiPrintClick(Sender:TObject)
  2. var
  3. i:integer;
  4. PText:TextFile;
  5. begin
  6. inherited;
  7. if PrintDialog.Execute then
  8. begin
  9. AssignPrn(PText);
  10. Rewrite(PText);
  11. try
  12. Printer.Cavas.Font:=memMainMemo.Font;
  13. for i:=0 to memMainMemo.Lines.Count-1 do
  14. writeln(PText,memMainMemo.Line[i]);
  15. finally
  16. CloseFile(PText);
  17. end;
  18. end;
  19. end;

注意打印机的字体被指定为TMemo组件的字体,导致打印输出的字体与memMainMemo的字体一样。只有指定打印机所支持的字体,打印机才能以指定的字体打印。否则打印机以与指定字体特征最接近的字体打印。

5.3.4   打印 RTF 格式的文本 
RTF 格式文本的打印同样简单,只要调用一个方法就行了。相应代码如下所示: 
procedure TMdiRtfForm.mmiPrintClick(Sender:TObject); 
begin 
inherited; 
reMain.Print(Caption); 
end;

5.4   打印技巧 
5.4.1   获取显示当前打印机的分辨率 
Windows 下的打印分辨率对打印程序有至关重要的作用,利用函数 GetDeviceCaps() 可以得到打印分辨率。 
例如: 
var 
  iHorizontal,iVertical:integer; 
  iHorizontal:=GetDeviceCap s(printer.handle,LOGPIXELSX); 
  iVertical:= GetDeviceCaps(printer.handle,LOGPIXELSY); 
begin 
  ShowMessage( '水平分辨率:'+inttostr(iHorizontal)+chr(12)+ ' 垂直分辨率:'+Inttostr(iVertical)); 
end;

5.4.2   尽量不要使用 AssignPrn 
尽管 AssignPrn简化了文本打印操作,是输出到打印机像输出到文件一样简单。但简单带来的是一系列不方便:用户无法知道当前打印的行数,无法准确控制行距,也无法灵活改变字体字型,所以最好使用 Canvas 属性。

5.4.3   用打印机的点数做度量单位 
如果要让打印程序在任何打印机上都能正常打印,就必须改变用户的度量单位。如果采用固定度量,不同分辨率打印效果是不同的。举例来说:printer.Canvas.rectangle(0,0,360,720)
在佳能 4200SP上能打出一个 1 inch  宽,2 inch  高的矩形,但在 600×600de HP6L上只能打出0.6 inch  宽,1.2inch  高的矩形。使用打印机的点数作为度量单位是一个明智的选择。具
体做法如下:

  1. var
  2. PointX:integer;
  3. PointY:integer;
  4. Begin
  5. PointX := GetDeviceCap s(printer.Handle,LOGPIXELSX);
  6. PointY := GetDeviceCap s(printer.Handle,LOGPIXELSY);
  7. Printer.Canvas.rectangle(0,0,PointX*1,PointY*2);
  8. End;

这样,无论使用什么打印机,都能得到一个1 inch  宽,2 inch  高的矩形。

5.4.4   将打印结果直接送到打印机 
Delphi 提供了两种打印方式:

一种将结果输出到Form,再调试 Form的Print 方法将结果输送给打印机。如果用户采用第一种方式,则无论用户怎样调整Form的PrintScal 属性,打印出来的东西也不能让用户满意,所以建议使用第二种方式。

5.4.5   获取默认打印机的信息 
在Windows 的Win.ini 文件中有下面的一些配置信息: 
[Window] 
load= 
run= 
NullPort=None; 
Device=HP LaserJet III,HPPCL5MS,LPT1: 
… 
其中windows 节的Device 键中默认打印机的信息,可以通过 Windows API 函数
GetProfileString获取该信息。函数 GetProfileString的原型如下: 
DWORD GetProfileString( 
  LPCTSTR lpAppName,    // 指定节名的字符串 
  LPCTSTR lpKeyName,    // 指定键名的字符串 
LPCTSTR lpDefault,   // 没有找到键名返回的字符串 
LPCTSTR lpReturnString,    // 找到键名返回的字符串 
DWORD nSize    //lpReturnedString的字节数 
);

5.5   本章小结 
本章介绍了 Windows 程序中实现打印的方法。

首先介绍了TPrint 类,讲述了TPrint 类的一些常用属性和常用函数,尤其着重介绍了Canvas 属性。接下来介绍了打印操作常用函数。

然后是一些基本的打印操作,分别介绍了文本文件,位图文件,TMemo组件和 RTF 格式的文件的打印,最后介绍了处理打印问题时的技巧和注意事项。

打印是应用程序通常具备的功能之一,通过这一部分知识的学习,有助于读者编写出功能全面的应用程序。

Delphi 打印 Tprinter的更多相关文章

  1. delphi 打印 PDevMode 说明

    //PDevMode = _devicemodeW;// _devicemodeW = record// dmDeviceName: array[0..CCHDEVICENAME - 1] of Wi ...

  2. Delphi 打印

    procedure TForm1.PrinterSetupExecute(Sender: TObject);begin PrinterSetupDialog1.Execute;end; procedu ...

  3. 重置delphi Printer对象

    http://www.efg2.com/Lab/Library/UseNet/1999/0714b.txt From: "Nick Ryan" <nick@avatardes ...

  4. Memo打印1

              Delphi 打印Memo里面的内容 实现的功能和记事本的打印的功能一样 打印保存为文件时此时的文件名如何设置? 当Memo里的文本数量巨大时 窗体正在打印会出现点数字显示问题 闪 ...

  5. (转: daifubing的博客 )Delphi二维码中文支持、分组、批量打印经验小结

    一直也没接触到什么复杂的报表,都是一些简单的报表,在DelphI下使用QuickReport一般也就能满足需要了,由于公司现在需求的变化,对条码扫描提出了新的要求,主要是扫码要包含更多地内容,以前的一 ...

  6. 主窗体里面打开子窗体&&打印饼图《Delphi 6数据库开发典型实例》--图表的绘制

    \Delphi 6数据库开发典型实例\图表的绘制 1.在主窗体里面打开子窗体:ShowForm(Tfrm_Print); procedure Tfrm_Main.ShowForm(AFormClass ...

  7. 使用Delphi实现票据精确打印

    一.概述在银行,税务,邮政等行业的实际工作中,经常涉及到在印刷好具有固定格式的汇款单,储蓄凭证,税票等单据上的确定位置打印输出相关的信息.在此类需求中,精确地定位单据并打印相关信息,是解决问题的关键. ...

  8. Delphi 10 Seattle 小票打印控件TQ_Printer

    TQ_Printrer控件,是一个为方便需要控制打印命令而设计的跨平台专用控件,已包含标准ESC/POS打印控制的基本指令在内(这些基本指令已能很好的满足多数项目使用). TQ_Printrer控件让 ...

  9. delphi LPT1端口打印与开钱箱

    {设置打印机}Assignfile(RPrinter,'LPT1'); {准备写文件}Rewrite(RPrinter); {向后倒纸}//Writeln(RPrinter,chr($b)+chr(2 ...

随机推荐

  1. 06_Python的数据类型3元组,集合和字典_Python编程之路

    上一节跟大家讲了Python的列表,当然不是完整的讲完,后续我们还会提到,这一节我们还是来讲Python的数据类型 首先要讲到的就是元组 元组其实拥有列表的一些特性,可以存储不同类型的值,但在某些方面 ...

  2. Oracle银行存取钱系统

    Oracle银行存取钱系统 /* 银行系统 要求: 1.创建一个用户信息表(userinfo).一个交易信息表(deal) 2.用户信息表字段:用户编号.用户名称.密码.余额 交易信息表字段:编号.交 ...

  3. js中严格模式

    我们在js中可以使用"use strict";定义了我们在接下来的文档输写中 将按照严格模式进行: function(){ "use strict'; ;// 在这里我们 ...

  4. 算法题丨3Sum Closest

    描述 Given an array S of n integers, find three integers in S such that the sum is closest to a given ...

  5. Win10安装Ubuntu14.04.5双系统(显示器为DP接口)

    系统安装主要参考了这篇博文Win10+Ubuntu17.04双系统安装,不再重复. 重点说说DP接口的事,如果主机有VGA接口的话可以到此为止了,如果只有DP接口的话可以参考以下内容. 一.Ubunt ...

  6. kubernetes进阶(02)kubernetes的node

    一.Node概念 Node是Pod真正运行的主机,可以物理机,也可以是虚拟机. 为了管理Pod,每个Node节点上至少要运行container runtime(比如docker或者rkt). kube ...

  7. WebService(1-1)webservice调用

    参考url : http://www.cnblogs.com/flying607/p/6254045.html 今天用动态创建客户端的方式调用webservice,报了这样一个错: 2017-01-0 ...

  8. python网络爬虫与信息提取 学习笔记day1

    Day1: 安装python之后,为其配置requests第三方库,并爬取百度主页内容. 语句解释: r.status_code检测请求的状态码,如果状态码为200,则说明访问成功,否则,则说明访问失 ...

  9. VMware虚拟机安装

            学习Linux系统最好的方式就是在自己的虚拟机上安装Linux:接下来就给大家简单介绍一下VMware虚拟机的安装以及Linux的安装:VMware虚拟机只是为了更好的学习Linux: ...

  10. 关于CheckStyle在eclipse出现的问题

    今天在公司换了一个CheckStyle xml文件.那么我尝试直接import进去新的文件. 在我Check code的时候就爆了下面的错误 o: Failed during checkstyle c ...