当前位置: 首页 > article >正文

别再只调API了!手把手教你用C#的PrintDocument类搞定小票打印(附完整源码)

别再只调API了手把手教你用C#的PrintDocument类搞定小票打印附完整源码在零售、餐饮等行业的软件开发中小票打印功能几乎是标配。很多开发者习惯性地寻找第三方库或现成的报表控件却忽略了.NET Framework中强大的PrintDocument类。本文将带你从零开始用最原生的方式实现专业级的小票打印功能。1. 准备工作与环境搭建1.1 创建基础项目首先创建一个Windows Forms应用程序项目。这是最常用的桌面应用开发方式也最适合小票打印场景。在Visual Studio中// 新建Windows Forms应用 File - New - Project - Windows Forms App (.NET Framework)提示建议使用.NET Framework 4.7.2或更高版本以确保最佳的兼容性和功能支持。1.2 添加必要的UI元素在Form1的设计器中添加以下控件一个ButtonbtnPrint用于触发打印一个PrintDocument组件printDocument1一个PrintPreviewDialogprintPreviewDialog1用于预览Button NamebtnPrint Text打印小票 / PrintDocument NameprintDocument1 / PrintPreviewDialog NameprintPreviewDialog1 DocumentprintDocument1 /2. 核心打印逻辑实现2.1 理解PrintDocument的工作原理PrintDocument类是.NET中打印功能的核心它通过事件驱动的方式工作。最重要的两个事件是BeginPrint打印开始前触发PrintPage每页打印内容时触发我们需要重点关注PrintPage事件在这里完成所有绘图逻辑。2.2 实现基本打印功能首先为printDocument1添加PrintPage事件处理private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) { // 获取Graphics对象这是我们的画布 Graphics g e.Graphics; // 设置字体 Font titleFont new Font(宋体, 14, FontStyle.Bold); Font normalFont new Font(宋体, 10); // 绘制标题 g.DrawString(某某商店销售小票, titleFont, Brushes.Black, 100, 20); // 绘制分隔线 g.DrawLine(Pens.Black, 50, 50, 300, 50); }2.3 动态构建小票内容小票内容通常是动态生成的我们可以使用StringBuilder来构建private string BuildReceiptContent() { StringBuilder sb new StringBuilder(); sb.AppendLine(订单号: DateTime.Now.ToString(yyyyMMddHHmmss)); sb.AppendLine(收银员: 张三); sb.AppendLine(-----------------------------); sb.AppendLine(商品名称 数量 单价 金额); sb.AppendLine(-----------------------------); // 模拟商品数据 var products new ListProduct { new Product { Name 可口可乐, Quantity 2, Price 3.5m }, new Product { Name 薯片, Quantity 1, Price 8.0m } }; foreach (var p in products) { sb.AppendLine(${p.Name.PadRight(10)} {p.Quantity.ToString().PadRight(5)} {p.Price.ToString(0.00).PadRight(7)} {(p.Quantity * p.Price).ToString(0.00)}); } sb.AppendLine(-----------------------------); sb.AppendLine(总计: products.Sum(p p.Quantity * p.Price).ToString(0.00)); return sb.ToString(); }3. 高级排版技巧3.1 精确控制文本位置小票打印需要精确控制每行文本的位置。我们可以使用Graphics.MeasureString方法计算文本尺寸private void PrintReceiptContent(Graphics g, string content) { Font font new Font(宋体, 10); float yPos 60; // 起始Y坐标 float leftMargin 50; // 左边距 foreach (var line in content.Split(\n)) { g.DrawString(line, font, Brushes.Black, leftMargin, yPos); yPos font.GetHeight() 2; // 行间距 } }3.2 处理多列对齐商品列表通常需要多列对齐显示。我们可以使用String.Format或插值字符串配合固定宽度// 更精确的列对齐方式 string format {0,-15}{1,5}{2,10}{3,10}; sb.AppendLine(string.Format(format, 商品名称, 数量, 单价, 金额)); foreach (var p in products) { sb.AppendLine(string.Format(format, p.Name, p.Quantity, p.Price.ToString(0.00), (p.Quantity * p.Price).ToString(0.00))); }3.3 添加公司LOGO如果需要打印公司LOGO可以这样实现private void PrintLogo(Graphics g) { if (File.Exists(logo.bmp)) { Image logo Image.FromFile(logo.bmp); g.DrawImage(logo, 50, 10, 100, 30); } }4. 完整实现与优化4.1 完整的PrintPage事件处理将前面所有功能整合private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) { Graphics g e.Graphics; // 打印LOGO PrintLogo(g); // 打印标题 Font titleFont new Font(宋体, 14, FontStyle.Bold); g.DrawString(某某商店销售小票, titleFont, Brushes.Black, 100, 50); // 打印内容 string content BuildReceiptContent(); PrintReceiptContent(g, content); // 打印页脚 Font footerFont new Font(宋体, 8); g.DrawString(谢谢惠顾欢迎再次光临, footerFont, Brushes.Black, 100, 400); g.DrawString(DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss), footerFont, Brushes.Black, 100, 420); }4.2 添加打印预览功能在打印按钮的点击事件中private void btnPrint_Click(object sender, EventArgs e) { // 预览 printPreviewDialog1.ShowDialog(); // 或者直接打印 // printDocument1.Print(); }4.3 处理多页打印如果内容超出一页需要设置HasMorePages属性private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) { // ...打印当前页内容... // 检查是否还有更多内容要打印 if (/* 还有内容 */) { e.HasMorePages true; } else { e.HasMorePages false; } }5. 实战技巧与常见问题5.1 选择合适的纸张大小小票打印机通常使用特殊的纸张尺寸。可以在打印前设置printDocument1.DefaultPageSettings.PaperSize new PaperSize(Custom, 300, 500);5.2 处理打印机设置允许用户选择打印机和设置打印参数PrintDialog printDialog new PrintDialog(); printDialog.Document printDocument1; if (printDialog.ShowDialog() DialogResult.OK) { printDocument1.Print(); }5.3 性能优化技巧复用Font和Brush对象避免频繁创建对于复杂的小票考虑先渲染到Bitmap再打印使用StringBuilder构建大文本内容// 复用对象示例 Font normalFont new Font(宋体, 10); SolidBrush blackBrush new SolidBrush(Color.Black); try { // 使用这些对象进行绘制... } finally { normalFont.Dispose(); blackBrush.Dispose(); }5.4 处理打印异常打印过程中可能会出现各种异常需要妥善处理private void btnPrint_Click(object sender, EventArgs e) { try { printDocument1.Print(); } catch (InvalidPrinterException ex) { MessageBox.Show(打印机设置错误: ex.Message); } catch (Exception ex) { MessageBox.Show(打印出错: ex.Message); } }6. 完整源码示例以下是完整的Form1.cs代码using System; using System.Drawing; using System.Drawing.Printing; using System.Text; using System.Windows.Forms; namespace ReceiptPrinterDemo { public partial class Form1 : Form { public Form1() { InitializeComponent(); printDocument1.PrintPage printDocument1_PrintPage; btnPrint.Click btnPrint_Click; } private void btnPrint_Click(object sender, EventArgs e) { printPreviewDialog1.ShowDialog(); } private void printDocument1_PrintPage(object sender, PrintPageEventArgs e) { Graphics g e.Graphics; // 设置纸张大小单位百分之一英寸 printDocument1.DefaultPageSettings.PaperSize new PaperSize(Custom, 300, 500); // 打印LOGO PrintLogo(g); // 打印标题 Font titleFont new Font(宋体, 14, FontStyle.Bold); g.DrawString(某某商店销售小票, titleFont, Brushes.Black, 100, 50); // 打印内容 string content BuildReceiptContent(); PrintReceiptContent(g, content); // 打印页脚 Font footerFont new Font(宋体, 8); g.DrawString(谢谢惠顾欢迎再次光临, footerFont, Brushes.Black, 100, 400); g.DrawString(DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss), footerFont, Brushes.Black, 100, 420); } private string BuildReceiptContent() { StringBuilder sb new StringBuilder(); sb.AppendLine(订单号: DateTime.Now.ToString(yyyyMMddHHmmss)); sb.AppendLine(收银员: 张三); sb.AppendLine(-----------------------------); sb.AppendLine(string.Format({0,-15}{1,5}{2,10}{3,10}, 商品名称, 数量, 单价, 金额)); sb.AppendLine(-----------------------------); var products new ListProduct { new Product { Name 可口可乐, Quantity 2, Price 3.5m }, new Product { Name 薯片, Quantity 1, Price 8.0m }, new Product { Name 矿泉水, Quantity 3, Price 2.0m } }; foreach (var p in products) { sb.AppendLine(string.Format({0,-15}{1,5}{2,10}{3,10}, p.Name, p.Quantity, p.Price.ToString(0.00), (p.Quantity * p.Price).ToString(0.00))); } sb.AppendLine(-----------------------------); sb.AppendLine(总计: products.Sum(p p.Quantity * p.Price).ToString(0.00)); return sb.ToString(); } private void PrintReceiptContent(Graphics g, string content) { Font font new Font(宋体, 10); float yPos 100; float leftMargin 50; foreach (var line in content.Split(\n)) { g.DrawString(line, font, Brushes.Black, leftMargin, yPos); yPos font.GetHeight() 2; } } private void PrintLogo(Graphics g) { if (File.Exists(logo.bmp)) { try { Image logo Image.FromFile(logo.bmp); g.DrawImage(logo, 50, 10, 100, 30); } catch { /* 忽略LOGO加载错误 */ } } } } public class Product { public string Name { get; set; } public int Quantity { get; set; } public decimal Price { get; set; } } }7. 扩展功能思路7.1 支持条形码打印许多小票需要打印条形码可以使用专门的库如ZXing.Netvar writer new BarcodeWriter { Format BarcodeFormat.CODE_128, Options new EncodingOptions { Height 50, Width 150 } }; var barcodeImage writer.Write(123456789); g.DrawImage(barcodeImage, 50, 300);7.2 多语言支持根据不同客户需求切换语言string title isChinese ? 销售小票 : Sales Receipt; g.DrawString(title, titleFont, Brushes.Black, 100, 50);7.3 打印样式配置允许用户自定义打印样式public class PrintSettings { public Font TitleFont { get; set; } new Font(宋体, 14, FontStyle.Bold); public Font ContentFont { get; set; } new Font(宋体, 10); public Color TextColor { get; set; } Color.Black; public int LeftMargin { get; set; } 50; }7.4 保存打印历史将打印内容保存到数据库或文件File.WriteAllText($Receipts/{DateTime.Now:yyyyMMddHHmmss}.txt, BuildReceiptContent());

相关文章:

别再只调API了!手把手教你用C#的PrintDocument类搞定小票打印(附完整源码)

别再只调API了!手把手教你用C#的PrintDocument类搞定小票打印(附完整源码) 在零售、餐饮等行业的软件开发中,小票打印功能几乎是标配。很多开发者习惯性地寻找第三方库或现成的报表控件,却忽略了.NET Framework中强大的…...

保姆级教程:在Ubuntu 22.04上为LAMMPS编译ReaxFF+Kokkos+OpenMP混合加速包(含GPU/CPU架构识别)

在Ubuntu 22.04上为LAMMPS编译ReaxFFKokkosOpenMP混合加速包的完整指南 对于计算材料科学和分子动力学模拟的研究者来说,LAMMPS是一个不可或缺的工具。然而,当模拟系统变得复杂时,计算效率往往成为瓶颈。本文将详细介绍如何在Ubuntu 22.04系统…...

Supertonic架构演进:从v1到v3的技术升级路线分析

Supertonic架构演进:从v1到v3的技术升级路线分析 【免费下载链接】supertonic Lightning-Fast, On-Device, Multilingual TTS — running natively via ONNX. 项目地址: https://gitcode.com/GitHub_Trending/sup/supertonic Supertonic是一款闪电般快速的设…...

CentOS 7最小化安装后,如何用VNC Viewer远程连接GNOME桌面?实测避坑指南

CentOS 7最小化安装后构建GNOME远程桌面的完整实践指南 当你面对一台仅完成最小化安装的CentOS 7服务器,突然需要图形界面完成某些复杂配置时,这套从零构建GNOME桌面环境并通过VNC安全访问的解决方案,将成为你的技术救星。不同于常规教程&…...

别再死记硬背!一张图+三个口诀,快速理解自反、对称、传递闭包怎么求

离散数学闭包运算:图解口诀实战,3分钟掌握核心技巧 第一次接触离散数学中的闭包运算时,很多同学都会被各种定义和符号绕晕。其实只要掌握几个简单的视觉化技巧,就能像搭积木一样轻松构建自反、对称和传递闭包。本文将用最直观的关…...

2026年程序员AI工具链完整配置指南:从开发到部署全流程

你的开发环境还在用2023年的工具?醒醒,AI工具链已经迭代了三代了。## 前言作为一个从 Cursor 0.x 版本就开始跟的早期用户,我亲眼见证了AI编程工具从"玩具"变成"生产力核武器"的过程。2026年5月的今天,整个AI…...

告别龟速下载!手把手教你用huggingface_hub把transformers模型存到本地指定文件夹

告别龟速下载!手把手教你用huggingface_hub把transformers模型存到本地指定文件夹 在深度学习项目的日常开发中,Hugging Face的transformers库已经成为NLP和计算机视觉领域的事实标准工具包。然而,许多开发者都遇到过这样的困扰:当…...

重新定义游戏体验:Atmosphere稳定版如何重塑Switch生态系统

重新定义游戏体验:Atmosphere稳定版如何重塑Switch生态系统 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 🔍 传统方案的三大痛点与Atmosphere的突破性解决方案 对…...

WechatSogou微信公众号爬虫实战指南:高效获取公众号数据的Python解决方案

WechatSogou微信公众号爬虫实战指南:高效获取公众号数据的Python解决方案 【免费下载链接】WechatSogou 基于搜狗微信搜索的微信公众号爬虫接口 项目地址: https://gitcode.com/gh_mirrors/we/WechatSogou 在信息爆炸的时代,微信公众号已成为内容…...

CMMLU中文理解瓶颈再定位:从词义消歧到跨文档推理,5个未公开bad case驱动的模型优化路径

更多请点击: https://intelliparadigm.com 第一章:CMMLU中文理解瓶颈再定位的总体发现 评测基准与数据分布偏移现象 近期对 CMMLU(Chinese Massive Multitask Language Understanding)基准的系统性重测揭示:模型在人…...

Claude Code 工具提示词全拆解:AI Agent、Prompt Engineering、工具调用、上下文工程、自动化编程的底层逻辑

开篇导读很多人做 AI Agent 时,最容易盯着模型参数、系统提示词、工具数量,却忽略了一个非常关键的细节:每一个工具自己的提示词。它看起来只是一个 description 字段,实际上却在悄悄决定模型什么时候用工具、怎样用工具、不能做什…...

Claude Code 模型特定调优与 A/B 测试全解析:Feature Flag、灰度发布、Undercover、安全门控、Prompt 调优与 AI Agent 工程化实战

一、先说结论:AI Agent 真正难的不是“会调用模型”,而是“能持续驾驭模型”很多人做 AI 编码助手、企业智能体、研发提效工具时,第一反应是接入一个更强的大模型:换成更大的参数、更新的版本、更长的上下文,似乎问题就…...

Perseus:碧蓝航线皮肤解锁补丁的完整使用指南

Perseus:碧蓝航线皮肤解锁补丁的完整使用指南 【免费下载链接】Perseus Azur Lane scripts patcher. 项目地址: https://gitcode.com/gh_mirrors/pers/Perseus 你是否曾经在《碧蓝航线》中看到心仪的舰船皮肤,却因为需要付费而望而却步&#xff1…...

面向AI系统的非功能测试:公平性、可解释性与鲁棒性验证

一、引言:当“功能正确”不再是终点在软件测试的早期时代,我们的职责边界相对清晰——功能符合需求文档、性能达到指标、界面无错别字,测试便可宣告完成。然而,当AI系统从实验室的象牙塔走向社会决策的核心地带,这套传…...

Sora提示词工程:从静态描述到动态世界导演的AI视频创作指南

1. 项目概述:当“提示词”成为Sora的“方向盘”最近在AI视频生成圈子里,一个叫SoraEase/sora-prompt的项目开始被频繁提及。乍一看,这只是一个GitHub上的开源仓库,里面可能收集了一些用于OpenAI Sora模型的提示词(Prom…...

掌握Flash逆向工程:JPEXS免费反编译工具完全指南

掌握Flash逆向工程:JPEXS免费反编译工具完全指南 【免费下载链接】jpexs-decompiler JPEXS Free Flash Decompiler 项目地址: https://gitcode.com/gh_mirrors/jp/jpexs-decompiler 在Flash技术逐渐淡出历史舞台的今天,无数经典的Flash动画、游戏…...

Buildah:从Dockerfile到OCI镜像的构建原理与生产实践

1. 项目概述:从 Dockerfile 到 OCI 镜像的“幕后推手”如果你用过 Docker,那你一定对docker build命令和Dockerfile不陌生。输入一行命令,等待片刻,一个包含了应用及其所有依赖的、可移植的容器镜像就生成了。这感觉就像魔法&…...

Spring Boot TransactionTemplate 实战:从声明式到编程式事务的进阶指南

1. 为什么需要编程式事务? 在Spring Boot开发中,事务管理就像给数据库操作上的保险。我们最熟悉的Transactional注解确实方便,就像自动驾驶模式——简单标注一下,Spring就会自动帮我们处理事务的开启、提交和回滚。但实际开发中总…...

思源宋体CN:7款免费开源中文字体快速上手完整指南

思源宋体CN:7款免费开源中文字体快速上手完整指南 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 思源宋体CN(Source Han Serif CN)是由Adobe和Goog…...

Acton权限提升防护:访问控制安全实现的完整指南

Acton权限提升防护:访问控制安全实现的完整指南 【免费下载链接】acton Toolchain for TON smart contract development and beyond 项目地址: https://gitcode.com/GitHub_Trending/acto/acton Acton作为TON智能合约开发工具链,提供了强大的访问…...

别只盯着公式!用ADS仿真带你‘看见’串扰:从饱和长度到脉冲宽度的实战观察

别只盯着公式!用ADS仿真带你‘看见’串扰:从饱和长度到脉冲宽度的实战观察 在高速电路设计中,串扰问题如同一个隐形的干扰者,常常在工程师最意想不到的时刻出现。传统教材中复杂的公式推导虽然严谨,却让许多工程师难以…...

Vivado跨SLR时钟路径优化指南:从ERROR: [Place 30-681]理解BUFG与全局时钟网络

Vivado跨SLR时钟路径优化实战:从架构原理到约束策略 在UltraScale这类多SLR架构的FPGA设计中,时钟网络规划往往是决定项目成败的关键因素。当你在Vivado中看到ERROR: [Place 30-681]这类与跨SLR时钟路径相关的报错时,表面上看是工具在抱怨布局…...

油猴脚本集成ChatGPT:从原理到实战的浏览器AI自动化指南

1. 项目概述:一个为油猴脚本注入ChatGPT能力的起点如果你是一名前端开发者,或者对浏览器自动化、网页增强有浓厚的兴趣,那么你一定听说过或者用过“油猴脚本”。它就像给你的浏览器装上了一套瑞士军刀,可以自定义网页的样式、功能…...

ArchR实战避坑指南:从scATAC-seq数据到细胞轨迹分析,我的踩坑记录与参数调优心得

ArchR实战避坑指南:从scATAC-seq数据到细胞轨迹分析 当你在深夜第三次尝试用ArchR处理scATAC-seq数据时,突然弹出的红色报错信息是否让你感到绝望?作为一款强大的单细胞染色质可及性分析工具,ArchR的官方教程虽然详尽,…...

告别依赖冲突!在Ubuntu上编译GmSSL静态库的保姆级教程

告别依赖冲突!在Ubuntu上编译GmSSL静态库的保姆级教程 在Linux开发环境中,密码学库的版本管理一直是令人头疼的问题。特别是当我们需要同时使用国际标准算法和国密算法时,OpenSSL与GmSSL的兼容性问题常常让开发者陷入困境。本文将彻底解决这个…...

Diablo Edit2:解放暗黑破坏神II角色定制的终极免费工具

Diablo Edit2:解放暗黑破坏神II角色定制的终极免费工具 【免费下载链接】diablo_edit Diablo II Character editor. 项目地址: https://gitcode.com/gh_mirrors/di/diablo_edit 还在为暗黑破坏神II中无尽的刷怪升级感到疲惫吗?想要快速体验不同职…...

如何轻松解包网易游戏资源:unnpk工具完整使用指南

如何轻松解包网易游戏资源:unnpk工具完整使用指南 【免费下载链接】unnpk 解包网易游戏NeoX引擎NPK文件,如阴阳师、魔法禁书目录。 项目地址: https://gitcode.com/gh_mirrors/un/unnpk 你是否曾好奇网易热门游戏如《阴阳师》、《魔法禁书目录》中…...

全国青少年信息素养大赛初赛(算法创意实践挑战赛C++初中组:样题带解析)

一、选择题 1、现有数组定义为 int array[5] {1};,数组 array 中的 元素分别是_____ A. 1 2 3 4 5 B. 0 0 0 0 1 C. 0 0 0 0 0 D. 1 0 0 0 0 答案:D 解析:int类型的数组中未赋值的元素,初始化赋值为0 2、在 C语言中&#…...

Nginx Server Configs:微服务网关API管理与路由配置终极指南 [特殊字符]

Nginx Server Configs:微服务网关API管理与路由配置终极指南 🚀 【免费下载链接】server-configs-nginx Nginx HTTP server boilerplate configs 项目地址: https://gitcode.com/gh_mirrors/se/server-configs-nginx 在当今微服务架构盛行的时代&…...

lz4宏展开调试终极指南:-E选项与预处理分析技巧

lz4宏展开调试终极指南:-E选项与预处理分析技巧 【免费下载链接】lz4 Extremely Fast Compression algorithm 项目地址: https://gitcode.com/GitHub_Trending/lz/lz4 lz4作为一款Extremely Fast Compression algorithm,在开发过程中,…...