Delphi 动态调整打印机纸张大小
信息管理系统中经常要提供各种打印功能,例如报表打印、凭证打印以及发票打印。在这些打印过程中所需要纸张的大小往往是不一致的,例如,打印报表有可能使用A4 纸或A3 纸,打印凭证或发票可能需要将打印纸张设置成自定义大小。如果在同一台打印机上打印这些内容,那么就应该针对不同的打印内容设置不同的纸张尺寸。显然如果用手动的方法来设置打印机的纸张尺寸是件很麻烦的事,最好的方法是让程序动态地修改打印机的纸张尺寸。
解决问题的思路
通过查阅API 函数技术文档可知,每个打印机都拥有唯一的一个叫做DevMode 的结构,与打印机相关的各项参数被存放在这个结构中。通过对DevMode 结构的分析,发现与设置打印机纸张大小有关的结构成员有四项:dmFields、dmPaperSize、dmPaperLength 以及dmPaperWidth。dmFields 是DevMode 的标志位初始化部分,如果要修改结构中的某些成员,那么dmFields 中相应位应被置位。dmPaperSize 表示打印机当前默认的打印纸张的大小,若要设置自定义纸张该项应为0(注,上述解释是根据微软提供的技术文档,但是在Delphi 中应将该成员设置成$100 即256)。dmPaperLength 和dmPaperWidth 只是在设置自定义大小纸张时使用,分别表示纸张的长度和宽度。如何对打印机的DevMode 结构进行修改呢?无非采用两种方法,一种是利用Delphi 提供的TPrinter 类中的某些方法,还有一种是调用与打印有关的API 函数。下面就以Delphi 为开发工具,以Epson 1600K 为默认打印机,用两种不同的方法来实现这一功能。
方法一:利用Delphi 的TPrinter 类
TPrinter 类是Delphi 对Windows 打印处理系统的封装,它能够帮助程序员在开发打印程序时尽可能地减少工作量。在程序中使用TPrinter,只要在单元的Use 子句后面添加Printers 即可。当前打印机的DevMode 结构的句柄可以通过调用Tprinter 类中的GetPrinter 方法来获取。当程序获得DevMode 结构的句柄后,就调用GlobalLock 函数来得到指向该结构的指针,随后可对结构中的某些成员进行修改。下面就举一个例子来说明这一问题:假设当前打印机的默认纸张尺寸是A3 纸,现在要打印长度为114mm、宽度为190mm 的纸张。为了简单起见,我们只在Form1 上放置一个Button1 按钮,增加一个OnClick 事件,在Use 子句后添加Printers。程序的代码如下:
delphi代码
Procedure TForm1.Button1Click(Sender: TObject);
var
Device : array[0..cchDeviceName -1] of Char;
Driver : array[0..(MAX_PATH -1)] of Char;
Port : array[0..32]of Char;
hDMode : THandle;
pDMode : PDevMode;
begin
Printer.GetPrinter(Device,Driver,Port,hDMode);
// 获取打印机DevMode 结构的句柄值,
存放在hDMode 中
if hDMode < > 0 then begin
pDMode := GlobalLock(hDMode);
// 获取指向打印机DevMode 结构的// 指针
if pDMode < > nil then begin
pDMode^.dmPaperSize := 256;
// 如果要将当前打印机纸张变为自定义
dmPaperSize 必须设置成256
pDMode^.dmPaperLength := 1140;
pDMode^.dmPaperWidth := 1900;
pDMode^.dmFields := pDMode^.dmFields or
DM_PAPERSIZE;
pDMode^.dmFields :=
pDMode^.dmFields or DM_PAPERLENGTH;
pDMode^.dmFields :=
pDMode^.dmFields or DM_PAPERWIDTH;
{ 以上三条语句是对相应
的dmFields 成员进行置位。}
ResetDC(Printer.Handle,pDMode^);
// 设置打印机设备环境句柄的值
GlobalUnlock(hDMode);
end;
end;
{ 下面的代码是为了测试打印机是否
按190 *114 纸张大小来打印}
with Printer do begin
BeginDoc;
Canvas.TextOut(10,10,'Hello, My Friend!');
EndDoc;
end;
end;
Procedure TForm1.Button1Click(Sender: TObject);
var
Device : array[0..cchDeviceName -1] of Char;
Driver : array[0..(MAX_PATH -1)] of Char;
Port : array[0..32]of Char;
hDMode : THandle;
pDMode : PDevMode;
begin
Printer.GetPrinter(Device,Driver,Port,hDMode);
// 获取打印机DevMode 结构的句柄值,
存放在hDMode 中
if hDMode < > 0 then begin
pDMode := GlobalLock(hDMode);
// 获取指向打印机DevMode 结构的// 指针
if pDMode < > nil then begin
pDMode^.dmPaperSize := 256;
// 如果要将当前打印机纸张变为自定义
dmPaperSize 必须设置成256
pDMode^.dmPaperLength := 1140;
pDMode^.dmPaperWidth := 1900;
pDMode^.dmFields := pDMode^.dmFields or
DM_PAPERSIZE;
pDMode^.dmFields :=
pDMode^.dmFields or DM_PAPERLENGTH;
pDMode^.dmFields :=
pDMode^.dmFields or DM_PAPERWIDTH;
{ 以上三条语句是对相应
的dmFields 成员进行置位。}
ResetDC(Printer.Handle,pDMode^);
// 设置打印机设备环境句柄的值
GlobalUnlock(hDMode);
end;
end;
{ 下面的代码是为了测试打印机是否
按190 *114 纸张大小来打印}
with Printer do begin
BeginDoc;
Canvas.TextOut(10,10,'Hello, My Friend!');
EndDoc;
end;
end;
方法二:利用有关打印的Windows API 函数
解决问题的思路和第一种方法类似,首先要获取当前打印机的DevMode 结构的指针,然后再对该结构进行修改,从而修改打印机纸张大小。要完成上述功能,就得调用DocumentProperties 函数。利用该函数程序就可以获取并修改与当前打印机相关的DevMode 结构中的成员。DocumentProperties 函数申明如下:
Delphi代码
LONG DocumentProperties
(
HWND hWnd,
HANDLE hPrinter,
LPTSTR pDeviceName,
PDEVMODE pDevModeOutput,
PDEVMODE pDevModeInput,
DWORD fMode
);
LONG DocumentProperties
(
HWND hWnd,
HANDLE hPrinter,
LPTSTR pDeviceName,
PDEVMODE pDevModeOutput,
PDEVMODE pDevModeInput,
DWORD fMode
);
六个参数中只有pDevModeOutput 是输出变量,其余五个参数必须由程序给出具体值。其中,hWnd 表征当前窗口的句柄值;hPrinter 表示当前打印机的句柄;pDeviceName 是对打印机设备的描述;pDevModeOutput 是指向句柄值为hPrinter 的打印机DevMode 结构的指针;pDevModeInput 是指向一个修改后的DevMode 结构的指针,该结构有待于被句柄值为hPrinter 的打印机接受;fMode 定义了该函数的具体功能,如果取值DM_IN_BUFFER 那么表示打印机接受由参数pDevModeInput 表示的由程序修改了的DevMode 值,如果取值DM_OUT_BUFFER 那么程序可以通过参数pDevModeOutput 来获取打印机的DevMode 值,如果fMode 为零,则函数返回的值表示结构DevMode 所需的字节数。承接上述例子,现在将190 *114 大小的纸张设成A4 纸。再往Form1 上放置按钮Button2,增加OnClick 事件,在Use 子句后面添加WinSpool。代码如下:
delphi 代码:
Procedure TForm1.Button2Click(Sender: TObject);
var
PrnHd : THandle;
PrnInfo : PPrinterInfo1;
pcbNeeded : DWORD;
PDevModeBytes : DWORD;
DevMode: PDeviceMode;
PrnHdc : HDC;
DocInfo : PDocInfo;
begin
OpenPrinter('Epson LQ -1600K',PrnHd,nil);
// 获得打印机句柄PrnHd
GetMem(PrnInfo,1024);
GetPrinter(PrnHd,1,PrnInfo,1024,@pcbNeeded);
PDevModeBytes:= DocumentProperties
( Handle,PrnHd,prninfo^.
pDescription,DevMode^,DevMode^,0 );
{ 获取DevMode 结构所需的字节数}
GetMem(DevMode,PDevModeBytes);
// 给结构DevMode 分配空间
DocumentProperties( Handle,PrnHd,PrnInfo^.p
Description,DevMode^,DevMode^,DM_OUT_BUFFER );
// 获取打印机的DevMode 结构
With DevMode^ do begin
dmPaperSize := DMPAPER_A4 ;
// 将纸张设置成A4 纸
dmFields := dmFields or DM_PAPERSIZE;
end;
DocumentProperties( Handle,PrnHd,PrnInfo^.p
Description,DevMode^,DevMode^,
DM_OUT_BUFFER or DM_IN_BUFFER);
// 修改DevMode 结构。
{ 下面的代码是为了测试打印机
是否按A4 纸大小来打印 }
PrnHdc := CreateDC
( nil, 'Epson LQ -1600K',nil,DevMode );
GetMem( DocInfo, 100 );
With DocInfo^ do begin
cbSize := sizeof(DocInfo);
lpszDocName := nil;
lpszOutput := nil;
lpszDatatype := nil;
fwType := DI_APPBANDING;
end;
StartDoc( PrnHdc, DocInfo^);
StartPage(PrnHdc);
TextOut( PrnHdc, 10, 10, 'Hello My Friend!',17);
EndPage(PrnHdc);
EndDoc(PrnHdc);
DeleteDC(PrnHdc);
FreeMem(DocInfo);
FreeMem(PrnInfo);
FreeMem(DevMode);
end;
Procedure TForm1.Button2Click(Sender: TObject);
var
PrnHd : THandle;
PrnInfo : PPrinterInfo1;
pcbNeeded : DWORD;
PDevModeBytes : DWORD;
DevMode: PDeviceMode;
PrnHdc : HDC;
DocInfo : PDocInfo;
begin
OpenPrinter('Epson LQ -1600K',PrnHd,nil);
// 获得打印机句柄PrnHd
GetMem(PrnInfo,1024);
GetPrinter(PrnHd,1,PrnInfo,1024,@pcbNeeded);
PDevModeBytes:= DocumentProperties
( Handle,PrnHd,prninfo^.
pDescription,DevMode^,DevMode^,0 );
{ 获取DevMode 结构所需的字节数}
GetMem(DevMode,PDevModeBytes);
// 给结构DevMode 分配空间
DocumentProperties( Handle,PrnHd,PrnInfo^.p
Description,DevMode^,DevMode^,DM_OUT_BUFFER );
// 获取打印机的DevMode 结构
With DevMode^ do begin
dmPaperSize := DMPAPER_A4 ;
// 将纸张设置成A4 纸
dmFields := dmFields or DM_PAPERSIZE;
end;
DocumentProperties( Handle,PrnHd,PrnInfo^.p
Description,DevMode^,DevMode^,
DM_OUT_BUFFER or DM_IN_BUFFER);
// 修改DevMode 结构。
{ 下面的代码是为了测试打印机
是否按A4 纸大小来打印 }
PrnHdc := CreateDC
( nil, 'Epson LQ -1600K',nil,DevMode );
GetMem( DocInfo, 100 );
With DocInfo^ do begin
cbSize := sizeof(DocInfo);
lpszDocName := nil;
lpszOutput := nil;
lpszDatatype := nil;
fwType := DI_APPBANDING;
end;
StartDoc( PrnHdc, DocInfo^);
StartPage(PrnHdc);
TextOut( PrnHdc, 10, 10, 'Hello My Friend!',17);
EndPage(PrnHdc);
EndDoc(PrnHdc);
DeleteDC(PrnHdc);
FreeMem(DocInfo);
FreeMem(PrnInfo);
FreeMem(DevMode);
end;
至此,程序实现了本文开头所提出的要求。需要指出的是,上述代码是在程序运行时,动态地改变打印机纸张大小,而不改变打印机默认纸张大小。也就是说当打印程序运行结束后,打印机还是会按照默认打印纸张大小来打印、走纸。动态调整打印机纸张尺寸也是因打印机而异,某些打印机基本不支持自定义纸张,例如惠普的HP DeskJet 1120C 喷墨打印机以及众多激光打印机。因此在这些打印机上,不能实现按任意纸张大小打印。对于一些针式打印机则没有上述问题。
自定义纸张大小
以下程序将打印机纸张设为:114mm*190mm:
procedure PreparePrinter;
var
aDevice: array[0..CCHDEVICENAME-1] of Char;
aDriver: array[0..MAX_PATH-1] of Char;
aPort: array[0..31] of Char;
hDevMode: THandle;
pDevMode: PDeviceMode;
begin
// 获取打印机DeviceMode的句柄
Printer.GetPrinter(aDevice, aDriver, aPort, hDevMode);
if hDevMode <> 0 then
begin
// 获取指向DeviceMode的指针
pDevMode := GlobalLock(hDevMode);
if pDevMode <> nil then
begin
pDevMode^.dmPaperSize := DMPAPER_USER;
pDevMode^.dmPaperLength := 1140;
pDevMode^.dmPaperWidth := 1900;
pDevMode^.dmFields := pDevMode^.dmFields or DM_PAPERSIZE;
pDevMode^.dmFields := pDevMode^.dmFields or DM_PAPERLENGTH;
pDevMode^.dmFields := pDevMode^.dmFields or DM_PAPERWIDTH;
ResetDC(Printer.Handle, pDevMode^);
GlobalUnlock(hDevMode);
end;
end;
end;
用修改
DeviceMode的方法的话,只是改变你程序中的打印机设置,不会影响其他程序打印的。
PAGESIZE:=256
PAGEWIDTH:2100
PAGEHEIGHTH:970
就可以了。
256代表的是自定义
//
var v,u,x,y: TfrView; b: TfrBandView; Page: TfrPage;
begin
//创建一个页面
frReport5.Pages.Clear;
frReport5.Pages.Add;
Page := frReport5.Pages[0];
Page.Prop['Size'] := 'US Std Fanfold, 14 7/8 x 11"';
我想将新创建的页面的纸张格式设置为 US Std Fanfold, 14 7/8 x 11" , 但上面的代码执行不了, 运行时提示:
Could not convert variant of type(string) into type(Boolean)
请教高手如何动态设置打印的纸张???
Delphi 动态调整打印机纸张大小相关推荐
- 动态调整打印机纸张大小
动态调整打印机纸张大小 江苏省昆山市地方税务局 信息管理系统中经常要提供各种打印功能,例如报表打印.凭证打印以及发票打印.在这些打印过程中所需要纸张的大小往往是不一致的,例如,打印报表有可能使用A4 ...
- delphi 获取打印机默认纸张_Delphi 动态调整打印机纸张大小
修 改与当前打印机相关的DevMode 结构中的成员.DocumentProperties 函数申明如下: Delphi代码 LONG DocumentProperties ( HWND hWnd, ...
- html打印纸张尺寸设置100*150,打印机纸张大小怎么设置 打印机纸张大小设置方法【详细介绍】...
打印机纸张大小怎么设置吗?下面就来为大家详细介绍设置打印机纸大小的几种方法. 一.通用 左键单击电脑的开始菜单 左键单击左上角的文件,再单击服务器属性 创建新格式,设置纸张的宽度和高度 左键单击打印机 ...
- 动态调整linux分区大小,GParted 动态调整Linux分区大小
在虚拟化环境中虚拟机运行一段时间后数据量持续增长,磁盘分区都需要进行扩容,对于Windows系统相对简单,在磁盘瘦格式的状态下直接修改虚拟机磁盘大小,在系统中的磁盘管理里扩展分区即可,实时生效连重启都 ...
- android程序字体大小,Android如何动态调整应用字体大小详解
前言 为什么要动态设置字体大小?由于项目面对的是中老年客户项目中自带的字体无法满足客户需求. Android应用字体大小默认随系统设置的字体大小而变化,但您可能不希望您的应用字体大小随系统设置变化,想 ...
- android程序字体大小,Android 动态调整应用字体大小
Android应用字体大小默认随系统设置的字体大小而变化,但您可能不希望您的应用字体大小随系统设置变化,想要自己控制,例如微信.本文简单介绍一下如何实现应用字体大小动态调整而不是依赖系统设置 字体大小 ...
- 在XP中自定义打印机纸张大小
在XP中自定义打印机纸张大小 一.问题描述: 在Windows 2000和Windows XP操作系统中,如何自定义纸张大小? 自定义纸张之后,为何在打印机属性的"纸张大小"中没有 ...
- C#导出Excle表格根据内容动态调整单元格大小
引入命名空间 using NPOI.HSSF.UserModel; using NPOI.HSSF.Util; using NPOI.SS.UserModel; using NPOI.SS.Util; ...
- python 动态调整控件大小_python GUI库图形界面开发之PyQt5动态(可拖动控件大小)布局控件QSplitter详细使用方法与实例...
PyQt5动态(可拖动控件大小)布局控件QSplitter简介 PyQt还提供了特殊的布局管理器QSplitter.它可以动态地拖动子控件之间的边界,算是一个动态的布局管理器,QSplitter允许用 ...
最新文章
- 基于docker安装tensorflow
- 最有二叉树 哈夫曼树
- arduino灯光装置_【pinpong库控制硬件】之Arduino uno-调光台灯
- HDRP中ShaderGraph自发光的一个小坑
- java 任务池_多线程的应用-异步任务线程池的简单实现
- Eclipse中使用Git-让版本管理更简单
- RedisLockRegistry源码-redis分布式锁
- 盘点云计算的概念,分类和特点
- 读《An Adaptable and Extensible Geometry Kernel》
- 坦然面对:应对前端疲劳
- java 时区 夏令时_关于时区:如何显示Java开始夏令时后的时间差异?
- 后台得到ajax传来的参数,几种ajax传参数到后台获取的方法
- 20种专业电影胶片调色luts预设
- Mac下编程的实用快捷键
- 【FF14】工匠配方爬取
- 孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备
- VC中 WM_SHOWWINDOW 与ShowWindow()的区别
- 模拟HTTP请求, POST方法(附源码)
- 前端架构师神技,三招统一团队代码风格
- 如何在网上选到一瓶心仪的红酒?通过文本分析预测葡萄酒的质量