POS 应用程序开发 - 小票打印

21

我正在为一家餐厅/酒吧构建POS应用程序。
设计部分已完成,过去一个月我一直在编写代码。
除了现在需要打印之外,一切都运行良好。我必须将其打印到连接到运行软件的计算机上的收据打印机上,稍后我将尝试在远程打印机(如厨房打印机)上打印。

我已经搜索了相关的帮助,但发现这些类型的打印机的标准是使用POS for .NET。问题是,这已经有点过时了,或者至少没有更新过几年了。现在有很多关于如何使用此库的问题,大多数答案都不太容易理解。因此,如果有人可以给出逐步打印简单短语(“Hello World”)到收据打印机的帮助,我将非常感激。
我正在使用运行在 Windows 7 64位系统上的 Visual Studio 2012,并使用C#编写WPF。


1
现在打印已经成为操作系统的事情了...不再是你必须编写自己的驱动程序的日子了(天哪,我想念它)。 - lboshuizen
1
这是什么意思?我不太理解你的评论。POS应用程序每天都在开发,因此显然有打印小票机的方法。 - Nuno
你已经决定使用哪种打印机了吗?因为很可能你将使用制造商的API或软件驱动程序。 - Mark Hall
这是我使用Star打印机打印的解决方案,你可以尝试搜索Epson打印机的帮助程序。https://dev59.com/A07Sa4cB1Zd3GeqP5KSk - adopilot
感谢您的回答,我考虑使用爱普生打印机,因为在我的国家它们是最常见的。 - Nuno
1
我想指出一个显而易见但常常被忽视的事实:制造商通常希望您使用他们的产品,因此如果您联系他们,他们通常会很乐意为您指引正确的方向。他们不会帮助您解决任何特定应用程序的问题,但通常可以为您提供所需信息,以便打印出“Hello World!”。 - Brandon Moore
4个回答

25

我知道这是一篇旧文章,但对于那些仍在寻找解决方案的人,我可以告诉你我是怎么做的。

在花费了很多时间研究OPOS和POS for .Net之后,我最终放弃了它们,改用内置的System.Drawing.Printing库。 OPOS和POS for .Net难以使用,并且最终效果不如内置库好。

我正在使用Epson TM-T20II收据打印机。

以下是对我有用的一些代码。

public static void PrintReceiptForTransaction()
{
    PrintDocument recordDoc = new PrintDocument();

    recordDoc.DocumentName = "Customer Receipt";
    recordDoc.PrintPage += new PrintPageEventHandler(ReceiptPrinter.PrintReceiptPage); // function below
    recordDoc.PrintController = new StandardPrintController(); // hides status dialog popup
                                                                // Comment if debugging 
    PrinterSettings ps = new PrinterSettings();
    ps.PrinterName = "EPSON TM-T20II Receipt";
    recordDoc.PrinterSettings = ps;
    recordDoc.Print();
    // --------------------------------------

    // Uncomment if debugging - shows dialog instead
    //PrintPreviewDialog printPrvDlg = new PrintPreviewDialog();
    //printPrvDlg.Document = recordDoc;
    //printPrvDlg.Width = 1200;
    //printPrvDlg.Height = 800;
    //printPrvDlg.ShowDialog();
    // --------------------------------------

    recordDoc.Dispose();
}

private static void PrintReceiptPage(object sender, PrintPageEventArgs e)
{
    float x = 10;
    float y = 5;
    float width = 270.0F; // max width I found through trial and error
    float height = 0F;

    Font drawFontArial12Bold = new Font("Arial", 12, FontStyle.Bold);
    Font drawFontArial10Regular = new Font("Arial", 10, FontStyle.Regular);
    SolidBrush drawBrush = new SolidBrush(Color.Black);

    // Set format of string.
    StringFormat drawFormatCenter = new StringFormat();
    drawFormatCenter.Alignment = StringAlignment.Center;
    StringFormat drawFormatLeft = new StringFormat();
    drawFormatLeft.Alignment = StringAlignment.Near;
    StringFormat drawFormatRight = new StringFormat();
    drawFormatRight.Alignment = StringAlignment.Far;

    // Draw string to screen.
    string text = "Company Name";
    e.Graphics.DrawString(text, drawFontArial12Bold, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
    y += e.Graphics.MeasureString(text, drawFontArial12Bold).Height;

    text = "Address";
    e.Graphics.DrawString(text, drawFontArial10Regular, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
    y += e.Graphics.MeasureString(text, drawFontArial10Regular).Height;

    // ... and so on
}

希望这能帮助某人跳过所有使用自定义驱动程序的麻烦。 :)


这段代码是否保证能够持续打印作业,而不是一页一页地打印? - Bon
哎呀,很抱歉我完全不记得遇到过那个问题 - 它似乎总是在打印最后一行后截断。很抱歉我不能提供更多帮助。 - Tim S
你从哪里获取你的ReceiptPrinter.PrintReceiptPage对象/函数? - Articulous
所以这个类的名称叫做“ReceiptPrinter”,而“ReceiptPrinter.PrintReceiptPage”只是上面代码中静态方法的一个句柄。你可能可以不用类名引用PrintReceiptPage,但这是我已经有一段时间没有使用的旧代码,所以我无法尝试。祝你好运! - Tim S
@TimS 我该如何将动态数据传递给 PrintReceiptPage 事件处理程序? - NuWin
显示剩余3条评论

13

使用 .NET 的 POS 可能是一个不错的选择。

大多数收据打印机制造商将提供 OPOS 服务对象。

此 MSDN 文章所述,POS for .NET 兼容于 OPOS v1.8 服务对象。

OPOS / UPOS(POS for .NET 基于其之上)是我认为设计较差的 API (由设备制造商而非应用程序开发人员设计),但这是目前最好的选择。

我没有具体的示例,但基础与 OPOS 相同 - 您需要打开、声明、启用设备,然后才能调用其方法(例如 Print)。您可以尝试查看 OPOS 示例,例如 此 PosPrinter1 示例,它可能与 POS for .NET 非常相似。

此博客 提供了有关设置 POS for .NET 的一些信息,可能会有所帮助。

更新

以下是针对 OPOS 打印机的 VB Hello World。您首先需要创建一个打印机,并将其添加到注册表中,其中需要逻辑设备名称 = LDN。我相信 Epson ADK 包括一个实用程序来在注册表中添加打印机。此实用程序还可以对打印机进行健康检查以检查其是否已正确安装。完成这些步骤后,很容易将下面的代码调整为 POS for .NET。

OPOSPOSPrinter.Open "MyPrinter"    ' LDN of your printer   
OPOSPOSPrinter.Claim 500           ' Timeout   
OPOSPOSPrinter.DeviceEnabled = True  

'- Print   
OPOSPOSPrinter.PrintNormal 2, "Hello world"  

'- Close the printer   
If OPOSPOSPrinter.Claimed then   
   OPOSPOSPrinter.Release   
End If  
OPOSPOSPrinter.Close  

好的,我下载了Epson OPOS ADK,通用控制对象和安装了POS for .NET,但是这些网站都没有提供一个使用库的直接明确方法。我知道我必须添加对Microsoft.PointOfService的引用,但接下来该怎么做?那我该如何处理OPOS通用控制对象呢?当每个人开始使用他们不熟悉的编程语言进行编码时,第一件学习的事情就是编写“Hello World”应用程序。我认为这是OPOS或POS for .NET文档中应该提及的内容。有什么帮助吗? - Nuno
在.NET 4中,如果您想要使用C#的动态特性(以便在4中运行POS for .NET),可能会遇到问题,并且您可以使用爱普生或其他知名打印机进行限制。大多数廉价打印机无法与POS for .NET一起使用!因此,我放弃了POS.NET。 - GorillaApe
@Parhs,你还记得你最终使用的是什么而不是POS.NET吗? - ingredient_15939

5

.NET打印

在.NET下进行打印并不太困难。您可以看一下这里 和在msdn上了解更多。

如果要打印到POS / 收据打印机,与打印到其他打印机相同,只要它是Windows打印机、网络或其他类型的打印机。如果您使用串口打印机,可能会更加困难,因为您很可能需要使用制造商特定的API,幸运的是,现今大多数优秀的POS打印机都得到操作系统的全面支持。

首先,您需要在项目中添加对System.Printing dll的引用。

然后,打印就像这样简单:

private void PrintText(string text)
{
    var printDlg = new PrintDialog();
    var doc = new FlowDocument(new Paragraph(new Run(text)));
    doc.PagePadding = new Thickness(10);

    printDlg.PrintDocument((doc as IDocumentPaginatorSource).DocumentPaginator, "Print Caption");
}

To use..

PrintText("Hello World");

你也可以利用PrintDialog.PrintVisual,并使用xaml模板定义你的文档。
打印设置可以使用PrintDialog属性进行设置。
获取想要打印的打印机。
private PrintQueue FindPrinter(string printerName)
{
    var printers = new PrintServer().GetPrintQueues();
    foreach (var printer in printers)
    {
        if (printer.FullName == printerName)
        {
            return printer;
        }
    }
    return LocalPrintServer.GetDefaultPrintQueue();
}

当打印到收据打印机时,需要注意一些事项,您需要考虑格式。更具体地说,您需要考虑页面宽度以及每行可以容纳多少个字符;对我来说,这需要大量的试错,尤其是在不同字体大小的情况下。

在大多数情况下,您实际上不需要担心分页问题,打印机将在完成文档后自动切割纸张。


2
将打印到POS / 收据打印机与打印到任何其他打印机相同。一个专业的POS应用程序将希望监视来自收据打印机的状态信号(例如,纸张不足,盖子打开,纸张卡住),这些信号在使用Windows打印机驱动程序时不可用。 - Joe
速度方面怎么样?因为在这种情况下我使用的是Windows驱动程序(对吧?),打印时间会更长,对吧?如果我想打印整张桌子的收据,你认为打印机需要多长时间才能完成? - Nuno
@Joe,那你有什么建议呢? - Nuno
@Joe 你说的很理想,但大多数人并不关心这些功能,如果你不提供硬件,那是不现实的。 - GorillaApe
实际上,我想使用这种方法。我会尝试一下并告诉你 @nmaait - swdev

1

如果您想以打印机的全速打印,您可能需要使用特定于打印机的转义代码,并生成“原始”输出。

请查看迈克尔·布恩对this SO question的回答,特别是更新部分。


不要像链接问题中建议的那样使用通用打印机。专业的POS应用程序将希望监视收据打印机的状态信号(例如,纸张不足,盖子打开,纸张卡住),这些信号在使用通用打印机时是不可用的。 - Joe
@Joe,请帮忙!当我说“专业的POS应用程序将想要监控收据打印机的状态信号(例如,纸张不足,盖子打开,纸张卡住)”时,人们会嘲笑我并认为我是个白痴。很少有应用程序/人关心这些问题。我也将提出一个问题。 - GorillaApe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接