资讯动态

Delphi一维条码控件:无依赖实现Code39与Code128打印

发布时间:2026/10/20 23:03:46 来源:尧图企业网站定制
简介这份资源面向仍在使用 Delphi 6 的开发者提供一套无需任何外部插件即可生成一维条形码的控件源码适用于库存管理、产品标识、标签打印等需要条码输出的场景。压缩包共 17 个文件约 239KB以 pas 源码、dcu 编译单元、dfm 窗体、dpr 工程文件为主另含 bmp 位图、res 资源、htm 说明及可执行示例便于直接编译运行与二次开发。控件支持 Code 39 与 Code 128 等常见一维码制涵盖字符编码、条纹绘制、校验码计算与打印输出等环节读者可从中理解条码编码原理、Delphi 图形 API 绘制方式以及打印布局处理思路。目前已有 1272 人学习下载适合希望低成本集成条码功能或研究 VCL 绘图与打印实现的中级开发者参考。1. 拆开这个 Delphi 一维条码控件为什么老项目还在用它上周帮一个做仓储管理系统的朋友排查打印问题他们那套 Delphi 6 写的老系统跑了十几年条码打印模块突然在几台新装的 Windows 上打不出 Code128换了几款第三方控件要么收费、要么依赖运行库、要么在 XP 上直接崩。最后翻出一个压箱底的.rar——一个纯 Delphi 代码实现的一维条形码控件没有 DLL、没有 OCX、没有外部依赖把单元文件拖进工程就能用。这件事让我意识到在工控、仓储、零售这些领域Delphi 6/7 的存量项目远比想象中多而条码打印恰恰是这些系统里最不能出问题的一环。这份资源解决的就是这个场景不装插件、不注册组件、不依赖任何第三方运行库用 Object Pascal 直接画出 Code39 和 Code128 两种最常用的一维条码。适合谁维护老 Delphi 项目的工程师、需要给现有系统快速加条码打印功能的开发者以及那些被商业控件授权费卡住的小团队。下面我从代码结构、编码原理、实际调用到踩坑记录把这份东西拆开讲清楚。2. 控件结构与编码原理先搞懂它在画什么2.1 单元文件里到底有什么解压后核心通常是一到两个.pas单元文件命名类似Barcode.pas或Code128.pas。打开看结构一般分三层最底层是编码表常量数组中间层是编码转换函数最上层是绘制过程。编码表是硬编码的——Code39 的 43 个字符加起始/终止符Code128 的 107 个码字全部以二进制位串或整数数组形式写死在const段里。这意味着它不查表文件、不读配置编译进去就是死的换台机器行为完全一致。绘制层通常提供两种输出方式一是直接画到TCanvas上适合TPrinter打印或TImage预览二是生成位图返回TBitmap方便嵌入报表或保存成文件。没有用 GDI 或任何图形库就是最原始的Canvas.MoveTo/Canvas.LineTo画竖条。这种做法的好处是兼容性极强从 Delphi 6 到 Delphi 10 都能编译代价是没有抗锯齿放大后边缘是硬的——但条码打印恰恰不需要抗锯齿反而要求边缘锐利。2.2 Code39 和 Code128 的编码差异Code39 是最简单的一维码之一每个字符由 9 个元素组成5 条 4 空其中 3 个是宽元素。它的字符集只有 43 个数字、大写字母、-、.、空格、$、/、、%。编码逻辑直白——查表拿到 9 位模式按位画宽窄条即可。起始符和终止符都是*所以实际数据前后会自动加上*。校验位可选Mod 43 算法很多场景直接不校验。Code128 复杂得多。它有三个子集A 集含控制字符和大写字母B 集含大小写字母和数字C 集专门放数字对。每个码字 11 位以11010010000Start B这类模式开头末尾跟校验位和停止符1100011101011。Code128 的密度比 Code39 高约 30%同样宽度能编更多数据而且支持全 ASCII。代价是编码逻辑要处理子集切换——比如一串数字中间夹个字母得从 C 集切到 B 集再切回来切换码字本身也占位。这份控件里Code39 的实现通常不到 100 行Code128 的编码函数会到 200 行以上主要开销就在子集切换判断上。我见过一些简化版直接固定用 B 集不切 C 集数字多的时候条码会偏宽但能扫——如果你的标签纸宽度够这反而是最省事的做法。2.3 条宽、窄宽比与静区参数画条码不是把位串一比一画出来就完事。三个参数直接决定能不能扫出来参数典型值作用调错后果窄条宽度1~3 像素最细那条的宽度太小打印糊太大标签放不下宽窄比2.0~3.0Code39 宽条/窄条小于 2 扫不出大于 3 太占地方静区10×窄条宽条码左右留白不留白扫描枪对不上焦控件里这些通常以属性形式暴露比如NarrowWidth、WideRatio、QuietZone。默认值往往偏保守——窄条 2 像素、宽窄比 3、静区 10 倍。实际用的时候如果打印机是 203 DPI 的热敏机窄条设 2 像素对应约 0.25mm刚好在多数扫描枪的识别范围内。设成 1 像素在屏幕上看着清楚一打印就断线这是最常见的翻车点。3. 在 Delphi 6 里跑起来从拖单元到出条码3.1 把单元加入工程并调用绘制过程假设解压得到Barcode.pas里面有一个TBarcode类或一组独立函数。最省事的用法是直接调函数不注册组件。在窗体单元的uses里加上Barcode然后在按钮事件里写procedure TForm1.btnPrintClick(Sender: TObject); var BC: TBarcodeRenderer; begin BC : TBarcodeRenderer.Create; try // 设置编码类型bcCode39 或 bcCode128 BC.Symbology : bcCode128; // 要编码的数据注意 Code39 只支持大写 BC.Data : ABC-123456; // 窄条宽度单位像素 BC.NarrowWidth : 2; // 宽窄比Code39 有效Code128 忽略 BC.WideRatio : 3; // 左右静区单位像素 BC.QuietZone : 20; // 直接画到 Printer 的画布上 Printer.BeginDoc; BC.DrawTo(Printer.Canvas, 100, 200, 400, 80); Printer.EndDoc; finally BC.Free; end; end;这段代码的逻辑很直白创建渲染器、设参数、调DrawTo。DrawTo的五个参数依次是目标画布、左上角 X、左上角 Y、最大宽度、高度。注意宽度参数是最大宽度——控件会根据数据长度和窄条宽度算出实际需要多宽如果算出来超过你给的值有的版本会截断有的会压缩这点必须先看源码确认。我一般会先调BC.GetWidth拿到实际宽度再决定打印位置。3.2 参数怎么设才扫得出来上面代码里的参数不是随便填的。NarrowWidth : 2对应 203 DPI 打印机约 0.25mm这是多数激光和热敏打印机的安全值。如果你用的是 300 DPI 的机器窄条设 2 像素就只有 0.17mm偏细建议设 3。QuietZone : 20是 10 倍窄条宽刚好卡在下限标签空间紧张时可以压到 15再小就玄学了——同一批标签有的扫得出有的扫不出查半天发现是静区不够。Code128 的WideRatio无效因为它的每个码字都是固定 11 位不存在宽窄条概念。但 Code39 必须设而且不能设 2.0 以下。我试过 1.8打印出来肉眼看着正常扫描枪十次里只认三次。设 3.0 最稳但条码会变宽约 50%标签窄的话自己权衡。还有一个隐藏参数是高度。DrawTo里的高度参数一般建议不低于 15mm对应 203 DPI 约 120 像素。太矮的条码对扫描枪的角度要求很苛刻收银台那种平扫的还好仓库里用手持枪斜着扫的矮条码就是灾难。3.3 打印预览与位图导出不是所有场景都直接打印。有时候要先在界面上预览或者把条码嵌进 FastReport 之类的报表里。这时候用位图输出procedure TForm1.ShowPreview; var BC: TBarcodeRenderer; Bmp: TBitmap; begin BC : TBarcodeRenderer.Create; Bmp : TBitmap.Create; try BC.Symbology : bcCode39; BC.Data : TEST001; BC.NarrowWidth : 2; BC.WideRatio : 3; BC.QuietZone : 20; // 先生成位图宽高由控件计算 BC.DrawToBitmap(Bmp, 300, 80); // 显示在 Image 控件上 Image1.Picture.Assign(Bmp); // 也可以存成文件 Bmp.SaveToFile(barcode.bmp); finally Bmp.Free; BC.Free; end; end;DrawToBitmap的宽高参数和DrawTo不同——这里是精确尺寸控件会把条码缩放到这个范围内。如果给的宽度不够条码会被压扁窄条变细可能扫不出。稳妥做法是先调BC.GetWidth(300)之类的函数拿到推荐宽度再传给DrawToBitmap。存成 BMP 的好处是可以用在报表工具里坏处是文件大、没压缩批量生成几百个标签时磁盘占用要注意。提示Delphi 6 的TBitmap默认是 24 位色存 BMP 没问题但如果要转成单色位图给某些老打印机用得手动调PixelFormat或做二值化处理否则打印出来灰度边缘会发虚。4. 避坑与排查那些让我加班到凌晨的细节4.1 打印出来扫描枪不认屏幕上却正常现象预览窗口里条码清清楚楚打印到纸上用扫描枪怎么都扫不出。原因通常有两个——一是打印机分辨率与窄条宽度不匹配屏幕上 1 像素对应打印机的多个点实际窄条被加粗或变细了二是打印机驱动做了缩放比如把 A4 内容缩放到标签纸上。解决把NarrowWidth按打印机 DPI 换算成物理尺寸203 DPI 下 2 像素约 0.25mm300 DPI 下要设 3同时在打印驱动里关掉缩放适应纸张用 100% 原始尺寸。4.2 Code39 数据里带小写字母条码直接空白现象传入abc123画出来一片空白或只有起始符。原因Code39 标准字符集只有大写字母控件遇到小写直接跳过或报错。解决在赋值前统一转大写BC.Data : UpperCase(Edit1.Text)。如果业务上必须区分大小写换 Code128 B 集它支持全 ASCII。这个坑我踩过两次第二次是因为忘了 Code39 连空格都支持但小写就是不认。4.3 Code128 数字串太长条码宽到标签外现象编 20 位纯数字条码宽度超出标签纸打印被截断。原因控件默认用 B 集编码每个数字占一个码字 11 位而 C 集可以把两个数字压进一个码字密度翻倍。解决看控件是否支持自动切 C 集如果不支持手动在数据前加 C 集起始符或者干脆换用 Code39——虽然密度低但 20 位数字在 40mm 标签上 Code39 反而可能放得下因为 Code39 没有子集切换开销。这是个反直觉的结论实测过才知道。4.4 在 Windows 10 上编译报错 Canvas 不支持现象Delphi 6 工程在 Win10 上编译通过运行时画条码抛异常。原因老版本 Delphi 的TPrinter.Canvas在某些新驱动下返回空或类型不匹配。解决不要直接画到Printer.Canvas先画到TBitmap再用Printer.Canvas.Draw贴上去。多一步中转兼容性立刻好转。这个技巧对所有老 Delphi 打印代码都适用不止条码。4.5 静区被优化掉了现象条码左右没有留白紧贴着标签边缘扫描枪要贴得很近才认。原因调用DrawTo时给的 X 坐标就是静区起点如果 X 设成 0静区就被画到画布外了。解决X 坐标至少留QuietZone的值比如BC.DrawTo(Canvas, BC.QuietZone, 200, 400, 80)。或者干脆在标签设计时左右各留 3mm 空白比在代码里算更省心。5. 进阶批量生成与校验位的手动补全批量打印是仓储系统的刚需——一次生成几百个库位标签每个条码数据不同。用这个控件做批量关键是别在循环里反复创建销毁渲染器把TBarcodeRenderer提到循环外只改Data属性procedure TForm1.BatchPrint; var BC: TBarcodeRenderer; I: Integer; Bmp: TBitmap; begin BC : TBarcodeRenderer.Create; Bmp : TBitmap.Create; try BC.Symbology : bcCode128; BC.NarrowWidth : 2; BC.QuietZone : 20; Printer.BeginDoc; for I : 1 to 200 do begin BC.Data : Format(LOC%06d, [I]); // 每 4 个标签换一页按实际标签纸排布调整 if (I - 1) mod 4 0 then begin if I 1 then Printer.NewPage; end; BC.DrawTo(Printer.Canvas, 50, 100 ((I - 1) mod 4) * 150, 400, 80); end; Printer.EndDoc; finally Bmp.Free; BC.Free; end; end;这段代码里Format(LOC%06d, [I])生成LOC000001到LOC000200(I-1) mod 4控制每页 4 个标签的纵向排布。实际标签纸的间距要自己量——常见的是 40mm×30mm一行两个、一列五个那mod的基数和 Y 偏移都要改。别照抄先拿一张空白标签试打用尺子量实际位置再调参数。校验位是另一个进阶点。Code39 的 Mod 43 校验、Code128 的 Mod 103 校验有些控件默认不算需要手动补。以 Code39 为例校验字符的计算逻辑是把每个字符在字符表中的索引值相加对 43 取模余数对应的字符就是校验位附在数据末尾、终止符之前。如果控件不自动加就得自己写个函数算出来拼到Data后面。扫描枪那边如果设了校验位检查不加校验位就会拒读如果没设加了也不影响。我一般建议加上多一个字符换更高的首读率值。最后说个验证方法生成条码后别只用一把扫描枪试。找两把不同品牌、不同年代的枪一把激光一把影像各扫十次。都过才算稳。从那以后我每次交付条码功能前都强制走一遍两枪各十次的流程再也没被现场退货过。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑