Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8350988
  • 博文数量: 444
  • 博客积分: 10593
  • 博客等级: 上将
  • 技术积分: 3852
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-09 15:26
文章分类

全部博文(444)

文章存档

2014年(1)

2013年(10)

2012年(18)

2011年(35)

2010年(125)

2009年(108)

2008年(52)

2007年(72)

2006年(23)

分类: WINDOWS

2009-03-20 09:58:00

---------------------------------------选择打印机------------------------------
在用户需求中我们会遇到这样的问题,一台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)

阅读(11942) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

chinaunix网友2009-03-27 10:48:02

HANDLE PrnHandle; AnsiString PrinterName=ComboBox1->Text; if (OpenPrinter(PrinterName.c_str(),&PrnHandle,NULL)) { char buf[8192]; DWORD dwSize; if (GetPrinter(PrnHandle,2,buf,sizeof(buf), &dwSize)) { PRINTER_INFO_2* pInfo; pInfo = (PRINTER_INFO_2*)buf; //pInfo->Status 就是打印机的状态,详细的代码可以 //参见wins