簡單介紹一下該功能所在的項目背景:C#語言編寫的WPF客戶端應用程序,在“結賬”模塊中,打印出的收款小票上需要顯示一個二維碼,服務生拿着小票去找顧客,顧客可以選擇現金、銀行卡等普通支付方式,也可以直接掃小票上的二維碼進行微信支付。用於打印小票的模板使用FastReport制作。結賬功能和收款單打印模板已經在使用,現在只需要在原有模板的基礎上進行修改。
首先,我們要明確一點:二維碼其實就是一張圖片。因此和打印條形碼不同,打印二維碼,只需要使用FastReport中的圖片控件就可以了。雙擊圖片控件后,有四種方式可以用於設置圖片的數據源,如下圖所示:
這些方法大家一看就知道怎么用,本項目中我們使用最下面這張大圖中的“數據列”方法,用FastReport數據源中的內容對圖片進行設置。
以本項目的結賬收款單打印模板為例,實現打印二維碼的步驟如下所示:
1、在程序中獲取需要打印的二維碼數據,並將數據源傳給打印模板
在該項目中,使用DataSet向打印模板傳遞數據源,使用Dictionary<string, string>向打印模板傳遞參數。傳遞的方法這里不再詳述。
為了實現打印二維碼這個功能,在傳遞給打印模板的數據源DataSet中添加了一張用於顯示二維碼的“微信數據”表,還添加了一個參數“微信二維碼”。“微信二維碼”參數中保存了這個二維碼的地址,若地址為空字符串,說明沒有微信二維碼,不需要打印。在程序端,調用下面的方法AddQRCodeForPrint為打印模板添加二維碼所需的數據。微信二維碼圖片的url(例:weixin://wxpay/payurl?pr=9BF4WY0)是線上的代碼生成的,這里不做介紹。
/// <summary> /// 向打印模板添加微信二維碼 /// </summary> /// <param name="dsPrint">數據源</param> /// <param name="objdict">參數</param> /// <param name="codeURL">微信二維碼圖片URL</param> public static void AddQRCodeForPrint(DataSet dsPrint, Dictionary<string, string> objdict, String codeURL) { try { //添加參數:微信二維碼圖片URL objdict.Add("微信二維碼", codeURL); //將微信二維碼寫入數據源 Bitmap bp = GetQrImage(codeURL); MemoryStream ms = new MemoryStream(); bp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); Byte[] code = ms.ToArray(); DataTable dt = new DataTable(); dt.Columns.Add("二維碼", typeof(Byte[])); DataRow dr = dt.NewRow(); dr["二維碼"] = code; dt.Rows.Add(dr); dt.TableName = "微信數據"; dsPrint.Tables.Add(dt); } catch { if (objdict != null && !objdict.ContainsKey("微信二維碼")) objdict.Add("微信二維碼", ""); } }
這個方法中,用於繪制二維碼圖形的方法GetQrImage如下所示:
/// <summary> /// 繪制二維碼 /// </summary> /// <param name="qrstr"></param> /// <param name="ImageWidth"></param> /// <param name="ImageHeight"></param> /// <param name="savelocal"></param> /// <returns>返回:二維碼</returns> private static Bitmap GetQrImage(String qrstr, int ImageWidth = 256, int ImageHeight = 256, bool savelocal = false) { try { Dictionary<EncodeHintType, object> ht = new Dictionary<EncodeHintType, object>(); ht.Add(EncodeHintType.MARGIN, 1); BitMatrix matrix = new MultiFormatWriter().encode(qrstr, BarcodeFormat.QR_CODE, ImageWidth, ImageHeight, ht); Bitmap bitmap = new BarcodeWriter().Write(matrix); //toBitmap(matrix); int[] rec = matrix.getEnclosingRectangle(); //二維碼所有的位置及大小 前兩位是位置 后兩位是大小 Bitmap argb32bp = new Bitmap(ImageWidth, ImageHeight); Graphics g = Graphics.FromImage(argb32bp); System.Drawing.Point[] point = new System.Drawing.Point[3]; point[0] = new System.Drawing.Point(5, 5); point[1] = new System.Drawing.Point(ImageWidth - 5, 5); point[2] = new System.Drawing.Point(5, ImageHeight - 5); g.FillRectangle(System.Drawing.Brushes.White, new System.Drawing.Rectangle(0, 0, ImageWidth, ImageHeight)); g.DrawImage(bitmap, point, new System.Drawing.Rectangle(rec[0], rec[1], rec[2], rec[3]), GraphicsUnit.Pixel); argb32bp.SetResolution(120, 120); if (savelocal) { String filename = DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".png"; bitmap.Save(String.Format(@"{0}\{1}", System.Windows.Forms.Application.StartupPath, filename), System.Drawing.Imaging.ImageFormat.Png); } bitmap.Dispose(); return argb32bp; } catch (Exception ex) { return null; } }
上述方法需要添加的引用:System.Drawing、System.IO,以及一個名為zxing的動態庫。(zxing的下載鏈接:http://pan.baidu.com/s/1c2G39IS)
2、在上面的方法中,程序端已經實現了向打印模板提供所需的數據,接下來需要修改打印模板,接收這些新添加的數據。
這里有一個簡單的方法,能夠為FastReport的數據源中添加一張表。那就是不直接雙擊打開打印模板,而是在打印模板的文件上右擊,選擇打開方式為“記事本”。在記事本中找到<Dictionary></Dictionary>這部分,在里面添加數據源和參數。以本項目的結賬收款單打印模板為例,添加了一張用於顯示二維碼的表“微信數據”,還添加了一個用於確定是否需要打印二維碼的參數“微信二維碼”。
因此,需要在<Dictionary></Dictionary>中添加如下內容:
<TableDataSource Name="微信數據" ReferenceName="Data.微信數據" DataType="System.Int32" Enabled="true"> <Column Name="二維碼" DataType="System.Byte[]"/> </TableDataSource> <Parameter Name="微信二維碼" DataType="System.String"/>
保存並關閉打印模板的記事本文件。再雙擊打開打印模板,此時在FastReport的右側邊欄中,能看到數據源里已經多了一個“微信數據”表,如下圖所示:
這里的“二維碼”就是步驟1中代碼里繪制出的二維碼圖形,檢查這個字段的屬性,需要確保它的DataType是Byte[]型的。並且在下面的“參數”列表中,也能看到多了一個“微信二維碼”參數。
為打印模板新建一個數據區,用於打印二維碼。點擊“報表”——“設置報表欄”菜單,在打開的窗體中點擊“添加“按鈕,添加”數據區”。將新添加的數據區重命名為Data_PictureCode。主要步驟如下圖所示:
為什么要新建一個數據區,而不是在原來的數據區里添加二維碼呢?因為當不需要打印二維碼,也就是“微信二維碼”參數為空時,我們可以直接把這個數據區隱藏,從而不用在打印出的小票上顯示出空白的一大片來,也為客戶節省紙張。
在新添加的數據區中插入圖片,如下圖所示:
雙擊圖片,在圖片編輯器的“數據列”中,選擇“微信數據”表中的“二維碼”。如下圖所示:
最后,設置是否需要顯示二維碼所在的這個數據區。選擇一個一定會打印的數據區,在這個數據區的BeforePrint事件中進行控制。首先為所選的數據區添加事件,在FastReport的右側邊欄中,進入到數據區的事件列表(點擊那個閃電形狀的按鈕),在BeforePrint事件后面的編輯框內雙擊,即可為該數據區添加一個BeforePrint事件。該事件中的代碼在打印數據區前執行,如下圖所示:
在所選數據區的BeforePrint事件中添加如下代碼,控制是否顯示二維碼所在的那個數據區:
private void Data10_BeforePrint(object sender, EventArgs e) { //獲取微信二維碼url string codeURL=(String)Report.GetParameterValue("微信二維碼"); //若微信二維碼url為空,則不顯示二維碼數據區 if(codeURL=="") { Data_PictureCode.Visible=false; } }
代碼和打印模板設計界面的切換按鈕,在FastReport的左下角,見下圖所示:
在進行了上述全部修改后,本項目的結賬收款單上就能夠打印出用於微信支付的二維碼了。