打印机池的设计与实现
打印机池的设计与实现
先说一个应用场景——中厨。
服务员先在点菜电脑上点菜,点好的菜单信息要在各出品部的“出品印机”上打印出来,各出品部的师傅再按照菜单来做菜。
不同的菜,要在不同的出品打印机上打印,有的菜要在多个出品打印机上打印。
整个中厨大概有十来个出品部门,有的出品部门有一台出品打印机,有的出口部门有几台。
笔者把这些打印机统称为“打印机池”。
// 单元功用:打印相关 // 单元设计: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.
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