说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

VB应用程序中打印条形码的两种方法

HTML文档下载 WORD文档下载 PDF文档下载
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 As StdFont

  Set fntOldFont = Printer.Font

  

  Printer.ScaleMode = vbTwips 注释: 设置打印用的坐标刻度为缇(twip=1)

  Printer.DrawWidth = 1   注释: 线宽为 1

  Printer.FontName = "宋体" 注释: 打印在条码下方字符的字体和大小

  Printer.FontSize = 10

  

  Dim strBC As String     注释: 要打印的条码字符串

  strBC = Ucase(strBarCode)

  注释: 将以毫米表示的 X 坐标转换为以缇表示

  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
AMD打造开放的异构计算标准? Podcasts:苹果史上最烂iOS应用 烂过iOS Maps 日本游戏开发公司谈:如何在激烈的APP世界立足 VC不会告诉你的8件事 Reddit宣布将接受虚拟货币Bitcoin付款 OneID创始人:双因素身份验证无法保护Twitter Opera放弃自家内核转投WebKit的背后 Amazon强攻私有云市场,目标锁定银行 微软的24年数据中心之路 Flurry:约会应用男同性恋用的最多 jQuery消息提示框的简单实现 Mozilla CTO:Mozilla不会转向WebKit 这很重要 Pinterest或超Twitter成第二大社交网站 适合儿童上手的八款编程工具 一周云事件:亚马逊对消费者的吸引力超过苹果 比尔&#183;盖茨对微软创新和手机不满意 让我们一起来做最漂亮的Android界面吧! 响应高达6秒 用户揭露Heroku修改路由“50倍圈钱”? [探讨]响应式设计四大原则 Linux Kernel 3.8发布 停止支持386设备 HTML5手机游戏引擎Devkit开源 程序员的一天:台湾个人移动游戏开发者 极限破解:利用低温环境读取Android加密数据 五种工具保护你的在线隐私 从打压到支持 微软与GitHub的爱恨情仇 “夫妻档”初创公司百万美元打造实时Hadoop系统 编程从娃娃抓起:13岁儿童的移动游戏之梦 新浪管理层调整 许良杰任CTO兼联席总裁 Java,你还会让多少人继续“受伤”? 中国或超美国 成全球智能设备市场霸主 告别手写 API文档生成工具推荐 谁先回来马上给分(简单问题) 机器的usb问题!! 兄弟们,小弟刚接触JSP,帮忙解决一个问题。 请教PHP.INI配置里的SESSION! 刚开始接触.net 求购程序,请进. 求购程序 求购程序 推荐一些适合初学者看的书吧 一家位于Montreal, Canada的公司,求购一个程序 如何保存UNICODE的字符串到硬盘上 如何将HTML文本直接显示在CppWebBrowser中?(不使用临时表) 如何保存UNICODE的字符串到硬盘上 redhat第4第5两个iso文件是做什么的 关于jsp做客户端调用ejb的问题?????望各位兄弟们救救我吧!!!!! COOL!将所有菜单设置为半透明的代码(只适用于WIN2000以下版本) 请问谁知道如何用jakarta-jmeter进行压力测试? 如何判断文件夹是否存在 在Win2K Server安装Oracle817时,没有安装数据库,后在创建数据库时出现"ORA-12560:TNS:协议适配器错误"... 请教.net服务器问题 解决这个问题,给你200分!!!!!!!!!!(回头追加给你!) 我是初学者,请问.net framework先进性在哪里? 有谁试过用JAVA编FTP软件? 很简单的listBox问题,HELP 今年大四,现在找工作,求助,我怎么样………UP有分。 寻找!! IE的文本输入框,输入一字符会联想,请问怎样去掉这个联想?(Win2K) 哪位大俠能賜教 哪位大俠能賜教 你们说VC到底要学些什么?VC更偏底层,总做这种纯技术总也做不完。迷茫~~~ 请问,在Oracle里建trigger是不是有什么说法呢?一个正常的不能在正常的trigger在Oracle里运行也说compilation errors. 请教:提取字符串里每个字符首字母,谢谢!!! aa模块代码 关于强烈要求恢复可用分增长、可用分转移、非技术区得分转换为可用分的建议!! SOS:如何找到窗口中多个进程其中我所需要的那一个? SOS:如何找到窗口中多个进程其中我所需要的那一个? 笑的人再发几个 query1.next是将指针移向下一条,啊向上条一记录是用什么命令呢? 对话框中使用工具栏如何进行更新? 关于文件指针的问题 ASP中SELECT 查询中前几条的查询如:TOP 的用法哪位讲解一下. 如何查找到两个不同数窗的不同数据 诚招ASP老师一名(请版主不要删) 提问!(欢迎讨论) 停电重启 原来已经编译通过的程序,再重新编译竟然出现了150个错误 一个很奇怪的想法 请问怎么转换以空格为分割符的文本文件转换为以TAB为分割符的文本文件?急! WIN2000下怎么设CLASSPATH (散分):BDE,ADO,dbExpress的前景如何? 关于VB调用asp的问题 如何关闭office2000文件优化器? 英语翻译危的古意、黯然的古意、或的古意、念得古意 Four hundred yuan for a shirt?It's too e___ 问号是开启任何一门科学的钥匙的作者在什么地方的什么人物什么学家 英语,求英语学霸回答, The coat is one hundred yuan改为同义句The coat ( )one hundred yuan 问号是开启任何一门科学的钥匙.作者巴尔扎克的国家在哪? 英语学霸求答案 The pencil is (four yuan ).刮号内提问 交通运输对社会经济发展的作用有哪些 求英语学霸答案,谢谢 What is the letter we have in December but we don't havein any other months?这句话的翻译? 求几个表示孤独的英文句子 描写兄弟间友爱的成语 what is it thatwe have in December but that we do not have in any other month 能不能不让我孤单翻译成英语句子 英语学霸们,知道的回答, 求现代人写的等待爱情的古诗词 中国社会的主要矛盾是人民日益增长的物质和文化的需要同落后生产力之间的矛盾为什么会出现这个现象?我想把这个问题展开来说! 海洋发起脾气来,也会【掀翻船只,冲垮堤坝,毁灭城镇】 写出一系列的动作 写借物抒情的诗句(现代人自己写,不要古诗宋词.) 《论语》警句摘录卡 That is a nice picture 改复数句 你认为中国古典诗词传达给现代人的是什么? 请问有那个做电线电缆外贸的高手可以告诉我电线,电缆的HS编码和其他相关信息啊我想知道这个编码那里有查找,还有相关的退税率,等等相关的信息.我们的产品主要是低压电力电缆,电线.比 Have we lost our minds? ..]Eric _____ his bicycle to the shop.A.rides B.ride C.is riding我选C,“标准答案”是A...应该选什么啊... “问号是开启任何门科学的钥匙”的作者是谁?包括作者的国家 How _______ is the cake?Three yuan.并请您说明理由 求教第36题,谢谢了! 曾经沧海难为水,除却巫山不是云这两句诗是啥意思 The is 30 yuan,that cake is 60 yuan同义句The is 30 yuan—— ——that one 36题答案是什么, 请教一下“曾经沧海难为水,除却巫山不是云.”这两句诗, My apple is (sour) 括号提问 This cake is (five yuan) 括号提问 第三十六题 X^2-4X=0(解方程) 掀翻船只,冲垮海堤,毁灭沿海的城镇 这三个词能调换吗?为什么? 人教版五年级上册数学练习二十五第9题怎么写一张边长4cm的正方形纸,从相邻两边的中点连一条线段,沿这条线段剪去一个角,剩下的面积是多少? 初三数学二次函数题求解答过程.(主要是想看看我做的对不对,特别是最后一问.)某商场购进一批单价为 20 元的日用品,销售一段时间后,为了获得更多利润,商场 决定提高销售价格.试销阶段 有没有描写美女的句子(现代的) 光学传递函数是什么?定义? 带口成语有哪些 Is that a photo?的复数形式 光学传递函数的理论基础是什么 汉字翻译正确拼音 上面文字下面拼音再别康桥徐志摩轻轻的我走了,正如我轻轻的来;我轻轻的招手,作别西天的云彩.那河畔的金柳,是夕阳中的新娘;波光里的艳影,在我的心头荡漾.软泥上的 the tv costs nint thousandeight hundred 1.The children are coming____the classroom.A.at B.out of C.on2.Whose father is a worker?____,I don't know.A.Excuse me B.Pardon C.Sorry有原因更好(为什么不选其他选这个) 问号是开启任何一门科学的钥匙 巴尔扎克他是什么国,什么家kuai kuai Mary spent three thousand yuan on the color TV set.The color TV set ____ ____ three thousand yuan 扩散性百万亚瑟王满破什么意思? 问号是开启任何一门科学的钥匙. 巴尔扎克他是什么国是什么家,比方物理学家 爱护地球的名句 模仿造句:但是,海洋发起脾气来,也会无情地掀翻船只,冲垮堤岸,毁灭沿海的城镇,给人类带来可怕的灾难.这个句子运用了什么修辞手法 百万亚瑟王满级的 切尔莉 经验会变多么?满破呢? 但是,海洋发起脾气来,也会无情地掀翻船只,冲垮堤岸,毁灭沿海的城镇 用掀翻,冲垮,毁灭加拟人一起造句 求一首自己写的仿古代诗歌和现代诗歌,要自己写的,因为要交给老师改的 [百万亚瑟王]谁能给我解释解释,为什么我丢了一张满破的7星卡 关于地球的名言警句要短的 描写春夏来到的现代短诗短诗喔,积极地,春天的充满朝气与希望的积极的就行! 槽钢,上海槽钢贸易公司,
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘