打印机池的设计与实现
打印机池的设计与实现
先说一个应用场景——中厨。
服务员先在点菜电脑上点菜,点好的菜单信息要在各出品部的“出品印机”上打印出来,各出品部的师傅再按照菜单来做菜。
不同的菜,要在不同的出品打印机上打印,有的菜要在多个出品打印机上打印。
整个中厨大概有十来个出品部门,有的出品部门有一台出品打印机,有的出口部门有几台。
笔者把这些打印机统称为“打印机池”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | // 单元功用:打印相关 // 单元设计:cxg // 设计日期:2014-05-12 // 每一台打印机都有自己的任务队列和处理任务队列的线程 // 快餐只有一个出品部门 unit untPrintTask; interface uses System . SysUtils, System . Classes, Datasnap . DBClient, frxclass, System . Generics . Collections; type TBillContent = record // 小票内容 machineNo: string ; // POS机号 skyName: string ; // 收款员姓名 saleNo: string ; // 小票号 saleTime: TDateTime; // 销售时间 amount: Currency ; // 应收 pay: Currency ; // 支付 change: Currency ; // 找零 prnData: OleVariant; // 小票明细:商品名称、单价、数量、金额。。。。。。 deskNo: string ; // 台号 payType: string ; // 支付方式 end ; type TPrinterInfo = record // 打印机信息 prnNo: Integer ; // 印机编号 prnName: string ; // 印机名称 prnType: string ; // 结账、厨打 prnWidth: Integer ; // 50mm\76mm\80mm remark: string ; // 备注 prnModel: string ; // 打印模版 end ; type TOneTimePrint = record // 一次打印 printerInfo: TPrinterInfo; // 打印机信息 billContent: TBillContent; // 小票内容 end ; type TPrintTaskThread = class (TThread) // 打印任务线程 private FPrintQueue: TQueue<TOneTimePrint>; // 打印队列 protected procedure Execute; override; public constructor Create; overload; destructor Destroy; override; property PrintQueue: TQueue<TOneTimePrint> read FPrintQueue write FPrintQueue; end ; var g_PrintTasks: TDictionary< string , TPrintTaskThread>; // <打印机名字, TPrintTask> implementation { TPrintTask } uses untFastReport, UntSysConst; constructor TPrintTaskThread . Create; begin Create( False ); FreeOnTerminate := False ; // 创建打印队列 FPrintQueue := TQueue<TOneTimePrint>.Create; end ; destructor TPrintTaskThread . Destroy; begin // 释放打印队列 FreeAndNil(FPrintQueue); inherited ; end ; procedure TPrintTaskThread . Execute; var OneTimePrint: TOneTimePrint; dm: TdmFastReport; c: TfrxComponent; begin while not Self . Terminated do begin if Assigned(FPrintQueue) and (FPrintQueue . Count > 0 ) then begin // 从任务队列中提取一个任务 OneTimePrint := FPrintQueue . Dequeue; dm := TdmFastReport . Create( nil ); try try // 小票明细数据 dm . cds . Data := OneTimePrint . billContent . prnData; // 小票模板 dm . report . LoadFromFile(OneTimePrint . printerInfo . prnModel); // 哪个打印机 dm . report . PrintOptions . Printer := OneTimePrint . printerInfo . prnName; // 变量赋值 c:=dm . report . FindObject( 'mmShopName' ); if c<> nil then TfrxMemoView(c).Memo . Text := UserInfo . ShopName; c := dm . report . FindObject( 'mmMachineNo' ); if c<> nil then TfrxMemoView(c).Memo . Text := OneTimePrint . billContent . machineNo; c:=dm . report . FindObject( 'mmSKY' ); if c<> nil then TfrxMemoView(c).Memo . Text := OneTimePrint . billContent . skyName; c:= dm . report . FindObject( 'mmBillNo' ); if c<> nil then TfrxMemoView(c).Memo . Text := OneTimePrint . billContent . saleNo; c:=dm . report . FindObject( 'mmSaleTime' ); if c<> nil then TfrxMemoView(c).Memo . Text := FormatDateTime( 'yyyy-mm-dd hh:nn' ,OneTimePrint . billContent . saleTime); c:= dm . report . FindObject( 'mmDeskNo' ); if c<> nil then TfrxMemoView(c).Memo . Text := OneTimePrint . billContent . deskNo; // 台号 c:= dm . report . FindObject( 'mmPayType' ); if c<> nil then TfrxMemoView(c).Memo . Text := OneTimePrint . billContent . payType; c:= dm . report . FindObject( 'mmAmount' ); if c<> nil then TfrxMemoView(c).Memo . Text := FormatCurr( '0.00' , OneTimePrint . billContent . amount); c:=dm . report . FindObject( 'mmPay' ); if c<> nil then TfrxMemoView(c).Memo . Text := FormatCurr( '0.00' , OneTimePrint . billContent . pay); c:= dm . report . FindObject( 'mmGiveChange' ); if c<> nil then TfrxMemoView(c).Memo . Text := FormatCurr( '0.00' , OneTimePrint . billContent . change); // 开始打印 dm . report . PrepareReport(); dm . report . Print; except // 打印失败,重新加入任务队列 Self . FPrintQueue . Enqueue(OneTimePrint); end ; finally FreeAndNil(dm); end ; end ; // 线程休眠 Sleep( 1000 ); end ; end ; end . |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | procedure TfrmSettleAccount . PrintBill; var OneTimePrint: TOneTimePrint; p: TPrintTaskThread; begin // 结帐打印机和出品打印机都打印相同的模板 frmPos . cdsPrinter . First; while not frmPos . cdsPrinter . Eof do begin // 打印机信息 OneTimePrint . printerInfo . prnNo := frmPos . cdsPrinter . FieldByName( 'prnNo' ) .AsInteger; OneTimePrint . printerInfo . prnName := frmPos . cdsPrinter . FieldByName ( 'prnName' ).Text; OneTimePrint . printerInfo . prnType := frmPos . cdsPrinter . FieldByName ( 'prnType' ).Text; OneTimePrint . printerInfo . prnWidth := UserInfo . PaperWidth; OneTimePrint . printerInfo . remark := frmPos . cdsPrinter . FieldByName ( 'remark' ).Text; // 不同宽度的打印机加载不同的打印模板 case OneTimePrint . printerInfo . prnWidth of 58 : OneTimePrint . printerInfo . prnModel := ExtractFilePath(Application . ExeName) + 'report\pos58.fr3' ; 76 : OneTimePrint . printerInfo . prnModel := ExtractFilePath(Application . ExeName) + 'report\pos76.fr3' ; 80 : OneTimePrint . printerInfo . prnModel := ExtractFilePath(Application . ExeName) + 'report\pos80.fr3' ; end ; // 小票内容 OneTimePrint . billContent . machineNo := UserInfo . MachineId; OneTimePrint . billContent . skyName := UserInfo . UserName; OneTimePrint . billContent . saleNo := UserInfo . saleNo; OneTimePrint . billContent . saleTime := Now; OneTimePrint . billContent . amount := self . Total . totalAmount; OneTimePrint . billContent . pay := self . Total . totalAmount; OneTimePrint . billContent . Change := StrToCurr(edtChange . Text); OneTimePrint . billContent . prnData := frmPos . cdsSaleD . Data; OneTimePrint . billContent . payType := frmPos . cdsSaleM . FieldByName ( 'payType' ).Text; OneTimePrint . billContent . deskNo := frmPos . edtDeskNo . Text; // 加入打印队列 if g_PrintTasks . TryGetValue(frmPos . cdsPrinter . FieldByName( 'prnName' ).Text, p) then begin p . PrintQueue . Enqueue(OneTimePrint); end ; frmPos . cdsPrinter . Next; end ; end ; |
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/9929640.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?