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

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
顺丰模式:物流行业“互联网化”的科技之路 移动应用云服务工具APICloud宣布完美适配iPhone6 从应用分发到能力开放 华为开发者联盟沙龙上的共赢理念 SOOMLA框架:移动游戏分分钟创建个虚拟商店 Facebook:如何让应用适合所有系统、带宽以及屏幕 Docker实践者不能错过2014 Container技术大会的九大理由!(讲师议题全面揭晓) 2014全球云计算大会中国站(CC China)精彩集锦 腾讯X5浏览服务正式开放 30多款APP成为首批受益者 Node.js设计经验谈 LeanKanban University首位中国认证讲师路宁:看板会为更多国内企业带来深刻变革 环信IM沙龙纪实:无分享不IM,无社交不未来 【工具推荐】ESL:更简洁、更高效的标准加载器 【先锋】亲加通讯云:以云服务模式为App提供社交引擎 2014中国移动开发者大调查第一批获奖名单大曝光 移动开发云服务AVOS Cloud宣布完成A轮融资 Uplinq2014:人工智能嵌入硬件 万物互联建生态 Uplinq2014:基于Vuforia的新奇智能玩具 一应俱全!开源跨平台3D应用开发框架Minko 【线下技术培训】敏捷测试实战解析和系统方案 《近匠》Ping++:简单、高效、第三方支付SDK 有关编程的12个猜想 【问底】王帅:深入PHP内核(二)——SAPI探究 【CTO俱乐部走进汽车之家】活动图文实录 只为逼格?超薄便携式无线充电设备Deuce 戴尔未来重心:云计算、大数据、移动互联与安全 【讲师】搜狐于顺治:Container在搜狐PaaS平台中的应用实践 【先锋】从代码层诊断,云端OneAPM平台让开发者专注开发 阿里将推无线领域重磅计划 阿里百川无线开放大会揭晓 提升网站转化率的四步优化方案 开发者应该了解的API技术清单! 【讲师】腾讯刘永峰:Docker时代,公有云面临的挑战和机遇 关于sql*loader导入excel文件的问题 请问哪儿有电影<<上帝也疯狂>>下载,我不能用ftp 水晶报表多字段分组的问题 他妈的,在网上下在的vb也不行呀.我靠. 我对一个从数据库读来的数值型变量用cint,怎么老是说溢出阿? 拜托了,我快崩溃了!请帮忙看看http://expert.csdn.net/Expert/topic/2247/2247767.xml?temp=.7379419 帮忙看看http://expert.csdn.net/Expert/topic/2244/2244528.xml?temp=.1244013 昨天国奥的问题到底出在哪里?大家看看主席怎么说。 ********** 中秋愉快,午饭后结贴 ************** 关于两种脚本的混用问题的怪事,解决高分相送? What means "ZT"? What means "im"? What means "P.S."?? Why??????????? 一个对你不是问题的问题(关于输入的)!谢谢. 请问如何在C#中实现管道操作??? 急!!! 中秋一人之心情舒畅!!! asp.net访问页面需认证 小女子祝各位中秋愉快~~~~~~~~~~~~~~~~ 黑盒测试中的边界值测试--要看到程序内部,why不属于白盒 急死人!!今天必须解决的问题:怎么在网页中使用word啊?怎么在网页中打开数据库中的二进制word文档? 求助:怎么读取条形码哦? 高分求购辞职信书写方案 哥们,如何将文件的内容上传到ORACLE数据库的CLOB字段中(中文问题)!急呀! 运行后,对我的输入,没有输出,为何??? 请教,IIS下面FSO相关代码无法正常运行 SQL Server中如何取得某个字段前后数据的差量?取其中某个数据如何表示!!!给分! 序列容器和关联容器有何区别? 一道考试题 可不可以有我自己的namespace??? [DBNMPNTW]找不到指定的 SQL Server。 怎么解决? 初次到数据库来提问,希望能得到各位的帮助:怎么将word文档弄进SQL数据库啊?二进制的。具体的操作步骤。 在触发器中调用存储过程?在线等待!!!! 关于DialogBox,有一事不明 ***** 谁能说出来域的十大有点?***** 保证让你笑的过瘾的37个笑话[推荐] 在Recordset对象的 getXXX 方法中,那个XXX 和 SQL Server 2k 中的 uniqueidentifier 类型相匹配,小弟急用!!! 有哪位大哥能近来帮我看一下这是什么问题?? SQL Server中如何取得某个字段前后数据的差量?取其中某个数据如何表示!!!给分! 关于数据窗口语法的拼接!!!!!!!!!!!!!请高手帮忙!! 非常菜的两个问题。有劳各位了 中秋,游子,放分---一祝母亲福泰安康,清福永享. 数1000张图的显示问题。 数据库中时间日期字段的问题 急急 四个裤衩了:) 中秋放分! 为什么可以ping通但上不了网 今天实在是太高兴了,逢中秋又升双星,散分!! 怎样得到数据窗口的sql生成语句? 路由的一个问题 高手请进!!关于线程问题 月饼节到了,祝所有在外工作的程序员们节日快乐, 忘记了XP的密码和用户名,怎么进去?(在线等) 求mo的文档,急 “钱是万能的!”这句话在现实生活中是不是就对了呢? 论语中八则的名言警句中生活交际的句子 一两句磨棱两可的英语句子Eliza remembers everything exactly as if it_____yesterdayA.was happeningB.happensC.has happened D.happened我选的是D,但是答案不是我想知道为什么?The car is in_____bad condition _____you can't drive i 第五题哦 怀集县有什么特色 前秦时期,汉族是主体民族吗? 第5题哦~ 20天的婴儿能吃醒脾养儿颗粒吗? 女生怎样练腹肌?13岁每天都做仰卧起坐,练了快一个月了,从每天30下加到45下,就是练不出来,怎样尽快练出来呀,是那种能显示出来的 六块腹肌与八块腹肌有什么区别? 有一个半圆形的鸡舍,靠墙而建的,直径是6米,如果将鸡舍的直径增加2米,这个鸡舍的面积是多少平方米? 港媒:三中全会或开启中国“黄金时代”美国官员称奥巴马对监听各国政要事并不美学者:星巴克咖啡在中国必须贵 否则湖南纪委回应干部突击办酒:发现即查处最高法:健全和完善错案评价标准和问责霍英东遗产案于其忌日开庭 一方被批“汉字听写缺少科技内容:不能钻到茴香豆世界新闻报窃听丑闻开审 卡梅伦政府威叙利亚电子军自称攻破奥巴马推特账户日本9月份失业率降至4%摄影发烧友新宠:3D打印遮光罩(图)[独家]许子东:张贤亮是中国的索尔仁第32届大众电影百花奖在甘肃兰州揭晓昆明市福建龙岩商会成立 促两地经贸文英超-曼联2-1西汉姆联 鲁尼破门染曼联球迷跑皇马客场放飞机 挂“C罗回英超-切尔西3-0维拉第32届百花奖:黄晓明封“帝” 章子新疆维吾尔自治区妇女第十一次代表大会张贤亮:现在的东西没有超出我的 哪个古力:十番棋结果不会影响我与李世石之作家张贤亮和他的影视城:一片荒凉上垒绿茵狂想仙人是怎样炼成的战气昂然噬柳仙盆未央游记天门圣徒汉魄星夜思网游之神魔空间异世巫妖技能穿越修真记灵顺寺旅游逢甲夜市旅游九族文化村旅游伊达邵码头旅游小湾旅游国立海洋生物博物馆旅游砂卡礑步道旅游龙王庙行宫旅游安亭老街旅游碧沽天池旅游易俗社剧场旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘