﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-努力创造未来！-随笔分类-delphi</title><link>http://www.blogjava.net/pdw2009/category/9731.html</link><description>J2EE相关应用技术日志</description><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 15:36:42 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 15:36:42 GMT</pubDate><ttl>60</ttl><item><title>使用Delphi实现票据精确打印.</title><link>http://www.blogjava.net/pdw2009/archive/2006/04/09/40110.html</link><dc:creator>有猫相伴的日子</dc:creator><author>有猫相伴的日子</author><pubDate>Sun, 09 Apr 2006 10:13:00 GMT</pubDate><guid>http://www.blogjava.net/pdw2009/archive/2006/04/09/40110.html</guid><wfw:comment>http://www.blogjava.net/pdw2009/comments/40110.html</wfw:comment><comments>http://www.blogjava.net/pdw2009/archive/2006/04/09/40110.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/pdw2009/comments/commentRss/40110.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/pdw2009/services/trackbacks/40110.html</trackback:ping><description><![CDATA[
		<div style="MARGIN: 4px 8px 0px" firstchar="">一、概述<br />在银行，税务，邮政等行业的实际工作中，经常涉及到在印刷好具有固定格式的汇款单，储蓄凭证，<br />税票等单据上的确定位置打印输出相关的信息。在此类需求中，精确地定位单据并打印相关信息，<br />是解决问题的关键。一般情况下，开发者都是通过在打印机上通过重复的测试来达到实际需求。<br />那么，有没有简单有效而又灵活的方法实现上述功能呢？<br />二、基本思路<br /><br />分析上述单据的特征，可以发现：此类打印输出的信息一般比较简短，不涉及到文字过长的折行处理，<br />另外，其打印输出的位置相对固定。因此，我们可以通过用尺子以毫米为单位，测量好每个输出信息位置<br />的横向和纵向坐标,作为信息输出的位置。但由于不同打印机在实际输出效果上，总是存在理论和实际位置<br />的偏差，因此，要求程序具有一定的灵活性，供最终用户根据需要，进行必要的位置调整。因此，可设置<br />一打印配置文件，用于存储横坐标和纵坐标的偏移量，用于用户进行位置校正，从而提供了一定的灵活性。<br />三、精确打印输出的程序实现<br />1． 在Delphi中新建一个名为mprint.pas的单元文件并编写如下程序，单元引用中加入Printers略：<br /><br />//取得字符的高度<br />function CharHeight: Word;<br />var<br />　Metrics: TTextMetric;<br />begin<br />　GetTextMetrics(Printer.Canvas.Handle, Metrics);<br />　Result := Metrics.tmHeight;<br />end;<br /><br />file://取得字符的平均宽度<br />function AvgCharWidth: Word;<br />var<br />　Metrics: TTextMetric;<br />begin<br />　GetTextMetrics(Printer.Canvas.Handle, Metrics);<br />　Result := Metrics.tmAveCharWidth;<br />end;<br /><br />file://取得纸张的物理尺寸---单位：点<br />function GetPhicalPaper: TPoint;<br />var<br />　PageSize : TPoint;<br />begin<br />　file://PageSize.X; 纸张物理宽度-单位:点<br />　file://PageSize.Y; 纸张物理高度-单位:点<br />　Escape(Printer.Handle, GETPHYSPAGESIZE, 0,nil,@PageSize);<br />　Result := PageSize;<br />end;<br /><br />file://2.取得纸张的逻辑宽度--可打印区域<br />file://取得纸张的逻辑尺寸<br />function PaperLogicSize: TPoint;<br />var<br />　APoint: TPoint;<br />begin<br />　APoint.X := Printer.PageWidth;<br />　APoint.Y := Printer.PageHeight;<br />　Result := APoint;<br />end;<br /><br />file://纸张水平对垂直方向的纵横比例<br />function HVLogincRatio: Extended;<br />var<br />　AP: TPoint;<br />begin<br />　Ap := PaperLogicSize;<br />　Result := Ap.y/Ap.X;<br />end;<br /><br />file://取得纸张的横向偏移量-单位：点<br />function GetOffSetX: Integer;<br />begin<br />　Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetX);<br />end;<br /><br />file://取得纸张的纵向偏移量-单位：点<br />function GetOffSetY: Integer;<br />begin<br />　Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetY);<br />end;<br /><br />file://毫米单位转换为英寸单位<br />function MmToInch(Length: Extended): Extended;<br />begin<br />　Result := Length/25.4;<br />end;<br /><br />file://英寸单位转换为毫米单位<br />function InchToMm(Length: Extended): Extended;<br />begin<br />　Result := Length*25.4;<br />end;<br /><br />file://取得水平方向每英寸打印机的点数<br />function HPointsPerInch: Integer;<br />begin<br />　Result := GetDeviceCaps(Printer.Handle, LOGPIXELSX);<br />end;<br /><br />file://取得纵向方向每英寸打印机的光栅数<br />function VPointsPerInch: Integer;<br />begin<br />　Result := GetDeviceCaps(Printer.Handle, LOGPIXELSY)<br />end;<br /><br />file://横向点单位转换为毫米单位<br />function XPointToMm(Pos: Integer): Extended;<br />begin<br />　Result := Pos*25.4/HPointsPerInch;<br />end;<br /><br />file://纵向点单位转换为毫米单位<br />function YPointToMm(Pos: Integer): Extended;<br />begin<br />　Result := Pos*25.4/VPointsPerInch;<br />end;<br /><br />file://设置纸张高度-单位：mm<br />procedure SetPaperHeight(Value:integer);<br />var<br />　Device : array[0..255] of char;<br />　Driver : array[0..255] of char;<br />　Port : array[0..255] of char;<br />　hDMode : THandle;<br />　PDMode : PDEVMODE;<br />begin<br />file://自定义纸张最小高度127mm<br />if Value &lt; 127 then Value := 127;<br />　file://自定义纸张最大高度432mm<br />　if Value &gt; 432 then Value := 432;<br />　　Printer.PrinterIndex := Printer.PrinterIndex;<br />　　Printer.GetPrinter(Device, Driver, Port, hDMode);<br />　　if hDMode &lt;&gt; 0 then<br />　　　begin<br />　　　　pDMode := GlobalLock(hDMode);<br />　　　　if pDMode &lt;&gt; nil then<br />　　　　begin<br />　　　　　pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or<br />　　　　　　　　　　　　　　　DM_PAPERLENGTH;<br />　　　　　pDMode^.dmPaperSize := DMPAPER_USER;<br />　　　　　pDMode^.dmPaperLength := Value * 10;<br />　　　　　pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL;<br />　　　　　pDMode^.dmDefaultSource := DMBIN_MANUAL;<br />　　　　　GlobalUnlock(hDMode);<br />　　　　end;<br />　　　end;<br />　　　Printer.PrinterIndex := Printer.PrinterIndex;<br />end;<br /><br />file://设置纸张宽度：单位--mm<br />Procedure SetPaperWidth(Value:integer);<br />var<br />　Device : array[0..255] of char;<br />　Driver : array[0..255] of char;<br />　Port : array[0..255] of char;<br />　hDMode : THandle;<br />　PDMode : PDEVMODE;<br />begin<br />file://自定义纸张最小宽度76mm<br />if Value &lt; 76 then Value := 76;<br />　file://自定义纸张最大宽度216mm<br />　if Value &gt; 216 then Value := 216;<br />　　Printer.PrinterIndex := Printer.PrinterIndex;<br />　　Printer.GetPrinter(Device, Driver, Port, hDMode);<br />　　if hDMode &lt;&gt; 0 then<br />　　begin<br />　　　pDMode := GlobalLock(hDMode);<br />　　　if pDMode &lt;&gt; nil then<br />　　　begin<br />　　　　pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or <br />　　　　　　　　　　　　　　DM_PAPERWIDTH;<br />　　　　pDMode^.dmPaperSize := DMPAPER_USER;<br />　　　　file://将毫米单位转换为0.1mm单位<br />　　　　pDMode^.dmPaperWidth := Value * 10;<br />　　　　pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL;<br />　　　　pDMode^.dmDefaultSource := DMBIN_MANUAL;<br />　　　　GlobalUnlock(hDMode);<br />　　　end;<br />　　end;<br />　　Printer.PrinterIndex := Printer.PrinterIndex;<br />end;<br /><br />file://在 (Xmm, Ymm)处按指定配置文件信息和字体输出字符串<br />procedure PrintText(X, Y: Extended; Txt: string; ConfigFileName: string; FontSize: Integer=12);<br />var<br />　OrX, OrY: Extended;<br />　Px, Py: Integer;<br />　AP: TPoint;<br />　Fn: TStrings;<br />　FileName: string;<br />　OffSetX, OffSetY: Integer;<br />begin<br />file://打开配置文件，读出横向和纵向偏移量<br />try<br />　Fn := TStringList.Create;<br />　FileName := ExtractFilePath(Application.ExeName) + ConfigFileName;<br />　if FileExists(FileName) then<br />　begin<br />　　Fn.LoadFromFile(FileName);<br />　　file://横向偏移量<br />　　OffSetX := StrToInt(Fn.Values['X']);<br />　　file://纵向偏移量<br />　　OffSetY := StrToInt(Fn.Values['Y']);<br />　end<br />else<br />begin<br />　file://如果没有配置文件，则生成<br />　Fn.Values['X'] := '0';<br />　Fn.Values['Y'] := '0';<br />　Fn.SaveToFile(FileName);<br />end;<br />finally<br />　Fn.Free;<br />end;<br />X := X + OffSetX;<br />Y := Y + OffSetY;<br />Px := Round(Round(X * HPointsPerInch * 10000/25.4) / 10000);<br />Py := Round(Round(Y * VPointsPerInch * 10000/25.4) / 10000);<br />Py := Py - GetOffSetY; file://因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标<br />Px := Px + 2 * AvgCharWidth;<br />Printer.Canvas.Font.Name := '宋体';<br />Printer.Canvas.Font.Size := FontSize;<br />file://Printer.Canvas.Font.Color := clGreen;<br />Printer.Canvas.TextOut(Px, Py, Txt);<br />end; <br /><br />　　2． 使用举例<br /><br />　　在主窗体中加入对mprint单元的引用，在一命令钮的OnClick<br />事件中书写如下代码（用于在邮政汇款单上的相应方框内打印邮政编码843300）：<br /><br />Printer.BeginDoc;<br />PrintText(16, 14, '8', 'config.txt');<br />PrintText(26, 14, '4', 'config.txt');<br />PrintText(36, 14, '3', 'config.txt');<br />PrintText(46, 14, '3', 'config.txt');<br />PrintText(56, 14, '0', 'config.txt');<br />PrintText(66, 14, '0', 'config.txt');<br />Printer.EndDoc; <br /><br />　　观察结果，用尺子测量偏移量，在config.txt文件中修改X，Y的值即可。<br /><br />　　其它，设置打印机和纸张类型从略。<br /><br />　　四、结束语<br /> <br />  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=易云飞" target="_blank">易云飞</a>, <b>时间：</b>2004-7-23 9:51:55, <b>ID：</b>2726013</div>
		<div style="MARGIN: 4px 8px 0px">  如果打小于76毫米的高度的票据呢？<br />  不就是没法控制精度拉。 <br />  而且我问过epson，十厘米以下一般走纸就不是非常准确，必须调整几毫米才能保证准确，如果你的高度间距恰好不被用英寸所精确确定，那么打印就有可能出现累计误差。<br />比如高度70mm的纸连续纸，Epson针打必须设置在719mm才能保证走到切纸位，<br />  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=易云飞" target="_blank">易云飞</a>, <b>时间：</b>2004-7-23 9:58:58, <b>ID：</b>2726045</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">而且，如果你用写字板做测试走纸是否走到切纸位，以上719mm也有一点点没有到位，当打多张时，累计走纸误差也就越来越大，10张就几乎10mm啦，如果调到721mm，走纸就过了切纸位一点点，调到7。20mm是最合适的，可惜epson是按英寸计算，719，720对应2。83in,<br />7.21 对应2。84in, 嘿嘿，没撤。  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=易云飞" target="_blank">易云飞</a>, <b>时间：</b>2004-7-23 10:14:54, <b>ID：</b>2726098</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">解决方法是有很多的，由直接也有间接，不过达到最佳效果，还得靠esc命令，不过得熟悉esc/p系列命令，亲自控制打印机的走纸。  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=易云飞" target="_blank">易云飞</a>, <b>时间：</b>2004-7-23 14:40:04, <b>ID：</b>2726748</div>
		<div style="MARGIN: 4px 8px 0px"> 可恨的是，我还在研究，头都大了  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=ktsxy" target="_blank">ktsxy</a>, <b>时间：</b>2004-7-30 10:58:21, <b>ID：</b>2738703</div>
		<div style="MARGIN: 4px 8px 0px">   非常感谢...你们给出这么好的答案...谢谢  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=ktsxy" target="_blank">ktsxy</a>, <b>时间：</b>2004-7-30 11:04:42, <b>ID：</b>2738732</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">请问  d_fan 怎么联系你....我有很急的事要请教你(关于票据打印)问题.....<br /><br />      你能不能发一份票据打印的Delphi 源程序给我..谢谢<br /><br /><br />         小弟很急...............QQ:330117537      </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=xdengni" target="_blank">xdengni</a>, <b>时间：</b>2004-11-23 15:18:09, <b>ID：</b>2904656</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">请问  d_fan 怎么联系你....我有很急的事要请教你(关于票据打印)问题.....<br /><br />      你能不能发一份票据打印的Delphi 源程序给我..我也想要，谢谢  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=cng81" target="_blank">cng81</a>, <b>时间：</b>2004-11-24 16:13:03, <b>ID：</b>2906618</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">TO：d_fan 真是感谢你提供的代码，我要好好研究一个。呵呵（敬礼！）  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=luckysw" target="_blank">luckysw</a>, <b>时间：</b>2004-11-30 16:21:27, <b>ID：</b>2913352</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">d_fan 我也正在做票据打印，感谢你提供的代码 呵呵<br />不过，这段代码好像还有一个小问题：<br />要是打印的位置超出了默认的页边距怎么办？<br />有什么办法能设置页边距吗？  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=thj" target="_blank">thj</a>, <b>时间：</b>2005-8-30 16:44:59, <b>ID：</b>3185727</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">还有一个重要问题：不好控制折行。  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=任逍遥1205" target="_blank">任逍遥1205</a>, <b>时间：</b>2005-12-7 18:04:41, <b>ID：</b>3289184</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">这行代码怎么来实现横打，我加上下面这段代码也不行<br />PDMode^.dmFields:=DM_ORIENTATION;<br />PDMode^.dmOrientation :=PDMode^.dmFields or DMORIENT_LANDSCAPE;  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=nido" target="_blank">nido</a>, <b>时间：</b>2005-12-15 8:20:29, <b>ID：</b>3297086</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">楼主 我也需要一份源代码，能否发给我呢<br />nidogz@gmail.com  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=zhangbo" target="_blank">zhangbo</a>, <b>时间：</b>2005-12-31 11:01:56, <b>ID：</b>3314733</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">请问  d_fan 怎么联系你<br />我有很急的事要请教你(关于票据打印)问题<br />你能不能发一份票据打印的Delphi 源程序给我..谢谢<br />我在打凭证时老差2mm，累计误差只能打10个凭证。<br />纸的高度是108mm<br />我用的是FastReport<br />我的QQ是382057922  </div>
		<br />
		<div style="PADDING-RIGHT: 4px; BORDER-TOP: #88a5db 1px solid; PADDING-LEFT: 4px; BACKGROUND: #e1e9ff; PADDING-BOTTOM: 4px; PADDING-TOP: 4px">
				<b>来自：</b>
				<a href="http://www.delphibbs.com/delphibbs/dispu.asp?username=zhangbo" target="_blank">zhangbo</a>, <b>时间：</b>2005-12-31 11:12:06, <b>ID：</b>3314753</div>
		<div style="MARGIN: 4px 8px 0px" firstchar="">请问  d_fan 怎么联系你<br />我有很急的事要请教你(关于票据打印)问题<br />你能不能发一份票据打印的Delphi 源程序给我..谢谢<br />我在打凭证时老差2mm，累计误差只能打10个凭证。<br />纸的高度是108mm<br />我用的是FastReport<br />我的QQ是382057922  <br />yhqzbb2@sina.com  </div>
<img src ="http://www.blogjava.net/pdw2009/aggbug/40110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/pdw2009/" target="_blank">有猫相伴的日子</a> 2006-04-09 18:13 <a href="http://www.blogjava.net/pdw2009/archive/2006/04/09/40110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>