http://www.ccidnet.com/tech/guide/2000/05/12/58_695.html

解决方案 »

  1.   

    http://www.google.com/search?q=%E6%9D%A1%E5%BD%A2%E7%A0%81%2Cdim&ie=UTF8&oe=UTF8&hl=zh-CN&lr=
      

  2.   

    http://www.ccidnet.com/tech/guide/2000/05/12/58_695.html
      

  3.   

    VB应用程序中打印条形码的两种方法  
    (作者:四川 李佑民 )  
      
      
      条形码作为一种机器可识别的图形,它能快速、准确地标识某种产品或商品,在许多数据库应用中起作很重要的作用,如超市收银、车站售票等场合。当某件物品上带有的条形码被条码扫描器正确解读后,将会得到该物品的唯一标识字符串,通过检索数据库我们就可以很容易知道它的一些其它属性并作相应处理。虽然在Internet上能找到许多免费和不免费的条形码打印控件,但是这些控件除了使用不方便外,还有一个最大的缺点:它们的打印输出不能和我们的程序共存在一个打印页面上,比如说在一个过程中,我们先向系统  Printer  中输出一些内容,然后再调用控件的条形码打印方法,最后打印的结果为两页!,如果现在我们要处理一张车票,上面不仅要打印条形码,还要有终点站和票价等信息,那么控件就变得不可用。对程序员来说,可能还是希望能了解条形码打印的原理,本文提出两种打印方法与同行们探讨。    
      
      
      
    一、直接利用有条形码打印功能的打印机    
      
      有许多打印机能够直接打印条形码,但在  VB  中,我们在DOS时代熟悉的LPRINT语句已经不能再使用了,打印操作被Windows的Spool系统完全接管,输出是以“页”为单位,所有的打印输出都被Windows转换为图形发送给打印驱动程序。而要使打印机打印条形码就必须将对应的ESC序列直接发送给它,因此我们就要想办法避开Windows的Spool系统,也就是说再程序中不能使用Printer对象和Printers集合处理打印输出,在VB中要将ESC指令直接发送给打印机至少有三种方法,前两种方法是调用Windows  API  函数:Escape()和SpoolFile(),第三种是最容易的方法:打开打印机端口进行二进制存取,我们主要考虑这种方法。    
      
      即使在Windows时代,”LPT1:”和”PRN”仍然是可用的,下面我们先作一个试验:打开一个DOS窗口,在提示符下输入COPY  CON  LPT1:回车,然后随便输入一些字符,最后按F6键,打印机就开始工作了,它将打印出你输入的那些字符!下面的代码演示了直接将指令和字符发送给打印机:    
      
    Private  Sub  Command1_Click()    
      
      Dim  strOut  As  String    
      
      StrOut  =  “这是直接发送到打印机端口的字符串”    
      
      ‘  打开打印机端口,其中的”LPT1:”可能需要根据你的打印机设置而改变    
      
      Open  “LPT1:”  For  Binary  Access  Write  As  #1    
      
      ‘  发送给打印机,注意语句的最后一个参数必须是变量    
      
        Put  #1,  ,strOut    
      
        ‘  关闭打印机端口    
      
        Close  #1    
      
    End  Sub    
      
      各种打印机打印条形码的指令可能不同,比如将上面的变量  strOut赋值为:    
      
      strOut  =  Chr(28)  &    “P”  &    Chr(5)  &    Chr(2)  &    Chr(3)  &    Chr(3)  &    Chr(6)  &    “012345”    
      
      将在  AR2400  打印机上打印出内容为”012345”的  CODE39  格式的条形码。具体的打印控制指令请参考打印机手册。    
      
      用这种方法的缺点:一是过份依赖打印机本身,而有条形码打印功能的打印机通常要比普通打印机昂贵,这会使构造应用系统不够经济;二是所有的打印输出都必须你自己处理,比如打印定位就很浪费时间。    
      
      
      
    二、利用画图方式输出到普通打印机    
      
      条形码的编码规则不外乎是通过线条和线条间间隙的宽窄不同来表示二进制的1和0,只要我们了解了条形码的编码规则,完全可以用画图的方式在普通打印机上得到可以接受的效果。下面我们就使用最普遍的CODE39码进行讨论。    
      
      CODE39码的编码规则是:    
      
    1、  每五条线表示一个字符;    
      
    2、  粗线表示1,细线表示0;    
      
    3、  线条间的间隙宽的表示1,窄的表示0;    
      
    4、  五条线加上它们之间的四条间隙就是九位二进制编码,而且这九位中必定有三位是1,所以称为39码;    
      
    5、  条形码的首尾各一个*标识开始和结束    
      
      在我们的程序中,给常用的字符都进行编码,解读时先取线条粗细,再取间隙宽窄,如:    
      
      
      
      上图中的字符*就可以解读为  001101000,字符3解读为  110000100    
      
      下面就是我们给出的子过程:    
      
    注释:  将字符串  strBarCode  对应的条形码输出到缺省打印机    
      
    Private  Sub  PrintBarCode(  _    
      
      ByVal  strBarCode  As  String,  _    
      
      Optional  ByVal  intXPos  As  Integer  =  0,  _    
      
      Optional  ByVal  intYPos  As  Integer  =  0,  _    
      
      Optional  ByVal  intPrintHeight  As  Integer  =  10,  _    
      
      Optional  ByVal  bolPrintText  As  Boolean  =  True  _    
      
    )    
      
    注释:  参数说明:    
      
    注释:  strBarCode    -  要打印的条形码字符串    
      
    注释:  intXPos,  intYPos  -  打印条形码的左上角坐标(缺省为(0,0),坐标刻度为:毫米)    
      
    注释:  intHeight      -  打印高度(缺省为一厘米,坐标刻度为:毫米)    
      
    注释:  bolPrintText    -  是否打印人工识别字符(缺省为true)    
      
      
      
    注释:  "0"-"9","A-Z","-","%","$"和"*"  的条码编码格式,总共  40  个字符    
      
    Static  strBarTable(39)  As  String    
      
    注释:  初始化条码编码格式表    
      
      strBarTable(0)  =  "001100100"    注释:  0    
      
      strBarTable(1)  =  "100010100"    注释:  1    
      
      strBarTable(2)  =  "010010100"    注释:  2    
      
      strBarTable(3)  =  "110000100"    注释:  3    
      
      strBarTable(4)  =  "001010100"    注释:  4    
      
      strBarTable(5)  =  "101000100"    注释:  5    
      
      strBarTable(6)  =  "011000100"    注释:  6    
      
      strBarTable(7)  =  "000110100"    注释:  7    
      
      strBarTable(8)  =  "100100100"    注释:  8    
      
      strBarTable(9)  =  "010100100"    注释:  9    
      
      strBarTable(10)  =  "100010010"  注释:  A    
      
      strBarTable(11)  =  "010010010"  注释:  B    
      
      strBarTable(12)  =  "110000010"  注释:  C    
      
      strBarTable(13)  =  "001010010"  注释:  D    
      
      strBarTable(14)  =  "101000010"  注释:  E    
      
      strBarTable(15)  =  "011000010"  注释:  F    
      
      strBarTable(16)  =  "000110010"  注释:  G    
      
      strBarTable(17)  =  "100100010"  注释:  H    
      
      strBarTable(18)  =  "010100010"  注释:  I    
      
      strBarTable(19)  =  "001100010"  注释:  J    
      
      strBarTable(20)  =  "100010001"  注释:  K    
      
      strBarTable(21)  =  "010010001"  注释:  L    
      
      strBarTable(22)  =  "110000001"  注释:  M    
      
      strBarTable(23)  =  "001010001"  注释:  N    
      
      strBarTable(24)  =  "101000001"  注释:  O    
      
      strBarTable(25)  =  "011000001"  注释:  P    
      
      strBarTable(26)  =  "000110001"  注释:  Q    
      
      strBarTable(27)  =  "100100001"  注释:  R    
      
      strBarTable(28)  =  "010100001"  注释:  S    
      
      strBarTable(29)  =  "001100001"  注释:  T    
      
      strBarTable(30)  =  "100011000"  注释:  U    
      
      strBarTable(31)  =  "010011000"  注释:  V    
      
      strBarTable(32)  =  "110001000"  注释:  W    
      
      strBarTable(33)  =  "001011000"  注释:  X    
      
      strBarTable(34)  =  "101001000"  注释:  Y    
      
      strBarTable(35)  =  "011001000"  注释:  Z    
      
      strBarTable(36)  =  "000111000"  注释:  -    
      
      strBarTable(37)  =  "100101000"  注释:  %    
      
      strBarTable(38)  =  "010101000"  注释:  $    
      
      strBarTable(39)  =  "001101000"  注释:  *    
      
      
      
      If  strBarCode  =  ""  Then  Exit  Sub  注释:  不打印空串    
      
      
      
      注释:  保存打印机  ScaleMode    
      
      Dim  intOldScaleMode  As  ScaleModeConstants    
      
      intOldScaleMode  =  Printer.ScaleMode    
      
      注释:  保存打印机  DrawWidth    
      
      Dim  intOldDrawWidth  As  Integer    
      
      intOldDrawWidth  =  Printer.DrawWidth    
      
      注释:  保存打印机  Font    
      
      Dim  fntOldFont 
      

  4.   

    Dim  x  As  Integer    
      
      x  =  Printer.ScaleX(intXPos,  vbMillimeters,  vbTwips)    
      
      注释:  将以毫米表示的  Y  坐标转换为以缇表示    
      
      Dim  y  As  Integer    
      
      y  =  Printer.ScaleY(intYPos,  vbMillimeters,  vbTwips)    
      
      注释:  将以毫米表示的高度转换为以缇表示    
      
      Dim  intHeight  As  Integer    
      
      intHeight  =  Printer.ScaleY(intPrintHeight,  vbMillimeters,  vbTwips)    
      
          
      
      注释:  是否在条形码下方打印人工识别字符    
      
      If  bolPrintText  =  True  Then    
      
        注释:  条码打印高度要减去下面的字符显示高度    
      
        intHeight  =  intHeight  -  Printer.TextHeight(strBC)    
      
      End  If    
      
          
      
      Const  intWidthCU  As  Integer  =  30  注释:  粗线和宽间隙宽度    
      
      Const  intWidthXI  As  Integer  =  10  注释:  细线和窄间隙宽度    
      
      Dim  intIndex  As  Integer      注释:  当前处理的字符串索引    
      
      Dim  i  As  Integer,  j  As  Integer,  k  As  Integer  注释:  循环控制变量    
      
      
      
      注释:  添加起始字符    
      
      If  Left(strBC,  1)  <  >    "*"  Then    
      
        strBC  =  "*"  &    strBC    
      
      End  If    
      
      注释:  添加结束字符    
      
      If  Right(strBC,  1)  <  >    "*"  Then    
      
        strBC  =  strBC  &    "*"    
      
      End  If    
      
          
      
      注释:  循环处理每个要显示的条码字符    
      
      For  i  =  1  To  Len(strBC)    
      
        注释:  确定当前字符在  strBarTable  中的索引    
      
        Select  Case  Mid(strBC,  i,  1)    
      
        Case  "*"    
      
          intIndex  =  39    
      
        Case  "$"    
      
          intIndex  =  38    
      
        Case  "%"    
      
          intIndex  =  37    
      
        Case  "-"    
      
          intIndex  =  36    
      
        Case  "0"  To  "9"    
      
          intIndex  =  CInt(Mid(strBC,  i,  1))    
      
        Case  "A"  To  "Z"    
      
          intIndex  =  Asc(Mid(strBC,  i,  1))  -  Asc("A")  +  10    
      
        Case  Else    
      
          MsgBox  "要打印的条形码字符串中包含无效字符!当前版本只支持字符  注释:0注释:-注释:9注释:,注释:A注释:-注释:Z注释:,注释:-注释:,注释:%注释:,注释:$注释:和注释:*注释:"    
      
        End  Select    
      
            
      
        注释:  是否在条形码下方打印人工识别字符    
      
        If  bolPrintText  =  True  Then    
      
          Printer.CurrentX  =  x    
      
          Printer.CurrentY  =  y  +  intHeight    
      
          Printer.Print  Mid(strBC,  i,  1)    
      
        End  If    
      
      
      
        For  j  =  1  To  5    
      
          注释:  画细线    
      
          If  Mid(strBarTable(intIndex),  j,  1)  =  "0"  Then    
      
            For  k  =  0  To  intWidthXI  -  1    
      
              Printer.Line  (x  +  k,  y)-Step(0,  intHeight)    
      
            Next  k    
      
            x  =  x  +  intWidthXI    
      
          注释:  画宽线    
      
          Else    
      
            For  k  =  0  To  intWidthCU  -  1    
      
              Printer.Line  (x  +  k,  y)-Step(0,  intHeight)    
      
            Next  k    
      
            x  =  x  +  intWidthCU    
      
          End  If    
      
      
      
          注释:  每个字符条码之间为窄间隙    
      
          If  j  =  5  Then    
      
            x  =  x  +  intWidthXI  *  3    
      
            Exit  For    
      
          End  If    
      
              
      
          注释:  窄间隙    
      
          If  Mid(strBarTable(intIndex),  j  +  5,  1)  =  "0"  Then    
      
            x  =  x  +  intWidthXI  *  3    
      
          注释:  宽间隙    
      
          Else    
      
            x  =  x  +  intWidthCU  *  2    
      
          End  If    
      
        Next  j    
      
      Next  i    
      
      
      
      注释:  恢复打印机  ScaleMode    
      
      Printer.ScaleMode  =  intOldScaleMode    
      
      注释:  恢复打印机  DrawWidth    
      
      Printer.DrawWidth  =  intOldDrawWidth    
      
      注释:  恢复打印机  Font    
      
      Set  Printer.Font  =  fntOldFont    
      
    End  Sub    
      
      
      
      最理想的情况是将它做成一个控件,在控件中提供一个打印方法,该方法实现与上    
      
      那个过程大致相同,只是不能在控件中直接使用VB的Printer对象,否则VB会将你在控件中的打印输出处理为一个单独的页面,而是应该将Printer.hDc传给它,通过调用那些需要指定  HDC  的Windows  API函数实现与容器的打印输出在一个页面上,比如我们可以这样定义这个控件的打印方法:    
      
    注释:  PrintIt  方法将对应的条形码输出到缺省打印机    
      
    Public  Sub  PrintIt(ByVal  PrintDC  As  Long,  _    
      
        Optional  ByVal  intXPos  As  Integer  =  0,  _    
      
      Optional  ByVal  intYPos  As  Integer  =  0,  _    
      
        Optional  ByVal  intPrintHeight  As  Integer  =  10)    
      
      既然不能使用Printer对象,那么画线和输出文字也不能使用Printer对象的Line和Print方法,在我们的程序中至少要申明以下三个Windows  API函数:    
      
    ‘  移动画笔的位置    
      
    Private  Declare  Function  MoveToEx  Lib  "gdi32"  (ByVal  hdc  As  Long,  ByVal  x  As  Long,  ByVal  y  As  Long,  lpPoint  As  POINTAPI)  As  Long    
      
    ‘  从画笔的当前位置到(x,y)画一条线    
      
    Private  Declare  Function  LineTo  Lib  "gdi32"  (ByVal  hdc  As  Long,  ByVal  x  As  Long,  ByVal  y  As  Long)  As  Long    
      
    ‘  在(x,y)处输出一个字符串    
      
    Private  Declare  Function  TextOut  Lib  "gdi32"  Alias  "TextOutA"  (ByVal  hdc  As  Long,  ByVal  x  As  Long,  ByVal  y  As  Long,  ByVal  lpString  As  String,  ByVal  nCount  As  Long)  As  Long    
      
    ‘  MoveToEx()  函数需要的参数    
      
    Private  Type  POINTAPI    
      
      xp  As  Long    
      
      yp  As  Long    
      
    End  Type    
      
    Dim  papi  As  POINTAPI    
      
      画线操作为(原来的Printer.Line函数):    
      
    MoveToEx  PrintDC,  x  +  k,  y,  papi    
      
    LineTo  PrintDC,  x  +  k,  y  +  intHeight  +  1    
      
      打印字符为(原来的Printer.Print函数):    
      
    TextOut  PrintDC,  x,  y  +  intHeight,  Mid(strBC,  i  +  1,  1),  1