近期涉及到一個需求要求提供簡單的打印功能,首先想到的winform的printDocument打印功能。之前有別的項目使用了這塊進行了簡單的封裝,但是感覺有問題。問題很簡單,之前的打印只能打印固定字體大小的內容。不好用。我不能自定義字體大小。
so,引出自己定義的需求。能不能自定義字體進行打印。而且簡單粗暴不使用第三方控件。
首先百度了下網上的代碼代碼很多,但大多有存在問題,問題如下:
1.不能換行,因爲使用RichTextBox之後固然是能夠使用自定義字體了,但是問題也是存在的那就是不會給你自動換行,而且即使控件自動換行了也沒用因爲頁面尺寸和控件尺寸並不一致。
2.打印會存在每一頁只打印一部分的問題
圍繞以上兩個問題,我找了很多代碼都不行,後來拼湊了下,並且找單位的大佬幫忙總算解決了,這裏記錄下:
首先拉出幾個控件:
PrintDialog ,PrintDocument,FontDialog,PageSetupDialog,以及3個button。
依次說明下這些控件的作用,PrintDialog用於打印之前的提示框,PrintDocument用於存放答應的文本信息,FontDialog設置字體信息,PageSetupDialog設置打印的頁面信息,三個button分別爲:
以上控件拖出後需要設置的屬性爲:
pageSetupDialog1的Document = prinntDocument1;
之後我們還需要richtextbox控件,以下爲打印的相關代碼:
在打印之前設置全局變量
// 需要打印的左上角位置
int top = 0;
// 一共已經打印了多少行
int count = 0;
private void buttonFont_Click(object sender, EventArgs e)
{
DialogResult dr = fontDialog1.ShowDialog(this);
if (dr == DialogResult.OK)
{
richTextBoxContent.Font = fontDialog1.Font;
richTextBoxContent.ForeColor = fontDialog1.Color;
}
}
此代碼目的是設置富文本的字體和顏色
private void buttonPages_Click(object sender, EventArgs e)
{
pageSetupDialog1.Document = printDocument1;
pageSetupDialog1.ShowDialog(this);
}
這段代碼爲設置打印頁面規制
private void buttonPrint_Click(object sender, EventArgs e)
{
printDialog1.Document = printDocument1;
DialogResult dr = printDialog1.ShowDialog(this);
if (dr == DialogResult.OK)
{
top = 0;
count = 0;
printDocument1.Print();
}
}
這段代碼設置了打印的初始值
top每次打印之前將打印的左上角置爲0
count計算已經打印了多少行。
// 該方法每打印一頁調用一次
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
// 設置需要打印的字體格式
Font f = richTextBoxContent.Font;
// 設置需要打印的字體顏色
Brush b = new SolidBrush(richTextBoxContent.ForeColor);
// 獲取每頁如果能打印完每頁的高度
int PageHeight = (int)Math.Ceiling(f.GetHeight(e.Graphics) * Math.Floor(e.MarginBounds.Height / f.GetHeight(e.Graphics)));
// 計算所有文本的打印區域大小
Size sf = Size.Round(e.Graphics.MeasureString(richTextBoxContent.Text, richTextBoxContent.Font, e.MarginBounds.Width));
e.Graphics.SetClip(e.MarginBounds);
// 設置當前頁的打印區域
Rectangle r = new Rectangle(new Point(e.MarginBounds.Left, e.MarginBounds.Location.Y - top), new Size(sf.Width, PageHeight*(count+1)));
e.Graphics.DrawString(richTextBoxContent.Text, richTextBoxContent.Font, b, r);
// 如果當前左上角的高度加上每頁的高度小於所有文本區域的高度說明當前頁沒有打印完
if (top + PageHeight < sf.Height)
{
// 頁數加一
count++;
// 左上角向下移動指定高度
top = top + PageHeight;
// 表明還有下一頁等待打印
e.HasMorePages = true;
}
}
以上方法可能不好理解這裏配圖說明下:
首先我們需要解決的是換行問題,這裏使用Rectangle,將文本填充到其中時,會自動換行。
其次解決分頁問題,這個問題我們先要理解打印的思路,在打印之前我們需要將所有的待打印信息放到一個待打印區間,正常的流程爲每頁打印MarginBounds範圍大小的內容,換句話說MarginBounds的大小決定了我們能打印多少。如果運氣不好就會發生上一頁一半字下一頁一半字的問題。
爲了解決這個問題我們採用了以下辦法進行打印:
這裏比較難理解的是
Rectangle r = new Rectangle(new Point(e.MarginBounds.Left, e.MarginBounds.Location.Y - top), new Size(sf.Width, PageHeight*(count+1)));
這個爲啥要-top,具體我也不清楚,但猜測是總打印區域是向上移動r的區域y軸必須爲負才能打印到下側區域但打印的區間必須放大到新的頁數否則將無法打印全部信息。
如果不對歡迎拍磚。