---------------------------------------选择打印机------------------------------
在用户需求中我们会遇到这样的问题,一台PC连接两台打印机,一个打印小票,一个打印报表,两种打印机打印时,纸张大小、打印方向等设置都不相同,如果每次切换都让用户手工设置的话,太繁琐,用户不能接受。这样我们就要在程序中控制自动切换打印机。Windows提供了功能很好的和打印机相关的API,在此我没有自己再对其封装,而是用了一个网上已经封装好了的用户对象,现在来看看怎么来实现这个功能。
思路是一台打印机设置成默认,切换时要保存默认打印机的各设置,在适当的时侯再切换会来。
程序如下:
写成一个函数,好调用 wf_set_printer(string as_oper) return boolean
any ls_para
String ls_driver,ls_our_driver, ls_port, ls_PBPrinter,ls_inifile
Integer li_i, li_count, li_size, li_width, li_length, li_row
if as_oper = 'xp' then //设置票据打印机
ls_IniFile = "c:\schinf.ini" //保存要切换的打印机名称的ini文件,格式如下
//[printer]
//Drivers = EPSON TM-U210A Partial cut
//report = Epson LQ-1600KIII(缺省打印机)
ls_our_driver = ProfileString(ls_inifile, "printer", "Drivers", "None")
if ls_our_driver = "None" then return false
// 取打印机列表
li_count = lnv_printer.of_GetPrinterList ( is_list )
// 取PB缺省打印机
ls_PBPrinter = lnv_printer.of_GetPBPrinter ( )
//保存缺省值
lnv_printer.of_GetPaperSize ( ls_pbprinter, ii_size, ii_width, ii_length )
is_para = lnv_printer.of_getpaperorientation(ls_pbprinter)
//遍历系统安装的所有打印机名称,如果找到要设置的打印机,设为缺省,达到切换的目的
For li_i = 1 To li_count
ls_driver = lnv_printer.of_GetDriverName ( is_list [ li_i ] )
if ls_driver = ls_our_driver AND ls_PBPrinter <> is_list [ li_i ] then
lnv_printer.of_setdefault(is_list[li_i])
ii_num = li_i //record printer arrery index
// 取打印纸大小
lnv_printer.of_GetPaperSize ( is_list [ li_i ], li_size, li_width, li_length )
//设置打印方向
ls_para = 1
lnv_printer.of_Printer( is_list[ii_num],103,ls_para, li_size, li_width, li_length )
return true
end if
next
return false
end if
//恢复缺省打印机,即切换会来
if as_oper = 'qs' then
if upperbound(is_list) = 1 then return false
for li_i = 1 to upperbound(is_list)
if li_i <> ii_num then
lnv_printer.of_setdefault(is_list[li_i])
if isnull(ii_num) or ii_num = 0 then
return false
else
lnv_printer.of_Printer( is_list[ii_num],103,is_para, ii_size, ii_width, ii_length )
return true
end if
end if
next
end if
return true
2----------------------------打印控制-------------------------------------
Powerbuilder数据窗口可用于生成各种复杂的 报表,但如何让用户在使用时控制打印份数、打印范围等信息呢?
我们在开发我局MIS系统时,经过对我局报表打印需求的分析,提出了如下的功能要求:
1.必须能够控制象打印份数、打印(页码)范围等信息,这是基本的要求。
2.我们系统中装有多台打印机,必须能让用户根据自己需要选择使用哪台打印机,必要时能对所选打印机进行配置。
3.在设计时,对每一个报表需要什么样的纸张,要多大的边距合适,都已确定,所以使用时不需要页面的设置。但由于不同的报表使用不同的纸张,必须在使用时给出提示,以便用有机会换上合适的纸张(或换用合适的打印机)。
根据以上要求,我们设计了如下图所示的对话框。 下面把设计过程以及用到的技术介绍一下。
首先使用窗口画板画出窗口,名字为w_printdlg,窗口类型为respons。“打印机”组框中的“名称”文本控制的名字为st_printname,“设置”按钮的名字为cb_printsetup。“页面范围”组框中的无线按钮组名字分别为rb_pagearrangeall、rb_pagearrangecurrent、rb_pagearrange,单行编辑框名字为sle_pagearrange,其enable属性为false。“副本”组框中的编辑域名字为em_copies。“打印”旁边的下拉列表框名字为ddlb_printwhat,列表有三项,分别为所选页面、偶数页、奇数页。“纸张”组框中的下拉列表框名字为ddlb_paper,列表内容为Poerbuiler定义的43种纸张类型,分别用0-42的数字来表示。“纵向”无线按钮的名字为rb_portrait,“横向”无线按钮的名字为rb_landscape。表示纵向和横向的图片框分别为p_portrait和p_landscape。 命令按钮“确定”和“取消”的名字分别为cb_ok和cb_cancel。
以上工作完成之后,就要着手编写程序。
首先为窗口定义实例变量idw_toprint,类型为datawindow,用于保存要打印的数据窗口。再定义一个窗口事件ue_initcontrols(也可以定义为窗口函数),其程序内容如下:
//eventue_initcontrols()
//设置窗口中各控件的初始值
st_printername.text = idw_toprint.object.
datawindow.printer //当前打印机名字
em_copies.text = "1" //默认打印份数为1
rb_pagearrangeall.checked = true //默认范围为全部页
sle_pagearrange.enabled = false //页面范围编辑框无效
ddlb_printwhat.SelectItem(1) //默认为“所选页面”
//打印方向
integer li_temp
li_temp = integer(idw_toprint.object.datawindow.print.orientation) //取出设计时的方向
if li_temp = 1 then //横向
rb_landscape.checked = true //选中
p_landscape.visible = true //图片显示
p_portrait.visible = false
elseif li_temp = 2 then //纵向
rb_portrait.checked = true
p_portrait.visible = true
p_landscape.visible = false
end if
//纸张类型
li_temp = integer(idw_toprint.object.datawindow.print.Paper.Size) //设计时的纸张类型
ddlb_paper.SelectItem(li_temp+1) //列表框中选中
然后,在窗口的open事件中编写如下脚本:
//openevent
//要使用OpenWithParm()打开,参数中包含要打印的数据窗口。
idw_toprint = message.powerobjectparm
//从参数中取出要打印的数据窗口
this.eventue_initcontrols() //初始化窗口各控件
在无线按钮rb_pagearrangall的clicked事件中编写脚本如下:
sle_pagearrange.enabled = false
在无线按钮rb_pagearrangcurrent的clicked事件中编写脚本如下:
sle_pagearrange.enabled = false
在无线按钮rb_pagearrang的clicked事件中编写脚本如下:
sle_pagearrange.enabled = true//当此无线按钮选中时才可用
在命令按钮cb_printersetup中编写如下脚本:
//cb_printersetup
PrintSetup() //设置打印机
parent.eventue_initcontrols()
在无线按钮rb_portrait的clicked事件中编写如下脚本:
//纵向
p_landscape.visible = false
p_portrait.visible = true//显示纵向图片框
在无线按钮rb_landscape的clicked事件中编写如下脚本:
//横向
p_portrait.visible = false
p_landscape.visible = true
在命令按钮cb_cancel的clicked事件中编写如下脚本
//cb_cancel执行程序
CloseWithReturn(parent,2) //如果选择取消,返回2
在命令按钮cb_ok的clicked事件中编写如下脚本
//cb_ok执行程序
string str_temp
integer li_temp
long ll_row
//打印什么
li_temp = ddlb_printwhat.FindItem(ddlb_printwhat.text,0) - 1
idw_toprint.object.datawindow.print.page.rangeinclude = li_temp
//打印范围
ifrb_pagearrangeall.checkedthen//全部页
str_temp = ""
elseifrb_pagearrangecurrent.checkedthen//当前页
ll_row = idw_toprint.GetRow()
idw_toprint.object.datawindow.print.preview = "Yes"
//设成预览模式
str_temp = idw_toprint.Describe("evaluate('Page()',"+String(ll_row)+")") //计算页码
idw_toprint.object.datawindow.print.preview = "No"
elseif rb_pagearrange.checkedthen //输入范围
str_temp = sle_pagearrange.text
end if
idw_toprint.object.datawindow.print.page.range=str_temp
//副本份数
iflen(em_copies.text)>0then
idw_toprint.object.datawindow.print.copies
=Integer(em_copies.text)
endif
//纸的方向
li_temp=0
if rb_landscape.checked then
li_temp=1
elseif rb_portrait.checked then
li_temp=2
endif
idw_toprint.object.datawindow.print.orientation=li_temp
//纸的尺寸
li_temp= ddlb_paper.FindItem(ddlb_paper.Text,0)
//第li_temp项
idw_toprint.object.datawindow.print.paper.size=li_temp
closewithreturn(parent,1)
几点说明:
1.原点访问语法:程序中多次用到了象datawindowcontrol.object.datawindow.print.attribute语法,用语控制数据窗口的打印属性。原点访问语法用语代替原来的Discribe和Modify函数,更符合面向对象的语言习惯。关于print属性的详细信息,请参见Powerbuilder帮助。
2.当前打印页的计算:先用GetRow得到当前行数, 再用Describe和Evaluate函数来计算数据窗口表达式,得出当前页号。注意在计算之前,先把要打印的数据窗口置成预览模式,否则计算出来的是显示页号,和打印页号不一致。
3.窗口内外信息的传递:虽然你可以用全局变量传递信息,但那决不是一个好的注意。使用OpenWithParm函数打开窗口可以向窗口传递一个参数,使用CloseWithReturn函数关闭窗口可以返回一个参数,根据参数的类型,其结果被放在系统全局变量message的相应成员中。如果要传递多个参数,可以把要他们定义为一个结构来传递。
--------------------打印机退纸----------------------------------------------------
打印时能使纸回退,打印完之后能能让纸前进一些,适合于打票据的单位(注意使用printdatawindow函数,Datawindow中字体设置均无效)
long job,temp
job=printopen()
printsend(job,"~h1B~h6A~254")
printsend(job,"~h1B~h6A~100")
printsend(job,"~h1c~h78~h01")
printsend(job,"~h1B~h43~h01")
print(job,"")
temp=printdatawindow(job,dw_print) /*dw_print是要打印的数据窗口*/
printclose(job)
Job = PrintOpen()
printsend(job,"~h1B~h43~h13")
printclose(job)
--------------------------------------------------------------------------
API之打印函数
AbortDoc 取消一份文档的打印
AbortPrinter 删除与一台打印机关联在一起的缓冲文件
AddForm 为打印机的表单列表添加一个新表单
AddJob 用于获取一个有效的路径名,以便用它为作业创建一个后台打印文件。它也会为作业分配一个作业编号
AddMonitor 为系统添加一个打印机监视器
AddPort 启动"添加端口"对话框,允许用户在系统可用端口列表中加入一个新端口
AddPrinter 在系统中添加一台新打印机
AddPrinterConnection 连接指定的打印机
AddPrinterDriver 为指定的系统添加一个打印驱动程序
AddPrintProcessor 为指定的系统添加一个打印处理器
AddPrintProvidor 为系统添加一个打印供应商
AdvancedDocumentProperties 启动打印机文档设置对话框
ClosePrinter 关闭一个打开的打印机对象
ConfigurePort 针对指定的端口,启动一个端口配置对话框
ConnectToPrinterDlg 启动连接打印机对话框,用它同访问网络的打印机连接
DeleteForm 从打印机可用表单列表中删除一个表单
DeleteMonitor 删除指定的打印监视器
DeletePort 启动"删除端口"对话框,允许用户从当前系统删除一个端口
DeletePrinter 将指定的打印机标志为从系统中删除
DeletePrinterConnection 删除与指定打印机的连接
DeletePrinterDriver 从系统删除一个打印机驱动程序
DeletePrintProcessor 从指定系统删除一个打印处理器
DeletePrintProvidor 从系统中删除一个打印供应商
DeviceCapabilities 利用这个函数可获得与一个设备的能力有关的信息
DocumentProperties 打印机配置控制函数
EndDocAPI 结束一个成功的打印作业
EndDocPrinter 在后台打印程序的级别指定一个文档的结束
EndPage 用这个函数完成一个页面的打印,并准备设备场景,以便打印下一个页
EndPagePrinter 指定一个页在打印作业中的结尾
EnumForms 枚举一台打印机可用的表单
EnumJobs 枚举打印队列中的作业
EnumMonitors 枚举可用的打印监视器
EnumPorts 枚举一个系统可用的端口
EnumPrinterDrivers 枚举指定系统中已安装的打印机驱动程序
EnumPrinters 枚举系统中安装的打印机
EnumPrintProcessorDatatypes 枚举由一个打印处理器支持的数据类型
EnumPrintProcessors 枚举系统中可用的打印处理器
Escape 设备控制函数
FindClosePrinterChangeNotification 关闭用FindFirstPrinterChangeNotification函数获取的一个打印机通告对象
FindFirstPrinterChangeNotification 创建一个新的改变通告对象,以便我们注意打印机状态的各种变化
FindNextPrinterChangeNotification 用这个函数判断触发一次打印机改变通告信号的原因
FreePrinterNotifyInfo 释放由FindNextPrinterChangeNotification函数分配的一个缓冲区
GetForm 取得与指定表单有关的信息
GetJob 获取与指定作业有关的信息
GetPrinter 取得与指定打印机有关的信息
GetPrinterData 为打印机设置注册表配置信息
GetPrinterDriver 针对指定的打印机,获取与打印机驱动程序有关的信息
GetPrinterDriverDirectory 判断指定系统中包含了打印机驱动程序的目录是什么
GetPrintProcessorDirectory 判断指定系统中包含了打印机处理器驱动程序及文件的目录
OpenPrinter 打开指定的打印机,并获取打印机的句柄
PrinterMessageBox 在拥有指定打印作业的系统上显示一个打印机出错消息框
PrinterProperties 启动打印机属性对话框,以便对打印机进行配置
ReadPrinter 从打印机读入数据
ResetDC 重设一个设备场景
ResetPrinter 改变指定打印机的默认数据类型及文档设置
ScheduleJob 提交一个要打印的作业
SetAbortProc 为Windows指定取消函数的地址
SetForm 为指定的表单设置信息
SetJob 对一个打印作业的状态进行控制
SetPrinter 对一台打印机的状态进行控制
SetPrinterData 设置打印机的注册表配置信息
StartDoc 开始一个打印作业
StartDocPrinter 在后台打印的级别启动一个新文档
StartPage 打印一个新页前要先调用这个函数
StartPagePrinter 在打印作业中指定一个新页的开始
WritePrinter 将发送目录中的数据写入打印机
--------------------------------
PB中控制码的传送及定制页长的实现
---- 在PB中通过函数Printsend(printjobnumber,string,{zerochar})来实现向打印机发送控制码。各参数定义如下:
printjobnumber: 由printjob()函数返回的打印作业号;
string: 控制字符串,使用ASCII码;
zerochar: 用来替代string中的数字0;
---- 由于字符串中,0终止字符串,如果string 中包含0,则需利用其他字符来表示0,参数zerochar即为此用途而设,当PB发送控制字符串给打印机时,把替代的字符zerochar转化为0。
---- 下面是具体的完成定制页长打印数据窗口的程序(定制页长为2.75英寸):
long ll_job
dw_print.reset()
ll_job = printopen()
if ll_job = -1 then
messagebox(gs_title,"打印机未准备好")
return
end if
//定制行距1/8英寸
PrintSend(ll_job, CHAR(27)+CHAR(48))
//设定页长22行
PrintSend(ll_job, CHAR(27)+CHAR(67)+CHAR(22))
printdatawindow(ll_job,dw_print)
printclose(ll_job)