使用Delphi实现票据精确打印
一、概述
在银行,税务,邮政等行业的实际工作中,经常涉及到在印刷好具有固定格式的汇款单,储蓄凭证,
税票等单据上的确定位置打印输出相关的信息。在此类需求中,精确地定位单据并打印相关信息,
是解决问题的关键。一般情况下,开发者都是通过在打印机上通过重复的测试来达到实际需求。
那么,有没有简单有效而又灵活的方法实现上述功能呢?
二、基本思路
分析上述单据的特征,可以发现:此类打印输出的信息一般比较简短,不涉及到文字过长的折行处理,
另外,其打印输出的位置相对固定。因此,我们可以通过用尺子以毫米为单位,测量好每个输出信息位置
的横向和纵向坐标,作为信息输出的位置。但由于不同打印机在实际输出效果上,总是存在理论和实际位置
的偏差,因此,要求程序具有一定的灵活性,供最终用户根据需要,进行必要的位置调整。因此,可设置
一打印配置文件,用于存储横坐标和纵坐标的偏移量,用于用户进行位置校正,从而提供了一定的灵活性。
三、精确打印输出的程序实现
1. 在Delphi中新建一个名为mprint.pas的单元文件并编写如下程序,单元引用中加入Printers略:
//取得字符的高度
function CharHeight: Word;
var
Metrics: TTextMetric;
begin
GetTextMetrics(Printer.Canvas.Handle, Metrics);
Result := Metrics.tmHeight;
end;
file://取得字符的平均宽度
function AvgCharWidth: Word;
var
Metrics: TTextMetric;
begin
GetTextMetrics(Printer.Canvas.Handle, Metrics);
Result := Metrics.tmAveCharWidth;
end;
file://取得纸张的物理尺寸---单位:点
function GetPhicalPaper: TPoint;
var
PageSize : TPoint;
begin
file://PageSize.X; 纸张物理宽度-单位:点
file://PageSize.Y; 纸张物理高度-单位:点
Escape(Printer.Handle, GETPHYSPAGESIZE, 0,nil,@PageSize);
Result := PageSize;
end;
file://2.取得纸张的逻辑宽度--可打印区域
file://取得纸张的逻辑尺寸
function PaperLogicSize: TPoint;
var
APoint: TPoint;
begin
APoint.X := Printer.PageWidth;
APoint.Y := Printer.PageHeight;
Result := APoint;
end;
file://纸张水平对垂直方向的纵横比例
function HVLogincRatio: Extended;
var
AP: TPoint;
begin
Ap := PaperLogicSize;
Result := Ap.y/Ap.X;
end;
file://取得纸张的横向偏移量-单位:点
function GetOffSetX: Integer;
begin
Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetX);
end;
file://取得纸张的纵向偏移量-单位:点
function GetOffSetY: Integer;
begin
Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetY);
end;
file://毫米单位转换为英寸单位
function MmToInch(Length: Extended): Extended;
begin
Result := Length/25.4;
end;
file://英寸单位转换为毫米单位
function InchToMm(Length: Extended): Extended;
begin
Result := Length*25.4;
end;
file://取得水平方向每英寸打印机的点数
function HPointsPerInch: Integer;
begin
Result := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
end;
file://取得纵向方向每英寸打印机的光栅数
function VPointsPerInch: Integer;
begin
Result := GetDeviceCaps(Printer.Handle, LOGPIXELSY)
end;
file://横向点单位转换为毫米单位
function XPointToMm(Pos: Integer): Extended;
begin
Result := Pos*25.4/HPointsPerInch;
end;
file://纵向点单位转换为毫米单位
function YPointToMm(Pos: Integer): Extended;
begin
Result := Pos*25.4/VPointsPerInch;
end;
file://设置纸张高度-单位:mm
procedure SetPaperHeight(Value:integer);
var
Device : array[0..255] of char;
Driver : array[0..255] of char;
Port : array[0..255] of char;
hDMode : THandle;
PDMode : PDEVMODE;
begin
file://自定义纸张最小高度127mm
if Value < 127 then Value := 127;
file://自定义纸张最大高度432mm
if Value > 432 then Value := 432;
Printer.PrinterIndex := Printer.PrinterIndex;
Printer.GetPrinter(Device, Driver, Port, hDMode);
if hDMode <> 0 then
begin
pDMode := GlobalLock(hDMode);
if pDMode <> nil then
begin
pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or
DM_PAPERLENGTH;
pDMode^.dmPaperSize := DMPAPER_USER;
pDMode^.dmPaperLength := Value * 10;
pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL;
pDMode^.dmDefaultSource := DMBIN_MANUAL;
GlobalUnlock(hDMode);
end;
end;
Printer.PrinterIndex := Printer.PrinterIndex;
end;
file://设置纸张宽度:单位--mm
Procedure SetPaperWidth(Value:integer);
var
Device : array[0..255] of char;
Driver : array[0..255] of char;
Port : array[0..255] of char;
hDMode : THandle;
PDMode : PDEVMODE;
begin
file://自定义纸张最小宽度76mm
if Value < 76 then Value := 76;
file://自定义纸张最大宽度216mm
if Value > 216 then Value := 216;
Printer.PrinterIndex := Printer.PrinterIndex;
Printer.GetPrinter(Device, Driver, Port, hDMode);
if hDMode <> 0 then
begin
pDMode := GlobalLock(hDMode);
if pDMode <> nil then
begin
pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or
DM_PAPERWIDTH;
pDMode^.dmPaperSize := DMPAPER_USER;
file://将毫米单位转换为0.1mm单位
pDMode^.dmPaperWidth := Value * 10;
pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL;
pDMode^.dmDefaultSource := DMBIN_MANUAL;
GlobalUnlock(hDMode);
end;
end;
Printer.PrinterIndex := Printer.PrinterIndex;
end;
file://在 (Xmm, Ymm)处按指定配置文件信息和字体输出字符串
procedure PrintText(X, Y: Extended; Txt: string; ConfigFileName: string; FontSize: Integer=12);
var
OrX, OrY: Extended;
Px, Py: Integer;
AP: TPoint;
Fn: TStrings;
FileName: string;
OffSetX, OffSetY: Integer;
begin
file://打开配置文件,读出横向和纵向偏移量
try
Fn := TStringList.Create;
FileName := ExtractFilePath(Application.ExeName) + ConfigFileName;
if FileExists(FileName) then
begin
Fn.LoadFromFile(FileName);
file://横向偏移量
OffSetX := StrToInt(Fn.Values['X']);
file://纵向偏移量
OffSetY := StrToInt(Fn.Values['Y']);
end
else
begin
file://如果没有配置文件,则生成
Fn.Values['X'] := '0';
Fn.Values['Y'] := '0';
Fn.SaveToFile(FileName);
end;
finally
Fn.Free;
end;
X := X + OffSetX;
Y := Y + OffSetY;
Px := Round(Round(X * HPointsPerInch * 10000/25.4) / 10000);
Py := Round(Round(Y * VPointsPerInch * 10000/25.4) / 10000);
Py := Py - GetOffSetY; file://因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标
Px := Px + 2 * AvgCharWidth;
Printer.Canvas.Font.Name := '宋体';
Printer.Canvas.Font.Size := FontSize;
file://Printer.Canvas.Font.Color := clGreen;
Printer.Canvas.TextOut(Px, Py, Txt);
end;
2. 使用举例
在主窗体中加入对mprint单元的引用,在一命令钮的OnClick
事件中书写如下代码(用于在邮政汇款单上的相应方框内打印邮政编码843300):
Printer.BeginDoc;
PrintText(16, 14, '8', 'config.txt');
PrintText(26, 14, '4', 'config.txt');
PrintText(36, 14, '3', 'config.txt');
PrintText(46, 14, '3', 'config.txt');
PrintText(56, 14, '0', 'config.txt');
PrintText(66, 14, '0', 'config.txt');
Printer.EndDoc;
观察结果,用尺子测量偏移量,在config.txt文件中修改X,Y的值即可。
其它,设置打印机和纸张类型从略。
四、结束语
使用Delphi实现票据精确打印的更多相关文章
- Delphi 10 Seattle 小票打印控件TQ_Printer
TQ_Printrer控件,是一个为方便需要控制打印命令而设计的跨平台专用控件,已包含标准ESC/POS打印控制的基本指令在内(这些基本指令已能很好的满足多数项目使用). TQ_Printrer控件让 ...
- Delphi水晶横向竖向打印
最近做一个打印项目,本来报表已经设为横向打印了,可是运行程序,打印出来的是竖向的,非要在打印机里再设定为横向,郁闷了很久,看看UCrpe32的源码之后,由于我重新封装了TCrpe,在TCrpe的派生类 ...
- [2014.01.27]wfPrintOcx 票据打印控件 v5.3
支持选择打印机,并自动记忆选择的打印机. 适合打印各类票据格式. 支持画正方形.长方形.圆形.椭圆.横线.竖线.HTTP图片. 支持数字金额转换成中文大写金额. 可以设置固定宽度的文字自动换行. 组件 ...
- Web打印组件jatoolsPrinter
应用web化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于web的应用,客户端的规则很简单,容易学习,容易维护,容易发布.但对程序员来说,因为浏览器的局限性,却要面对很多挑战.怎么样 ...
- 2013第39周一Web打印
2013第39周一Web打印 项目中遇到了Java Web打印问题,简单调用IE浏览器的打印不能完全满足要求,于是就搜集了Web打印相关的主题,简单汇总一下.web打印难点在分页.页面纸张设置,页眉页 ...
- Web打印组件jatoolsPrinter(转载)
应用web化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于web的应用,客户端的规则很简单,容易学习,容易维护,容易发布.但对程序员来说,因为浏览器的局限性,却要面对很多挑战.怎么样 ...
- WEB打印的几种方案
-------------------------------------------一 基于Web的打印方案比较分析-------------------------------- 基于web的套 ...
- Web系统页面打印技术实现与分析
1 Web页面打印概述应用WEB化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于WEB的应用,客户端的规则很简单,容易学习,容易维护,容易发布.在WEB系统中,打印的确是个烦人的问题 ...
- lodop 控件实现web打印功能
WEB套打可选方案不多,理想的更少,利用免费控件Lodop+JavaScript实现精确套打,算是较为经典的选择.这种方案其实比较简单,利用一个htm文件就可以实现模板设计过程,几乎是“空手套”式的开 ...
随机推荐
- JqueryValidate表单相同Name不校验问题解决
在使用Jquery validate中遇到一个问题,当表单元素有name相同字段时,validate只校验表单元素name第一个值是否通过校验,比如 <input type="text ...
- VC++ MFC应用程序项目文件2.cpp
//GameServer.cpp: 定义应用程序的入口点. // #include "stdafx.h" #include "GameServer.h" #de ...
- [Spring Boot] Use Component Scan to scan for Bean
Component Scan is important concept when we want to create Bean. Currently we know what, for the cla ...
- java enum 用法
/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2010, Red Hat Inc. or th ...
- LintCode: Combination Sum II
C++ DFS class Solution { public: void help(vector<int> &a, int now, int sum, int target, v ...
- 关于操作系统:eos、deepin
朋友星神推荐了这两个操作系统:eos.deepin,大致看了一下介绍,貌似看起来很棒,界面清新,而且开源,支持的应用也不少,后续我准备尝试一下.此处Mark一下: 官网分别为: https://ele ...
- 微信小程序 - 怎样合理设计小程序
假如我们无意中,把腾讯地图或者高德地图的管理Key删了! 关于定位的一切相关模块就都会报废! 接着呢?客户会找你,对你公司信任感下降,一系列问题接踵而来 最好的办法就是先预留key后台管理 “随时可以 ...
- springboot整合mybatis的两种方式
https://blog.csdn.net/qq_32719003/article/details/72123917 springboot通过java bean集成通用mapper的两种方式 前言:公 ...
- Eclipse经常使用快捷键
Eclipse经常使用快捷键 1几个最重要的快捷键 代码助手:Ctrl+Space(中文简体操作系统是Alt+/) 高速修正:Ctrl+1 单词补全:Alt+/ 打开外部Java文档:Shift+F2 ...
- Live555实战之交叉编译live555共享库
作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 能够通过这个链接获得最新的live555源代码:Live555源代码下载 Live555 是一个为 ...