winfrom 打印表格 字符串的封裝實(shí)現(xiàn)代碼 附源碼下載
所以對(duì)于應(yīng)用層用著還不是很方便。最近做一個(gè)項(xiàng)目順便就封裝了一個(gè)調(diào)用默認(rèn)打印機(jī)的類。雖說有幾個(gè)小bug,但對(duì)于目前來說,已經(jīng)滿足需求了。以后不夠了在來升級(jí)吧。
1,關(guān)于打印上下左右邊距和紙張的高寬。以往都把這些寫死到代碼里面。既然是調(diào)用默認(rèn)打印機(jī),打印機(jī)的型號(hào)自然有差異。所以我就把這些配置放到app.config里面。但又怕每次打印都加載config影響效率。故此設(shè)計(jì)了個(gè)PrintPaper類。里面所有屬性都是靜態(tài)的。還有一個(gè)靜態(tài)的構(gòu)造方法。這樣只有在程序開始運(yùn)行加載一次config。之后就直接從內(nèi)存讀取了。
PrintPaper類
/*CreateBy:Bonker,Date:20121115*/
/// <summary>
/// 從配置文件讀取紙張的大小,與邊框的距離
/// </summary>
public class PrintPaper
{
/// <summary>
/// 距離上邊界的距離
/// </summary>
public static int MarginTop { set; get; }
/// <summary>
/// 距離左邊界的距離
/// </summary>
public static int MarginLeft { set; get; }
/// <summary>
/// 距離右邊界的距離
/// </summary>
public static int MarginRight { set; get; }
/// <summary>
/// 距離下邊界的距離
/// </summary>
public static int MarginBottom { set; get; }
/// <summary>
/// 紙張的寬度
/// </summary>
public static int Width { set; get; }
/// <summary>
/// 紙張的高度
/// </summary>
public static int Height { set; get; }
/// <summary>
/// 異常情況
/// </summary>
public static string Error { set; get; }
//對(duì)于靜態(tài)屬性和構(gòu)造方法。當(dāng)?shù)谝淮问褂迷擃惖臅r(shí)候,先初始化靜態(tài)屬性,然后調(diào)用靜態(tài)類。
//故此配置文件只加載一次,以后調(diào)用都會(huì)從內(nèi)存中讀取。
//此中寫法的好處,一次加載,以后不再加載,速度快。弊端:程序運(yùn)行過程中,改變了config配置。則需重新運(yùn)行程序。配置才加載生效。
static PrintPaper()
{
//先給異常賦空值,當(dāng)異常不為空時(shí)。說明配置數(shù)據(jù)有問題,或者程序有異常
Error = null;
string marginTop = BonkerConfig.GetConfig("marginTop");
string marginBottom = BonkerConfig.GetConfig("marginBottom");
string marginLeft = BonkerConfig.GetConfig("marginLeft");
string marginRight = BonkerConfig.GetConfig("marginRight");
//margin的值可以為負(fù)值,但是width只能為正,
//marginTop,等值默認(rèn)已經(jīng)為0,如果margin不為空,取值復(fù)制給margin
try
{
if (!string.IsNullOrWhiteSpace(marginTop))
{
MarginTop = int.Parse(marginTop);
}
if (!string.IsNullOrWhiteSpace(marginTop))
{
MarginBottom = int.Parse(marginBottom);
}
if (!string.IsNullOrWhiteSpace(marginTop))
{
MarginLeft = int.Parse(marginLeft);
}
if (!string.IsNullOrWhiteSpace(marginTop))
{
MarginRight = int.Parse(marginRight);
}
}
catch (Exception ex)
{
//如果有異常繼續(xù)
Error = ex.Message;
return;
}
//判斷紙張寬度
try
{
//如果paperWidth配置不為正,則為PrintCore類打印的時(shí)候,則去默認(rèn)值
string width = BonkerConfig.GetConfig("paperWidth");
string height = BonkerConfig.GetConfig("paperWidth");
if (!string.IsNullOrWhiteSpace(width))
{
Width = int.Parse(width);
}
if (!string.IsNullOrWhiteSpace(height))
{
Height = int.Parse(width);
}
}
catch (Exception ex)
{
//如果有異常繼續(xù)
Error = ex.Message;
return;
}
}
}
app.config的內(nèi)容
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!--******************************連接字符串設(shè)置************************************-->
<add key="DBConnectionStr" value=" "/>
<!--********************************打印邊界設(shè)置**********************************-->
<!--打印紙的距四個(gè)邊界的距離,為空這表示默認(rèn)為0,可以為負(fù)值-->
<!--與上邊界距離-->
<add key="marginTop" value=""/>
<!--與上邊界距離-->
<add key="marginBottom" value=""/>
<!--與上邊界距離-->
<add key="marginLeft" value=""/>
<!--與上邊界距離-->
<add key="marginRight" value=""/>
<!--********************************打印紙大小設(shè)置**********************************-->
<!--打印紙張的大小,為空表示取默認(rèn)值,不可以為負(fù)值 -->
<!--紙張的寬度-->
<add key="paperWidth" value=""/>
<!--紙張的高度-->
<add key="paperHeight" value=""/>
<!--*******************************************************************************-->
</appSettings>
</configuration>
2,打印表格,翻閱了很多msdn大神的代碼。大致有點(diǎn)眉目。打印表格是在一點(diǎn)打印完字體后,然后不改變X,Y坐標(biāo)繼續(xù)打印個(gè)矩形。所以就有表格了。這樣的表格理論上表格的四個(gè)邊框有點(diǎn)細(xì)。里面的小格子有點(diǎn)粗。但打印出來后基本就沒差別了。
打印表格是自適應(yīng)表格里面的文字最大的寬度。但如果表格里面確實(shí)列很少,沒列的最大寬度又很小。打印完真整個(gè)表格沒有頁面的紙張寬。那會(huì)自動(dòng)拉寬每一列的寬度。
打印的核心類PrintCore
/*CreateBy:Bonker,Date:20121115*/
/// <summary>
/// 打印類,負(fù)責(zé)打印表格,普通行等。
/// </summary>
public class PrintCore
{
/// <summary>
/// 打印基礎(chǔ)封裝類PrintDocument
/// </summary>
public PrintDocument printDoc { set; get; }
/// <summary>
/// 當(dāng)前打印的x坐標(biāo)
/// </summary>
public float currentX { set; get; }
/// <summary>
/// 當(dāng)前打印的Y坐標(biāo)
/// </summary>
public float currentY { set; get; }
/// <summary>
/// 默認(rèn)打印字體
/// </summary>
public Font defaultFont { set; get; }
/// <summary>
/// 打印的畫刷,默認(rèn)黑色加粗
/// </summary>
public Brush defaultBrush { set; get; }
/// <summary>
/// 是否居中打印,默認(rèn)為false
/// </summary>
public bool isCenter { set; get; }
/// <summary>
/// 異常錯(cuò)誤
/// </summary>
public string Error { set; get; }
private Graphics graphic { set; get; }
/// 構(gòu)造函數(shù)
/// </summary>
/// <param name="_printDoc">打印基礎(chǔ)類</param>
/// <param name="_currentX">打印開始的x坐標(biāo),默認(rèn)為0</param>
/// <param name="_currentY">打印開始的y坐標(biāo),默認(rèn)為0</param>
public PrintCore(PrintDocument _printDoc, Graphics _graphics, Font _defaultFont, float _currentX = 0, float _currentY = 0)
{
this.printDoc = _printDoc;
this.currentX = _currentX;
this.currentY = _currentY;
this.defaultFont = _defaultFont;
this.graphic = _graphics;
this.defaultBrush = new SolidBrush(Color.Black); //默認(rèn)加粗黑色
this.isCenter = false;
//讀取配置文件
printDocConfig(_printDoc);
Error = PrintPaper.Error;
}
private void printDocConfig(PrintDocument _printDoc)
{
_printDoc.DefaultPageSettings.Margins = new Margins(PrintPaper.MarginLeft, PrintPaper.MarginRight, PrintPaper.MarginTop, PrintPaper.MarginBottom);
//當(dāng)paper配置的寬度和高度都大于0時(shí),才配置。否則忽略
if (PrintPaper.Width > 0 && PrintPaper.Height > 0)
{
_printDoc.DefaultPageSettings.PaperSize = new PaperSize("", PrintPaper.Width, PrintPaper.Height);
}
}
/// <summary>
/// 打印字符串,系統(tǒng)可以總動(dòng)判斷換行打印。
/// </summary>
/// <param name="prnStr">打印的字符串</param>
/// <param name="isPrintLine">打印完成后,是否換行,默認(rèn)為true</param>
public void printString(string prnStr, bool isPrintLine = true)
{
//打印字符串,根據(jù)字符串長(zhǎng)度,和紙張寬度,高度等自動(dòng)換行
SizeF measure = graphic.MeasureString(prnStr, defaultFont);
//如果x坐標(biāo)不為0,或者打印的一行寬度大于紙張的寬度,則居中打印是沒用的。不考慮打印
if (!isCenter || currentX != 0 || printDoc.DefaultPageSettings.PaperSize.Width < measure.Width)
{
//計(jì)算打印這么多字要多少行
int rows = (int)Math.Ceiling(measure.Width / (printDoc.DefaultPageSettings.PaperSize.Width - currentX));
//根據(jù)行,算出要打印的邊界矩形框
graphic.DrawString(prnStr, defaultFont, defaultBrush, new Rectangle((int)currentX, (int)currentY, (int)Math.Ceiling((printDoc.DefaultPageSettings.PaperSize.Width - currentX)), (int)Math.Ceiling((measure.Height * rows))));
if (isPrintLine)//如果換行
{
currentY = currentY + measure.Height * rows;
currentX = 0;
}
else
{
currentY = currentY + measure.Height * (rows - 1);
currentX = (measure.Width % (printDoc.DefaultPageSettings.PaperSize.Width - currentX)) + currentX;
}
}
else
{
//居中打印一行
//計(jì)算打印前的留白寬度
float blank = (printDoc.DefaultPageSettings.PaperSize.Width - measure.Width) / 2.0f;
currentX = currentX + blank;
graphic.DrawString(prnStr, defaultFont, defaultBrush, currentX, currentY);
if (isPrintLine)//如果換行
{
currentX = 0;
currentY = currentY + measure.Height;
}
else
{
currentX = currentX + measure.Width;
}
}
}
/// <summary>
/// 打印表格,自適應(yīng)沒列的寬度
/// </summary>
/// <param name="prnDgv"></param>
/// <param name="isPrintLine"></param>
public void printDataGridView(DataGridView prnDgv, Font titleFont, Brush titleBrush, Color titleBackGroup, bool isPrintLine = true)
{
if (prnDgv == null)
{
return;
}
prnDgv.AllowUserToAddRows = false;
//記錄每一列的寬度
int[] columnWidths = new int[prnDgv.ColumnCount];
//******************取每列的最大寬度***********************
//先計(jì)算表頭的寬度
for (int i = 0; i < prnDgv.ColumnCount; i++)
{
string celValue = prnDgv.Columns[i].HeaderText;
SizeF measure = graphic.MeasureString(celValue, titleFont);
columnWidths[i] = (int)Math.Ceiling(measure.Width);//把打印表頭所占的寬度 先放到columnWidths里面
}
//計(jì)算表中數(shù)據(jù)打印的最大寬度
for (int i = 0; i < prnDgv.Rows.Count; i++)
{
for (int j = 0; j < prnDgv.ColumnCount; j++)
{
string celValue = prnDgv[j, i].Value.ToString();
SizeF measure = graphic.MeasureString(celValue, defaultFont);
if (columnWidths[j] < measure.Width)//如果寬度小于打印寬度,則把長(zhǎng)的打印寬度賦值給列寬
{
columnWidths[j] = (int)Math.Ceiling(measure.Width);
}
}
}
//如果表格的寬度小于紙張的寬度,表格沒列的寬度加大
int allColumsWidth = 0;
for (int i = 0; i < prnDgv.ColumnCount; i++)
{
allColumsWidth += columnWidths[i];//把打印表頭所占的寬度 先放到columnWidths里面
}
if (allColumsWidth + prnDgv.ColumnCount < PrintPaper.Width)
{
int columnAddWidth = (PrintPaper.Width - allColumsWidth - prnDgv.ColumnCount) / prnDgv.ColumnCount;
for (int i = 0; i < prnDgv.ColumnCount; i++)
{
columnWidths[i] += columnAddWidth;
}
}
//*************************************************************
currentX = 0;
int titleHeight = (int)Math.Ceiling(graphic.MeasureString("1e{(汗", titleFont).Height);
//打印表頭
for (int i = 0; i < prnDgv.ColumnCount; i++)
{
string celValue = prnDgv.Columns[i].HeaderText;
//打印背景
graphic.FillRectangle(new SolidBrush(titleBackGroup), new Rectangle((int)currentX, (int)currentY, columnWidths[i], titleHeight));
//打印內(nèi)容
graphic.DrawString(celValue, titleFont, titleBrush, currentX, currentY);
//打印表格邊框
graphic.DrawRectangle(new Pen(titleBrush), new Rectangle((int)currentX, (int)currentY, columnWidths[i], titleHeight));
currentX = currentX + columnWidths[i];
}
currentX = 0;
currentY = currentY + titleHeight;
int contentHeight = (int)Math.Ceiling(graphic.MeasureString("1e{(汗", defaultFont).Height);
//打印內(nèi)容
for (int i = 0; i < prnDgv.Rows.Count; i++)
{
for (int j = 0; j < prnDgv.ColumnCount; j++)
{
string celValue = prnDgv[j, i].Value.ToString();//打印內(nèi)容
graphic.DrawString(celValue, defaultFont, defaultBrush, currentX, currentY);//打印表格邊框
graphic.DrawRectangle(new Pen(defaultBrush), new Rectangle((int)currentX, (int)currentY, columnWidths[j], contentHeight));
currentX = currentX + columnWidths[j];
}
currentX = 0;
currentY = currentY + contentHeight;
}
}
}
調(diào)用示例代碼
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
PrintCore print = new PrintCore(printDocument1, e.Graphics, new Font("宋體", 14));
if (print.Error != null)
{
e.Cancel = true;
MessageBox.Show(print.Error);
return;
}
print.isCenter = true;
print.defaultFont = new Font("宋體", 16);
print.printString("定積分落實(shí)到減肥了減肥了圣誕節(jié)死減", true);
print.isCenter = false;
print.defaultFont = new Font("宋體", 14);
print.printString("111定積分落實(shí)到減定積分落實(shí)到減肥了圣誕節(jié)死定了減肥了束帶結(jié)發(fā)連鎖店減肥了哦定積分落實(shí)到減肥了圣誕節(jié)死定了減肥了束帶結(jié)發(fā)連鎖店減肥了哦肥了圣誕節(jié)死定了減肥了束帶結(jié)發(fā)連鎖店減肥了哦");
print.printDataGridView(dataGridView1,new Font("宋體", 18),Brushes.Black,DefaultBackColor);
}
總結(jié):以上打印有兩個(gè)小問題沒有處理。一個(gè)是關(guān)于分頁,一個(gè)是當(dāng)表格的寬度過長(zhǎng),超過了頁面的寬度,沒有進(jìn)行換行處理。
另附上源碼 winfrom_mrdyj_jb51net
作者:Bonker
- WinFrom中l(wèi)abel背景透明的實(shí)現(xiàn)方法
- .NET WinFrom中給文本框添加拖放事件的代碼
- C# winfrom 模擬ftp文件管理實(shí)現(xiàn)代碼
- winfrom 在業(yè)務(wù)層實(shí)現(xiàn)事務(wù)控制的小例子
- C#之WinForm跨線程訪問控件實(shí)例
- c#中多線程訪問winform控件的若干問題小結(jié)
- 深入分析C#中WinForm控件之Dock順序調(diào)整的詳解
- C#中讓控件全屏顯示的實(shí)現(xiàn)代碼(WinForm)
- WinForm實(shí)現(xiàn)按名稱遞歸查找控件的方法
- WinForm自定義控件應(yīng)用實(shí)例
- 簡(jiǎn)介Winform中創(chuàng)建用戶控件
- WinForm 自動(dòng)完成控件實(shí)例代碼簡(jiǎn)析
- C#的winform控件命名規(guī)范
相關(guān)文章
C#實(shí)現(xiàn)壓縮和解壓縮的方法示例【Gzip和Zip方式】
這篇文章主要介紹了C#實(shí)現(xiàn)壓縮和解壓縮的方法,結(jié)合具體實(shí)例形式分析了Gzip和Zip兩種壓縮操作實(shí)現(xiàn)方法,需要的朋友可以參考下2017-06-06C# 通過同步和異步實(shí)現(xiàn)優(yōu)化做早餐的時(shí)間
本文以一個(gè)簡(jiǎn)單的小例子—如何做一頓早餐及如何優(yōu)化做早餐的時(shí)間來讓大家具體了解一下同步和異步方法的區(qū)別,需要的朋友可以參考一下2021-12-12C#判斷頁面中的多個(gè)文本框輸入值是否有重復(fù)的實(shí)現(xiàn)方法
這篇文章主要介紹了C#判斷頁面中的多個(gè)文本框輸入值是否有重復(fù)的實(shí)現(xiàn)方法,是一個(gè)非常簡(jiǎn)單實(shí)用的技巧,需要的朋友可以參考下2014-10-10C#獲取系統(tǒng)當(dāng)前日期和時(shí)間的示例詳解
這篇文章主要為大家詳細(xì)介紹了C#如何使用DateTime的Now靜態(tài)屬性動(dòng)態(tài)獲得系統(tǒng)當(dāng)前日期和時(shí)間,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下2024-01-01C#發(fā)送Get、Post請(qǐng)求(帶參數(shù))
本文主要介紹了C#發(fā)送Get、Post請(qǐng)求,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09利用C#實(shí)現(xiàn)獲取當(dāng)前設(shè)備硬件信息
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)獲取當(dāng)前設(shè)備硬件信息的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-03-03