自定义一个控制打印机的单元unit My_Print;interfaceuses Printers, Types, Windows, Messages, SysUtils, Variants, Graphics,Dialogs, Inifiles, Forms;type TCustomPrinter=class(TObject) private FiOffsetX: Integer; //水平方向偏移量:.1毫米 FiOffsetY: Integer; //垂直方向偏移量:.1毫米 //取得字符的高度 function CharHeight: Word; //取得字符的平均宽度 function AvgCharWidth: Word; //取得纸张的物理尺寸---单位:点 function GetPhicalPaper: TPoint; //得到打印机默认的页边距 function GetPrintStartPos:TPoint; //取得纸张的逻辑宽度--可打印区域,纸张的逻辑尺寸 function PaperLogicSize: TPoint; //纸张水平对垂直方向的纵横比例 function HVLogincRatio: Extended; //取得纸张的横向偏移量-单位:点 function GetOffSetX: Integer; //取得纸张的纵向偏移量-单位:点 function GetOffSetY: Integer; //毫米单位转换为英寸单位 function MmToInch(Length: Extended): Extended; //英寸单位转换为毫米单位 function InchToMm(Length: Extended): Extended; //取得水平方向每英寸打印机的点数 function HPointsPerInch: Integer; //取得纵向方向每英寸打印机的光栅数 function VPointsPerInch: Integer; //横向点单位转换为毫米单位 function XPointToMm(Pos: Integer): Extended; //纵向点单位转换为毫米单位 function YPointToMm(Pos: Integer): Extended; //设置纸张尺寸:纸张宽度和纸张高度-单位:mm procedure SetPagerSize(const ASize: Integer; AWidth,AHeight: Double); protected public constructor Create; {******************************************************************** 函数名称: InitPrinter 函数功能: 初始化打印机,包括打印机名称、纸张大小等等 输入参数: ConfigIni: string --打印配置文件:*.ini 输出参数: None --参数的用途 *********************************************************************} procedure InitPrinter(PRatio: Integer=1;APWidth: Double=171; APHeight: Double=78;APsize: Integer=256;ADeviceName:string=''; Adefault:string='YES';AOffsetX:Integer=0;AOffsetY:Integer=0); overload; procedure InitPrinter(ConfigIni: string;PRatio: Integer=1); overload; {******************************************************************** 函数名称: PrintText 函数功能: 在 (Xmm, Ymm)处按指定配置文件信息和字体输出字符串 输入参数: X, Y: Extended; -- 打印起始点,单位为毫米 输入参数: LineHeight, TextWidth: Extended; --行高,待打印矩形宽度 输入参数: Txt: string; -- 待打印的文本 输入参数: FontSize: Integer=12 --字体为'宋体',缺省大小为12, 输入参数: TextAlignment: Integer=DT_LEFT --文本对齐方式,缺省为'左对齐' 输入参数: AllowNewLine:Boolean=False --是否允许换行 输出参数: 换了几行则返回几,默认为1,未换行 --参数的用途 *********************************************************************} function PrintText(Xmm, Ymm, LineHeight, TextWidth: Extended; Txt: string; FontSize: Integer=10; TextAlignment: Integer=DT_LEFT; AllowNewLine:Boolean=False):Integer; overload; function PrintText(Xmm, Ymm: Extended; Txt: string;FontSize: Integer=10; AllowNewLine:Boolean=False):Integer; overload; procedure PrintChar(s: PChar); procedure PrintEllipse(Xmm1, Ymm1, Xmm2, Ymm2: DOUBLE;APenWidth: Integer=2); procedure PrintLine(Xmm1, Ymm1, Xmm2, Ymm2: DOUBLE; ACanvas: TCanvas; APenWidth: Integer=5); procedure PrintTableLine(ACanvas: TCanvas; APenWidth: Integer=5); end; procedure My_InitPrinter(ConfigIni :string); function My_PrintText(Xmm, Ymm: Extended; Txt: string;FontSize: Integer=10):Integer;implementationconstructor TCustomPrinter.Create;begin FiOffsetX:=0; FiOffsetY:=0;end;function TCustomPrinter.CharHeight: Word;{取得字符的高度}var Metrics: TTextMetric;begin GetTextMetrics(Printer.Canvas.Handle, Metrics); Result := Metrics.tmHeight;end;//取得字符的平均宽度function TCustomPrinter.AvgCharWidth: Word;var Metrics: TTextMetric;begin GetTextMetrics(Printer.Canvas.Handle, Metrics); Result := Metrics.tmAveCharWidth;end;//取得纸张的物理尺寸---单位:点function TCustomPrinter.GetPhicalPaper: TPoint;var PageSize : TPoint;begin //PageSize.X; 纸张物理宽度-单位:点 //PageSize.Y; 纸张物理高度-单位:点 Escape(Printer.Handle, GETPHYSPAGESIZE, 0,nil,@PageSize); Result := PageSize;end;//打印机的坐标原点总是在纸张的左上角,不管纸张从那个方向进入打印机。//得到打印机默认的页边距function TCustomPrinter.GetPrintStartPos:TPoint;var pageMargin:TPoint; myEscape:integer;begin pageMargin.x:=0; pageMargin.y:=0; myEscape:=GETPRINTINGOFFSET; if Escape(Printer.Handle,QUERYESCSUPPORT,sizeof(myEscape),@myEscape,nil)>0 then begin if Escape(printer.Handle,GETPRINTINGOFFSET,0,nil,@pageMargin)<=0 then begin pageMargin.x:=0; pageMargin.y:=0; end; end; result:=pageMargin;end; //2.取得纸张的逻辑宽度--可打印区域 //取得纸张的逻辑尺寸function TCustomPrinter.PaperLogicSize: TPoint;var APoint: TPoint;begin APoint.X := Printer.PageWidth; APoint.Y := Printer.PageHeight; Result := APoint;end;//纸张水平对垂直方向的纵横比例function TCustomPrinter.HVLogincRatio: Extended;var AP: TPoint;begin Ap := PaperLogicSize; Result := Ap.y/Ap.X;end;//取得纸张的横向偏移量-单位:点 --打印机的每英寸为多少像素function TCustomPrinter.GetOffSetX: Integer;begin Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetX);end;//取得纸张的纵向偏移量-单位:点 --打印机的每英寸为多少像素function TCustomPrinter.GetOffSetY: Integer;begin Result := GetDeviceCaps(Printer.Handle, PhysicalOffSetY);end;//毫米单位转换为英寸单位function TCustomPrinter.MmToInch(Length: Extended): Extended;begin Result := round(Length/25.4); //每毫米水平方向象素end;//英寸单位转换为毫米单位function TCustomPrinter.InchToMm(Length: Extended): Extended;begin Result := round(Length*25.4);//每毫米水平方向象素end;//取得水平方向每英寸打印机的点数function TCustomPrinter.HPointsPerInch: Integer;begin Result := GetDeviceCaps(Printer.Handle, LOGPIXELSX);end;//取得纵向方向每英寸打印机的光栅数function TCustomPrinter.VPointsPerInch: Integer;begin Result := GetDeviceCaps(Printer.Handle, LOGPIXELSY)end;//横向点单位转换为毫米单位function TCustomPrinter.XPointToMm(Pos: Integer): Extended;begin Result := Pos*25.4/HPointsPerInch;end;//纵向点单位转换为毫米单位function TCustomPrinter.YPointToMm(Pos: Integer): Extended;begin Result := Pos*25.4/VPointsPerInch;end;procedure TCustomPrinter.SetPagerSize(const ASize: Integer; AWidth, AHeight: Double);var Device : array[0..255] of char; Driver : array[0..255] of char; Port : array[0..255] of char; hDMode : THandle; PDMode : PDEVMODE; paperOrientation: Integer;begin //自定义纸张最小高度70mm if AHeight < 70 then AHeight := 70; //自定义纸张最大高度432mm if AHeight > 500 then AHeight := 500; //自定义纸张最小宽度76mm if AWidth < 76 then AWidth := 76; //自定义纸张最大宽度216mm if AWidth > 300 then AWidth := 300; paperOrientation:=1; {AWidth := 171; AHeight := 78;} Printer.PrinterIndex := Printer.PrinterIndex; Printer.GetPrinter(Device, Driver, Port, hDMode); if hDMode <> 0 then begin pDMode := GlobalLock(hDMode); if pDMode <> nil then begin {设定打印的方向为纵向或横向 if PaperOrientation<>0 then pDMode^.dmOrientation:=DMORIENT_LANDSCAPE else pDMode^.dmOrientation:=DMORIENT_PORTRAIT; //设置拷贝份数为1份. pDMode^.dmCopies:=1;} //自定义纸张 pDMode^.dmPaperSize := DMPAPER_USER; {pDMode^.dmPaperSize:=256;} //将毫米单位转换为0.1mm单位 pDMode^.dmPaperWidth := round(AWidth * 10); pDMode^.dmPaperLength := round(Aheight * 10); pDMode^.dmFields := pDMode^.dmFields or DM_PAPERSIZE or DM_PAPERWIDTH; pDMode^.dmFields := pDMode^.dmFields or DM_PAPERLENGTH; //pDMode^.dmFields := pDMode^.dmFields or DMBIN_MANUAL; {pDMode^.dmFields:=pDMode^.dmFields or DM_PAPERSIZE; pDMode^.dmFields:=pDMode^.dmFields or DM_PAPERWIDTH; pDMode^.dmFields:=pDMode^.dmFields or DM_PAPERLENGTH;} //pDMode^.dmDefaultSource := DMBIN_MANUAL; GlobalUnlock(hDMode); end; end; Printer.PrinterIndex := Printer.PrinterIndex;end;procedure TCustomPrinter.InitPrinter(PRatio: Integer=1;APWidth: Double=171; APHeight: Double=78;APsize: Integer=256;ADeviceName:string=''; Adefault:string='YES';AOffsetX:Integer=0;AOffsetY:Integer=0);{在 (Xmm, Ymm)处按指定配置文件信息和字体输出字符串}var dName: string; bDefault:string;//是否使用缺省打印机 offSetX, offSetY: Integer; pSize: Integer; pWidth,pHeight: Double;begin bDefault:=Adefault; dName:=ADeviceName; pSize:=APsize; pWidth:=APWidth; pHeight:=APHeight; offSetX:=AOffsetX; offSetY:=AOffsetY; pHeight:=pHeight*PRatio; FiOffsetX:=offSetX; FiOffsetY:=offSetY; if CompareText(UpperCase(bDefault),'YES')=0 then //是否使用缺省打印机 Printer.PrinterIndex:=-1 else if dName<>'' then Printer.PrinterIndex:= Printer.Printers.IndexOf(dName); SetPagerSize(pSize,pWidth,pHeight);end;procedure TCustomPrinter.InitPrinter(ConfigIni: string;PRatio: Integer=1);{在 (Xmm, Ymm)处按指定配置文件信息和字体输出字符串}var fN: string; inif: TIniFile; dName: string; bDefault:string;//是否使用缺省打印机 offSetX, offSetY: Integer; pSize: Integer; pWidth,pHeight: Double;begin pSize:=256; pWidth:=239; pHeight:=139.7; offSetX:=0; offSetY:=0; fN := ConfigIni; // ExtractFilePath(Application.ExeName)+'/'+ if FileExists(fN) then begin inif:= TIniFile.Create(fN); try try dName:=inif.ReadString('Printer','DeviceName','error'); bDefault:=inif.ReadString('Printer','IsUseDefault','Yes'); pSize:=StrToInt(inif.ReadString('Printer','PaperSize','256')); pWidth:=StrToFloat(inif.ReadString('Printer','PageWidth','20')); pHeight:=StrToFloat(inif.ReadString('Printer','PageHeight','20')); offSetX:= 0; //StrToInt(inif.ReadString('Printer','OffsetX','0')); offSetY:= 0; //StrToInt(inif.ReadString('Printer','OffsetY','0')); except bDefault:='Yes'; pSize:=256; pWidth:=239; pHeight:=139.7; offSetX:=0; offSetY:=0; end; finally inif.Free; end; end; pHeight:=pHeight*PRatio; FiOffsetX:=offSetX; FiOffsetY:=offSetY; if CompareText(bDefault,'Yes')=0 then //是否使用缺省打印机 Printer.PrinterIndex:=-1 else Printer.PrinterIndex:= Printer.Printers.IndexOf(dName); SetPagerSize(pSize,pWidth,pHeight);end;//在 (Xmm, Ymm)处按指定配置文件信息和字体输出字符串function TCustomPrinter.PrintText(Xmm, Ymm, LineHeight, TextWidth: Extended; Txt: string; FontSize: Integer=10; TextAlignment: Integer=DT_LEFT; AllowNewLine:Boolean=False): Integer;var PrintRect: TRect; Px,Py: Integer; lh,tw: Extended; tmpTxt,prnTxt: string;begin Result:=1; Xmm := Xmm + FiOffSetX/10; Ymm := Ymm + FiOffSetY/10; Px := Round(Round(Xmm * HPointsPerInch * 10000/25.4) / 10000); Py := Round(Round(Ymm * VPointsPerInch * 10000/25.4) / 10000); Py := Py - GetOffSetY; //因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标 Px := Px + 2 * AvgCharWidth; tw:= Round(Round(textwidth * HPointsPerInch * 10000/25.4) / 10000); lh:= Round(Round(LineHeight * VPointsPerInch * 10000/25.4) / 10000); Printer.Canvas.Font.Name :='宋体'; // Arial' Printer.Canvas.Font.Size := FontSize; //Printer.Canvas.Font.Color := clGreen; PrintRect.Left := Round(px); PrintRect.Top := Round(py); PrintRect.Bottom := Round(PrintRect.Top + Lh); PrintRect.Right := Round(PrintRect.Left +tw); if (Length(txt)*AvgCharWidth>tw) and AllowNewLine then begin tmpTxt:=Txt; while Length(tmpTxt)*AvgCharWidth>tw do begin prnTxt:=string(Copy(WideString(tmpTxt),1,Length(WideString(Copy(tmpTxt,1,Trunc(tw/AvgCharWidth))))-1)); if not Printer.Aborted then DrawText(Printer.Canvas.Handle,PChar(prnTxt),Length(prnTxt),PrintRect,TextAlignment); tmpTxt:=' '+Copy(tmpTxt,Length(prnTxt)+1,Length(tmpTxt)-Length(prnTxt)); Py:=PrintRect.Bottom-PrintRect.Top; PrintRect.Top:= PrintRect.Bottom; PrintRect.Bottom:= PrintRect.Bottom+py; Inc(Result); end; if not Printer.Aborted then DrawText(Printer.Canvas.Handle,PChar(tmpTxt),Length(tmpTxt),PrintRect,TextAlignment); end else if not Printer.Aborted then DrawText(Printer.Canvas.Handle,PChar(Txt),Length(Txt),PrintRect,TextAlignment);end;function TCustomPrinter.PrintText(Xmm, Ymm: Extended; Txt: string; FontSize: Integer=10;AllowNewLine:Boolean=False):Integer;var Px, Py: Integer;begin Result:=1; Xmm := Xmm + FiOffSetX/10; Ymm := Ymm + FiOffSetY/10; Px := Round(Round(Xmm * HPointsPerInch * 10000/25.4) / 10000); Py := Round(Round(Ymm * VPointsPerInch * 10000/25.4) / 10000); Py := Py - GetOffSetY; //因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标 Px := Px + 2 * AvgCharWidth; Printer.Canvas.Font.Name := '宋体'; Printer.Canvas.Font.Size := FontSize; //Printer.Canvas.Font.Color := clGreen; if not Printer.Aborted then Printer.Canvas.TextOut(Px, Py, Txt);end;Procedure TCustomPrinter.PrintChar(s: PChar);var tf: TextFile;begin AssignFile(tF, 'LPT1'); Rewrite(tF); Write(tF,s); CloseFile(tF);end;procedure TCustomPrinter.PrintEllipse(Xmm1, Ymm1, Xmm2, Ymm2: DOUBLE;APenWidth: Integer=2);var oldPen: TPen; Px1, Py1, Px2, Py2 : Integer;begin oldPen:=TPen.Create; OldPen.Assign(Printer.Canvas.Pen); Xmm1 := Xmm1 + FiOffSetX/10; Ymm1 := Ymm1 + FiOffSetY/10; Xmm2 := Xmm2 + FiOffSetX/10; Ymm2 := Ymm2 + FiOffSetY/10; Px1 := Round(Round(Xmm1 * HPointsPerInch * 10000/25.4) / 10000); Py1 := Round(Round(Ymm1 * VPointsPerInch * 10000/25.4) / 10000); Py1 := Py1 - GetOffSetY; //因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标 Px1 := Px1 + 2 * AvgCharWidth; Px2 := Round(Round(Xmm2 * HPointsPerInch * 10000/25.4) / 10000); Py2 := Round(Round(Ymm2 * VPointsPerInch * 10000/25.4) / 10000); Py2 := Py2 - GetOffSetY; //因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标 Px2 := Px2 + 2 * AvgCharWidth; // Printer.Canvas.Font.Name := '宋体'; // Printer.Canvas.Font.Size := 10; // FontSize Printer.Canvas.Pen.Style := psSolid; Printer.Canvas.Pen.Width := APenWidth; if not Printer.Aborted then Printer.Canvas.Ellipse(Px1,Py1,Px2,Py2); Printer.Canvas.Pen.Assign(OldPen); OldPen.Free;end;procedure TCustomPrinter.PrintLine(Xmm1, Ymm1, Xmm2, Ymm2: DOUBLE; ACanvas: TCanvas; APenWidth: Integer=5);var oldPen: TPen; Px1, Py1, Px2, Py2 : Integer;begin oldPen:=TPen.Create; OldPen.Assign(ACanvas.Pen); Xmm1 := Xmm1 + FiOffSetX/10; Ymm1 := Ymm1 + FiOffSetY/10; Xmm2 := Xmm2 + FiOffSetX/10; Ymm2 := Ymm2 + FiOffSetY/10; Px1 := Round(Round(Xmm1 * HPointsPerInch * 10000/25.4) / 10000); Py1 := Round(Round(Ymm1 * VPointsPerInch * 10000/25.4) / 10000); Py1 := Py1 - GetOffSetY; //因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标 Px1 := Px1 + 2 * AvgCharWidth; Px2 := Round(Round(Xmm2 * HPointsPerInch * 10000/25.4) / 10000); Py2 := Round(Round(Ymm2 * VPointsPerInch * 10000/25.4) / 10000); Py2 := Py2 - GetOffSetY; //因为是绝对坐标, 因此, 不用换算成相对于Y轴坐标 Px2 := Px2 + 2 * AvgCharWidth; with ACanvas do begin //Printer.Canvas.Font.Name := '宋体'; //Printer.Canvas.Font.Size := 10; // FontSize Pen.Style:= psSolid; Pen.Width:= APenWidth; // APenWidth if not Printer.Aborted then begin MoveTo(px1,py1); LineTo(px2,py2); end; Pen.Assign(OldPen); end; OldPen.Free;end;procedure TCustomPrinter.PrintTableLine(ACanvas: TCanvas; APenWidth: Integer=5);var cv:TCanvas;begin cv:=ACanvas; PrintLine(0,32,170,32,cv,APenWidth); //行 PrintLine(0,40,170,40,cv,APenWidth); PrintLine(0,72,170,72,cv,APenWidth); PrintLine(0,79,170,79,cv,APenWidth); PrintLine(0,32,0,79,cv,APenWidth); //列 PrintLine(68,32,68,72,cv,APenWidth); PrintLine(80,32,80,72,cv,APenWidth); PrintLine(102,32,102,72,cv,APenWidth); //PrintLine(111,32,111,72,cv,APenWidth); //PrintLine(122,32,122,72,cv,APenWidth); PrintLine(127,32,127,79,cv,APenWidth); PrintLine(157,32,158,79,cv,APenWidth); PrintLine(170,32,170,79,cv,APenWidth);end;procedure My_InitPrinter(ConfigIni :string);var printer1 : TCustomPrinter;begin printer1 := TCustomPrinter.Create; printer1.InitPrinter(ConfigIni,1);end;function My_PrintText(Xmm, Ymm: Extended; Txt: string;FontSize: Integer=10):Integer;var printer1 : TCustomPrinter;begin printer1 := TCustomPrinter.Create; result := printer1.PrintText(Xmm, Ymm, Txt,FontSize,false);end;end.应用如下: //初始化打印机 My_InitPrinter(strFileName); //开始打印 Printer.BeginDoc; //把要打印的信息放到文档中 My_PrintText(t_X[0] ,t_Y[0] ,strDate,10); //结束打印 Printer.EndDoc;