餐饮软件打印队列之实现

餐饮软件,特别是中厨的出品打印机数量非常多,整个酒店可能有N个出品部门,一个出品部门可能有N台出品打印机。

打印队列的功用:

(1)打印不掉单,打印任务缓存于队列中,如果某个打印任务失败,则重新加入队列;

(2)各台打印机都是并行作业,一台打印机发生故障不会影响其它打印机的正常工作。

打印队列实现方法之一:

为每一台打印机建立自己专属的打印任务队列和打印任务处理线程。

// 单元功用:处理打印任务的线程
// 单元设计:cxg
// 设计日期:2014-05-12

unit untPrintTask;

interface

uses
System.SysUtils, System.Classes, Vcl.Dialogs,
Datasnap.DBClient, Vcl.Forms, frxclass, System.Variants,
System.Generics.Collections;

type
TBillContent = record // 小票内容
machineNo: string; // POS机号
skyName: string; // 收款员姓名
saleNo: string; // 小票号
saleTime: TDateTime; // 销售时间
amount: Currency; // 应收
pay: Currency; // 支付
change: Currency; // 找零
prnData: OleVariant; // 商品名称、单价、数量、金额
end;

type
TPrinterInfo = record // 打印机信息
prnNo: Integer; // 印机编号
prnName: string; // 印机名称
prnType: string; // 结账、厨打
prnWidth: Integer; // 50mm76mm80mm
remark: string; // 备注
prnModel: string; // 打印模版
end;

type
TOneTimePrint = record // 一次打印
printerInfo: TPrinterInfo; // 打印机信息
billContent: TBillContent; // 小票内容
end;

type
TPrintTask = 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
PrintTaskArray: array of TPrintTask;

implementation

{ TPrintTask }

uses untFastReport;

constructor TPrintTask.Create;
begin
Create(False);
FPrintQueue := TQueue<TOneTimePrint>.Create;
end;

destructor TPrintTask.Destroy;
begin
FreeAndNil(FPrintQueue);
inherited;
end;

procedure TPrintTask.Execute;
var
OneTimePrint: TOneTimePrint;
dm: TdmFastReport;
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;
TfrxMemoView(dm.report.FindObject('mmMachineNo')).Memo.Text :=
OneTimePrint.billContent.machineNo;
TfrxMemoView(dm.report.FindObject('mmSKY')).Memo.Text :=
OneTimePrint.billContent.skyName;
TfrxMemoView(dm.report.FindObject('mmBillNo')).Memo.Text :=
OneTimePrint.billContent.saleNo;
TfrxMemoView(dm.report.FindObject('mmSaleTime')).Memo.Text :=
FormatDateTime('yyyy-mm-dd hh:nn',
OneTimePrint.billContent.saleTime);
TfrxMemoView(dm.report.FindObject('mmAmount')).Memo.Text :=
FormatCurr('0.00', OneTimePrint.billContent.amount);
TfrxMemoView(dm.report.FindObject('mmPay')).Memo.Text :=
FormatCurr('0.00', OneTimePrint.billContent.pay);
TfrxMemoView(dm.report.FindObject('mmGiveChange')).Memo.Text :=
FormatCurr('0.00', OneTimePrint.billContent.change);
// dm.report.ShowReport();
dm.report.PrepareReport();
dm.report.Print;
except
Self.FPrintQueue.Enqueue(OneTimePrint);
end;
finally
FreeAndNil(dm);
end;
end;
Sleep(1000);
end;
end;

end.

// 为每一台打印机创建队列和线程

{$IFDEF pool}
SetLength(PrintTaskArray, cdsPrinter.RecordCount);
for i := 0 to High(PrintTaskArray) do
begin
PrintTaskArray[i] := TPrintTask.Create;
PrintTaskArray[i].FreeOnTerminate := False;
end;

{$ENDIF}

// 释放所有的线程

{$IFDEF pool}
for i := 0 to High(PrintTaskArray) do
begin
PrintTaskArray[i].Terminate;
PrintTaskArray[i].WaitFor;
FreeAndNil(PrintTaskArray[i]);
end;

// 打印小票

procedure TfrmSettleAccount.PrintBill;
var
OneTimePrint: TOneTimePrint;
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 := frmPos.cdsPrinter.FieldByName('prnWidth').AsInteger;
OneTimePrint.printerInfo.remark := frmPos.cdsPrinter.FieldByName('remark').Text;
case OneTimePrint.printerInfo.prnWidth of
58: OneTimePrint.printerInfo.prnModel := ExtractFilePath(Application.ExeName) + 'reportpos58.fr3';
76: OneTimePrint.printerInfo.prnModel := ExtractFilePath(Application.ExeName) + 'reportpos76.fr3';
80: OneTimePrint.printerInfo.prnModel := ExtractFilePath(Application.ExeName) + 'reportpos80.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 := StrToCurrDef(edtCash.Text, 0);
OneTimePrint.billContent.change := StrToCurrDef(edtChange.Text, 0);
OneTimePrint.billContent.prnData := frmPos.cdsSaleD.Data;
// 加入打印队列
PrintTaskArray[frmPos.cdsPrinter.RecNo - 1].PrintQueue.Enqueue(OneTimePrint);
frmPos.cdsPrinter.Next;
end;
end;


{$ENDIF}

原文地址:https://www.cnblogs.com/hnxxcxg/p/3727033.html