C# 可视化 打印格式设计 模板设计 单据打印 标签打印

时常在网络上搜索关于打印格式的设计方面的资料,发现资料比较少,前一段时间因为有一个项目有这样一个需求,需要客户自定义打印格式,自己干脆做了一个,基本能满足要求.

本文章已经发布了三个版本,越靠后面 版本越新,功能更完善.

https://download.csdn.net/download/guo9long/89450604

https://download.csdn.net/download/guo9long/89623501

https://download.csdn.net/download/guo9long/89642363

(包含Demo,测试的模板,可以直接运行debug里面的exe看效果.)

20240912已经发布了 可拖拉的最新版,链接地址如下:

新版链接

C# 可视化 拖拉控件 打印格式设计 模板设计 单据打印 标签打印 使用教程-CSDN博客

感兴趣的朋友可以去关注下。

开发环境:vs2019 + Dev express 20.1(如果不用修改模板设计代码, 可不用安装DevExpress环境.)

引用下载的DLL后,把里面的 frmFormatForm 设计窗体show出来.

 HY.PrintSet.frmFormatSetForm f1 = new HY.PrintSet.frmFormatSetForm();
 f1.Show();

第一步 先新建一个容器,该容器决定打印的纸张大小,然后点击 工具栏的控件,按需添加控件到容器中.默认放在容器的左上角,叠在一起可能看不到,需要挪开上层控件,下面的才能看到.

目前只能通过右边字段属性进行调整,不能在预览界面拖拉控件.(下一版本 推出在预览界面直接拖拉控件,当前是0815版本) 

 

可拖拉控件的版本已经发布:如下链接

C# 可视化 拖拉控件 打印格式设计 模板设计 单据打印 标签打印 使用教程-CSDN博客

还可以添加表格,再添加列,就能看到效果

每一列相当于是 一个活动文本, 打印时可以用数据里面的绑定的数据 替换.

耐心添加完,就可以你这样子

打印模板设计好后,保存到本地一个文件,(后缀.fmt),大家有需要可以自己修改代码,比如保存模板到数据库,打印时按字段读取或者json文本保存读取. 这里我们用模板文件做演示.

当前保存到本地文件json格式保存, 打印时先读取模板的json内容, 读取代码可以参考如下:(demo里面也有)

 private string ReadFormat(string filename)
        {
            string json = "";           
                FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                StreamReader sr = new StreamReader(fs, Encoding.UTF8);
                string strLine = "";

                while ((strLine = sr.ReadLine()) != null)
                {
                    json += strLine;
                }
            
            return json;
        }

通过Newtonsoft.Json 反序列化一下,得到模板对象.

 JsonSerializerSettings jsset = new JsonSerializerSettings();
 jsset.TypeNameHandling = TypeNameHandling.All;
 PFormat fmat = JsonConvert.DeserializeObject<PFormat>(json, jsset);

最关键的是构建符合要求的打印数据:

目前支持2种方式: 

 #region 构建打印数据 方式一,Dic单头 + DataTable 单体
            Dictionary<string, string> po = new Dictionary<string, string>();
            po.Add("fbillno", "PO20240808001");
            po.Add("fsupplier", "中山市供应商有限公司");
            po.Add("fnote", "测试单头备注");
            po.Add("fdate", DateTime.Now.ToString("yyyy-MM-dd"));

            DataTable ens = new DataTable();
            ens.Columns.Add("fnumber");  //物料Code
            ens.Columns.Add("fname"); //物料名称
            ens.Columns.Add("funit");//单位
            ens.Columns.Add("fqty"); //数量
            ens.Columns.Add("fprice");//单价
            ens.Columns.Add("famount"); //金额
            ens.Columns.Add("fnote");//行备注

            DataRow dr = ens.NewRow();

            decimal qtys = 0;
            decimal Amount = 0;
            for (int r = 1; r < 10; r++)
            {
                dr = ens.Rows.Add();
                dr[0] = "M00" + r;
                dr[1] = "吸顶灯" + r;
                dr[2] = "PCS";
                dr[3] = "200";
                dr[4] = "36.00";
                dr[5] = "7200.00";
                dr[6] = "测试行备注" + r;

                qtys += 200;
                Amount += 7200;
            }

            //数据里面自己添加合计行,后续可以看下模板是否支持
            dr = ens.Rows.Add();
            dr[0] = "总合计:";
            dr[3] = qtys;
            dr[5] = Amount;
            #endregion 构建打印数据
#region 构建打印数据 方式二 Model方式
            PO po = new PO()
            {
                fbillno = "PO20240808001",
                fsupplier = "中山市供应商有限公司",
                fdate = DateTime.Now.ToString("yyyy-MM-dd"),
                fnote = "测试单头备注"
            };

            List<POEntry> ens = new List<POEntry>();
            for (int r = 1; r <= 10; r++)
            {
                POEntry en = new POEntry()
                {
                    fnumber = "M00" + r,
                    fname = "吸顶灯" + r,
                    funit = "PCS",
                    fqty = "100.00",
                    fprice = "35.00",
                    famount = "3500.00",
                    fnote = "测试行备注" + r
                };

                ens.Add(en);
            }

            //数据里面自己添加合计行,后续版本可以完善模板参数控制 合计行,包含页小计,最后页总合计.
            POEntry ensum = new POEntry()
            {
                fnumber = "总合计:",
                fname = "",
                funit = "",
                fqty = "1000.00",
                fprice = "",
                famount = "35000.00",
                fnote = ""
            };
            ens.Add(ensum);
            #endregion 构建打印数据
 public class PO
    {
        public string fbillno { get; set; }  //单号
        public string fsupplier { get; set; }  //供应商
        public string fdate { get; set; } //日期
        public string fnote { get; set; } //备注
        
    }

  public class POEntry
    {
        public string fnumber { get; set; }  //物料Code
        public string fname { get; set; }  //物料名称
        public string funit { get; set; }  //单位
        public string fqty { get; set; }  //数量
        public string fprice { get; set; }  //单价
        public string famount { get; set; }  //金额
        public string fnote { get; set; }  //行备注
    }

 public class Product
    {
        public string bcode { get; set; }
        public string fname { get; set; }
        public string model { get; set; }
        public string specs { get; set; }
    }

模板有了,数据有了,接下来就是调用打印服务,开始打印.

// Dic +DataTable 方式 调用方法
 PrintService ps = new PrintService(false, fmat, po, ens, false, 0, 0);
            //打印预览
            ps.PrintView();

            //打印需要打印机名称
            //ps.Print("打印机名称");


//Model 调用方法
 PrintServiceT<PO, POEntry> ps = new PrintServiceT<PO, POEntry>(false, fmat, po, ens, false, 0, 0);
            //打印预览
            ps.PrintView();

上面是单据类打印,如果是标签类打印,也是可以的,构建的数据 调用一次打印一张, 多张就循环调用,

后续这里也可以更改成传入List<>, 一次打完全部.

图片控件 需要将图片事先拷贝到软件的当前目录,当前设置是这样.其他目录打印时读取不到.

  #region 构建打印数据  标签类Did+DT方式
            Dictionary<string, string> pd = new Dictionary<string, string>();
            pd.Add("bcode", DateTime.Now.ToString("yyyyMMddHHmmss"));
            pd.Add("fname", "吸顶灯1");
            pd.Add("model", "86141-551");
            pd.Add("specs", "35*35*20");
            #endregion 构建打印数据


 #region 构建打印数据  Model方式
            Product pd = new Product()
            {
                bcode= DateTime.Now.ToString("yyyyMMddHHmmss"),
                fname= "吸顶灯1",
                model= "86141-551",
                specs= "35*35*20"
            };           
            #endregion 构建打印数据
 #region 调用打印
            PrintService ps = new PrintService(false, fmat, pd, null, false, 0, 0);
            //打印预览
            ps.PrintView();
            #endregion

//Model方式
  //第二个T ,用不到,随便一个Model都行
            PrintServiceT<Product, Product> ps = new PrintServiceT<Product, Product>(false, fmat, pd, null, false, 0, 0);            
            //打印预览
            ps.PrintView();

小插曲 : c# 获取本地打印机 :

//获取本地打印机列表 
public static List<String> GetLocalPrinters()
        {
            List<String> fPrinters = new List<String>();           
            foreach (String fPrinterName in PrinterSettings.InstalledPrinters)
            {
                if (!fPrinters.Contains(fPrinterName))
                {
                    fPrinters.Add(fPrinterName);
                }
            }
            return fPrinters;
        }


打印机列表可以绑定到程序界面的下拉控件让用户自己选择 . 或者设置默认.

程序在实际打印时,可能对纸张的方向以及坐标系,边距 等存在布局差异.更改坐标的原点进行调整.

 PrintServiceT<Product, Product> ps = new PrintServiceT<Product, Product>(false, fmat, pd, null, false, 0, 0);   最后两个参数就是用来调整坐标原点的.

这两个参数(可以负数) 进行调整,调整到合适的位置即可.

之前看到有些朋友用BarTender 设计格式,打印时调用组件和格式文件 实现打印, 或者用水晶报表来实现, 测试发现打印速度真的是慢如牛,特别是某些办公电脑卡的很,还不怎么灵活.

还是用纯.net自带的组件(设计模板界面用到dev,客户端实际打印是纯.net),那速度杠杠的.也没有什么授权认证,这省了多少资源,经过测试,老古董电脑照样打印快的飞起.

    下载地址:    (越靠后的链接版本越新,功能更完善稳定)

https://download.csdn.net/download/guo9long/89450604

https://download.csdn.net/download/guo9long/89623501

https://download.csdn.net/download/guo9long/89642363  (最新版)

debug目录里面包含所需的所有Dev的DLL 以及 Demo源码. 最新版也修复了之前版本存在的一些bug.

如有疑问, 可以发邮件给我咨询(82963620@qq.com) 或者回复本帖,我会不定时查看回复的.

真的很希望能有机会跟大家一起交流学习,希望开发从业者,不要做信息孤岛,尽量开放包容. 有交流进步才快.

一、应用场景与出发点 同一个系统中,为了解决不同的客户可能需要设计不同的单据打印模板,实现此方法可能是: 1、设计不同的自带RDLC报表文件,根据当前客户加载不同的报表并打印 2、GDI+绘图 和 打印组件 ,不同的客户创建不同的绘图XML格式模板内容 3、其他第三方组件 主要对比一下前两种方法,第一种方法不好之处在于,不灵活,开发者必须地每个客户制订一个报表,不推荐采用。第二种方法,修改对应的模板内容就可以了, 模板内容可以是Xml文件,也可以是存放在数据库中的Xml格式字符串。推荐采用这种方法。然后这种方法的也有一个棘手问题 :如何让用户快速、方便地设计打印模板,本示例就是为了解决这个问题。 二、实现思路与原理 功能概要:设计一个界面,支持用户自由添加 要打印的项,文本,直线,图片 等,并且可以方便改变打印项的 字体、颜色、粗细、位置,设计时支持效果预览。 技术要点:GDI+绘图、拖动控件、XML解析、自定义控件 三、相关类介绍 绘图工具类:DrawHelper 实现 xml格式模板打印项 之间进行互相转换,在目标画板中绘制 拖动工具类:WinHelper 实现控件的鼠标拖动,键盘移动 自定义控件:用于显示文字的文本框 TextBoxExt、用于显示直线的标签 LabelExt 主窗体代码:用于用户操作,添加,删除,编辑,打印项 详细介绍请参照我的博文:http://de.cel.blog.163.com/blog/static/51451236201472215450939/
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值