PDA

View Full Version : شروع کار با پرینتر



iranrose63
شنبه 28 بهمن 1385, 17:42 عصر
سلام
من تا حالا با پرینتر کار نکردم حالا می خوام یه جدول رو با پرینتر چاپ کنم میشه یه نفر بهم بگه از اول باید چیکار کنم اگه ممکنه با کد

ARA
یک شنبه 29 بهمن 1385, 09:30 صبح
من راهنماییت میکنم خودت جستجو کن پیدا میکنی

دنبال کار با کریستال ریپورت رو باش وقتی گزارش ها رو میبینی میتونی اونها رو چاپ کنی

iranrose63
یک شنبه 29 بهمن 1385, 12:19 عصر
نمی خوام با کریستال ریپورت کار کنم اصلا نمی خوام گزارش بگیرم می خوام از پرینتر استفاده کنم برای استفاده از fax .توی یکی از تایپک ها نوشته بودن برای Fax باید عملیات پرینت رو انجام داد می خوامک بدونم این عملیات چی هستند و یا اینکه اگه بخوام یه متن خاص رو پرینت بگیرم اون وقت چی؟

PC2st
سه شنبه 01 اسفند 1385, 19:36 عصر
پرینت گرفتن توی .نت بسادگی ایجاد تغییرات روی یک شئ از کلاس Graphics هست (بعدا خودتون خواهید دید) برای پرینت گرفتن، نمیخواد هیچ DialogBoxای رو ایجاد کنید، از بین کنترلهای موجود در .نت، کنترل PrintDialog و PageSetupDialog برای پرینت یک صفحه کافی هستند! خب... دست به کار شده و دو کنترل ذکر شده را به فرم خود اضافه نمائید. درحالت طراحی، وقتی که روی یکی از کنترلهای فوق را انتخاب کنید، یکسری از خاصیتهای آن نمایش داده می شود، ولی ما احتیاجی به این خاصیتها نداریم و خاصیتهای مورد نیاز ما، باید در هنگام کد نویسی مورد استفاده قرار گیرند...
مثلا، یک TextBox روی فرم خود دارید، که خاصیت Multiline آن نیز True است، حال میخواهیم متن داخل این TextBox (که نام آن textBox1 است) را پرینت بگیریم. البته با کمک کنترلهای موجود در .نت، یعنی PrintDialog و PageSetupDialog (!)
خوب حال یک Button را به فرم خود اضافه کرده و در رویداد Click آن، کدهائی که لازم است متن داخل textBox پرینت شود را می نویسیم.
برنامه طوری عمل میکند که پس از فشرده شدن Button، کادر محاوره ای Print Setup نمایش داده شده و پس از آن کادر محاوره ای Page Setup نمایش داده میشود و بعد از آن متن داخل textBox1 پرینت میشود.
پس با توجه به فرضیات بالا، فکر خود را روی نوشتن کد برای پرینت گرفتن، متمرکز میکنیم.

1. قبل از هر چیز، فضای نام System.Drawing.Printing را به برنامه خود اضافه میکنیم.
2. سپس باید خاصیت Document از کنترل printDialog1 نمونه سازی کنیم، بصورت زیر:


printDialog1.Document = new PrintDocument();


و باید خاصیت Document از کنترل pageSetupDialog1 را بصورت زیر:


pageSetupDialog1.Document = printDialog1.Document;


3. حال میخواهیم کادر محاوره ای Print Setup نمایش داده شود:


printDialog1.ShowDialog();


4. تنظیمات صورت گرفته در کادر محاوره ای در خاصیت PrinterSetting وجود دارد، پس این خاصیت را به خاصیت PrinterSetting از کنترل pageSetupDialog1 ارجاع میدهیم:


pageSetupDialog1.PrinterSettings = printDialog1.PrinterSettings;


5. حال نوبت آن رسیده که کادر محاوره ای Page Setup نمایش داده شود:


pageSetupDialog1.ShowDialog();


6. در واقع، هنگامی که یک صفحه پرینت میشود، رویداد PrintPage رخ میدهد. پس باید رویداد PrintPage از خاصیت Document از کنترل printDialog1 را بصورت زیر تنظیم کنیم:


printDialog1.Document.PrintPage += new PrintPageEventHandler(PrintItNow);

که در کد فوق، PrintItNow نام تابعی است که برای پرینت گرفتن باید اجرا شود.

7. حال متد Print را صدا میزنیم:


printDialog1.Document.Print();


پس از اینکه متد Print صدا زده شد، رویداد PrintPage (به مرحله 6 بروید) دست بکار شده و متد PrintItNow (به مرحله 6 بروید) را صدا میزند.
و هم اکنون نوبت ما رسیده است که مشخص کنیم یک صفحه چگونه باید پرینت شود!؟ و عملیات مورد نظرمان را در متد PrintItNow مینویسیم.

فعلا تا اینجا نوشته ام، بقیه اش را الان مینویسم... (تا اینجا را فکر کنم همه بلد بودند!)

PC2st
سه شنبه 01 اسفند 1385, 21:42 عصر
متد PrintItNow باید بصورت زیر تعریف (اعلان) شود تا بتواند در رویداد PrintPage (رجوع شود به مرحله 6 از پس قبلی!) قرار بگیرد:


void PrintItNow(object sender, PrintPageEventArgs e)
{
پیاده سازی عملیات برای چاپ، در اینجا نوشته میشود...
}


همانطور که به خاطر دارید، ممکن است کاربر در کادر محاوره ای Page Setup (رجوع شود به مرحله 5 از پست قبلی) مشخص کرده باشد که متن در کجای صفحه پرینت شود؟! پس در عملیات پرینت، باید تنظیمات صورت گرفته توسط کاربر در کادر محاوره ای Page Setup نیز مد نظر قرار گیرد.
متد PrintItNow شامل یک پارامتر از نوع PrintPageEventArgs است که نام آن e میباشد.
شئ e تمام تنظیمات صورت گرفته توسط کاربر را در خود ذخیره کرده است، پس برای عملیات چاپ (پرینت) حتما به آن احتیاج خواهیم داشت.
ابتدا بهتر است، روش کلی چاپ یک متن (یا سند یا ...) را توضیح دهم. در واقع شئ e دارای یک خاصیت بنام Graphics است.
نکته: توجه داشته باشید که خاصیت Graphics از نوع کلاس Graphics است (به این تشابه اسمی گیر ندهید!!!)، این کلاس که از نظر گرافیک کاران، نامی آشناست، برای ایجاد اشکال گرافیکی بکار میرود! بله... در واقع برای پرینت کردن یک صفحه، باید اشکال یا متن یا ... را بصورت گرافیک رسم کنیم تا بتواند پرینت شود!

خب حالا که تا حدودی آشنائی پیدا کردید، به سراغ نوشتن دستورات متد PrintItNow میرویم. طول صفحه (کاغذ) که توسط کاربر تعیین شده است، درون خاصیت e.MarginBounds.Height ذخیره شده است، فاصله متن از سمت چپ کاغذ در خاصیت e.MarginBounds.Left و فاصله متن از بالای کاغذ در خاصیت e.MarginBounds.Top ذخیره شده است.

همانطور که گفتم، تمام مطالبی را که میخواهیم در یک صفحه کاغذ چاپ کنیم، باید بصورت گرافیکی باشند (!) که توسط خاصیت Graphics (که از نوع کلاس Graphics است) این کار را انجام میدهیم. خاصیت e.Graphics دارای متدی بنام DrawString است که باعث میشود یک متن بصورت گرافیکی داخل آن کشیده شود (!) (یا ذخیره شود)، پس این نکته مهم است که بدانید هر آنچه که در شئ e.Graphics کشیده میشود در آخر سر توسط Printer چاپ خواهد شد...!
اما چگونه تمام خطوط نوشته شده در textBox1 را در شئ e.Graphics بکشیم؟ بعبارت دیگر، باید یک خط از textBox1 را خوانده و در شئ e.Graphics (و در مختصات معینی) رسم کنیم (بکشیم!) و سپس خط دوم از متن textBox1 را خوانده و در شئ e.Graphics (و در مختصات معینی) رسم کنیم تا الی آخر... بعبارت دیگر، بعد از افزودن یک خط متن در شئ e.Graphics باید متن بعدی در مختصات دیگری از شئ e.Graphics رسم شود تا با متن قبلی تداخل پیدا نکند! (مثل این می ماند که در برنامه ای مثل Paint یک متن بنویسید و دوباره در همان مختصات یک متن دیگر بنویسید! در اینصورت متنها با هم تداخل پیدا کرده اند و معلوم نیست که چه چیزی نوشته شده است!)
حال که این موضوع برای شما روشن شد، میخواهیم کاری کنیم که هر خط نوشته از textBox1 (همانطور که میدانید textBox1 میتواند چندین خط نوشته را در خود داشته باشد) را در شئ e.Graphics رسم کنیم بگونه ای که خطها (هر خط نوشته) با دیگری تداخل نداشته باشد. راستی، توجه داشته باشید که برای رسم متن در شئ e.Graphics، برای اینکه هر خط نوشته با دیگری تداخل پیدا نکند، باید یک فاصله مناسبی بین آن دو وجود داشته باشد و این فاصله به نوع فونت هر خط نوشته شده بستگی دارد! یعنی اینکه هر فونت یک ارتفاع مخصوص به خود را دارد، و با توجه به این ارتفاع، هر خط نوشته شده باید از خط دیگر، فاصله برقرار کند.
برای این منظور باید ارتفاع کاغذ را (e.MarginBounds.Height) بر ارتفاع فونتی که بکار برده ایم تقسیم کنیم، در اینصورت مشخص میشود که در یک صفحه کاغذ چند خط نوشته میتوانیم داشته باشیم در صورتی که خطوط نوشته با یکدیگر تداخل پیدا نکنند. پس اولین مورد: بدست آوردن حداکثر تعداد خطوطی است که میتوان در یک صفحه کاغذ نوشت.
مورد دوم، آن است که برای رسم شدن هر خط توی شئ e.Graphics میخواهیم از یک حلقه استفاده کنیم. برای اینکه بتوانیم از یک حلقه استفاده کنیم، باید پس از رسم یک خط نوشته در شئ e.Graphics مکان یا مختصاتی که خط بعد باید در شئ e.Graphics رسم شود نیز محاسبه گردد، برای این منظور از یک متغیر بنام sngVerticalPosition استفاده میکنیم که کار متغیر این است که مختصات یک خط نوشته ای را که بعدا در شئ e.Graphics باید رسم شود را در خود نگهداری میکند. بعبارت دیگر مختصات خط بعدی که در شئ e.Graphics رسم میگردد، در این متغیر ذخیره خواهد شد. یک متغیر دیگر لازم خواهد بود، و کار آن اینست که تعداد خطوطی که در شئ e.Graphics رسم شده اند را در خود ذخیره میکند، نام این متغیر را intLineCount می نامیم. خوب احتیاجی به متغیر دیگری نیست، پس نوبت آن میرسد که کد داخل متد PrintItNow را مشاهده کنیم و از روی این کد، به توضیح بپردازیم:


void PrintItNow(object sender, PrintPageEventArgs e)
{
float sngLinesPerPage = e.MarginBounds.Height / objPrintFont.GetHeight(e.Graphics);
float sngVerticalPosition = 0;
int intLineCount = 0;
while(intLineCount < sngLinesPerPage && ii < textBox1.Lines.Length)
{
sngVerticalPosition = e.MarginBounds.Top + (intLineCount * objPrintFont.GetHeight(e.Graphics));
e.Graphics.DrawString(textBox1.Lines[ii], objPrintFont, Brushes.Black, e.MarginBounds.Left, sngVerticalPosition, new StringFormat());
intLineCount++;
ii++;
}
if(ii < textBox1.Lines.Length) e.HasMorePages = true;
else e.HasMorePages = false;
}


توضیحات:
1. متغیر sngLinesPerPage که همون تعداد حداکثر خطوطی هست که میشه توی یک صفحه ی کاغذ جا داد. قبلا توی همین پست توضیحشو دادم. متغیر sngVerticalPosition هم مکان خط بعدی هست که باید توی شئ e.Graphics رسم بشه (و در آخر سر هم پرینت بشه!). قبلا یک توضیح کوچولو دادم. intLineCount هم شماره خطی هست که باید پرینت بشه، مثلا اگر مقدارش 3 باشه، معنیش اینه که تا حالا 3 تا خط پرینت شده (یا به عبارت صحیح تر، تا حالا 3 تا خط نوشته توی شئ e.Graphics رسم شده). در مورد متغیر intLineCount باید بگم که بعد از رسم هر خط توی شئ e.Graphics یک مقدار به این متغیر افزوده میشود و در صورتی که یک صفحه کاغذ (یا شئ e.Graphics) از تمام خطوط پر شود و خط دیگری نتواند در آن چاپ شود (یا به عبارت صحیح تر، در شئ e.Graphics رسم شود)، مقدار این متغیر برابر با sngLinesPerPage خواهد شد! (الان میگید که چرا برابر شده، باید بیشتر میشد! اما توجه داشته باشید که sngLinesPerPage از 1 شروع شده و intLineCount از صفر شروع میشود)
با while یک حلقه درست کرده و شرط حلقه را طوری تعیین میکنیم تا درصورتی که خط نوشته ای که میخواهیم پرینت کنیم (یا صحیحترش، بخواهیم توی شئ e.Graphics رسم کنیم) از حداکثر تعداد خطوط یک صفحه کاغذ بیشتر شد، خوب دیگر در اینصورت این خط نوشته توی یک کاغذ جا نمیشود، پس نمیتوان آنرا در این صفحه کاغذ پرینت کرد (یا بعبارت بهتر توی شئ e.Graphics رسمش کرد!) پس در اینصورت دستورات داخل حلقه اجرا نشده و خط نوشته مورد نظر هم پرینت نمیشود (توی شئ e.Graphics رسم نمیشود) اما راه حل آن بعدا توضیح داده میشود!! (فعلا ما فرض میکنیم که خط نوشته ای که میخواهیم توی صفحه کاغذ رسم کنیم (ببخشید پرینت کنیم...!) از حداکثر تعداد خطوطی که توی یک صفحه جا میشه، بیشتر نباشه... البته فعلا اینجور فرض میکنیم تا بقیه کد رو بنویسیم)

برای اینکه این نکته زیاد مبحث رو شلوغ نکنه، فقط این رو بخاطر داشته باشید که در شرط داخل حلقه while اگر intLineCount بزرگتر یا مساوی sngLinesPerPage بشه، یعنی اینکه صفحه کاغذ پر شده و نمیشه توی اون صفحه خط نوشته دیگری اضافه کرد و اگر ii < textBox1.Lines.Length ارزش نادرستی داشته باشه، یعنی اینکه تمام متن داخل textBox1 خونده شده.

2. در اولین دستور داخل حلقه while فاصله ی نسبت به بالای صفحه کاغذ از خطی (نوشته ای) که باید در شئ e.Graphics رسم بشه، مشخص میشه و در متغیر sngVerticalPosition قرار میگیره. (اگر خوب دقت کنید، اگر intLineCount صفر باشه، یعنی خط اول رو میخوایم رسم کنیم، پس مقدار sngVerticalPosition برابر با همون e.MarginBounds.Top میشه و اگر بخوایم خط دوم رو رسم کنیم یعنی intLineCount برابر 1 باشه، مقدار e.MarginBounds.Top با اندازه ارتفاع یک خط از نوشته جمع میشه، که در اینصورت sngVerticalPosition با یک فاصله مناسبی از بالای صفحه کاغذ، مکان خط دوم رو مشخص میکنه (بدون اینکه با خط اول تداخل پیدا کنه))

3. خب، همه اطلاعات از جمله sngVerticalPosition (فاصله خط از بالای صفحه کاغذ بصورتی که با خط قبلی قاطی نشه یا تداخل پیدا نکنه) و textBox1.Lines[ii] (نوشته موجود در خط شماره ii از texBox1 یا بعبارت دیگر، خط نوشته ای که باید توی شئ e.Graphics رسم بشه) و e.MarginBounds.Left (فاصله نوشته از سمت چپ صفحه کاغذ) و objPrintFont (فونت نوشته ای که میخواد رسم بشه) و Brushes.Black (نوع قلم مو!) همه مشخص هستند و میشه یک خط نوشته از textBox1 رو توسط متد DrawString در مکانی مشخص در شئ e.Graphics قرار داد (تا در اینصورت بشه چاپش کرد).

اما دو مورد رو یادم رفته بود بگم:
الف) ii یک متغیر از نوع int هست که درست در بدنه برنامه یعنی جائیکه خارج از متد PrintItNow قابل دسترسی باشه، قرار گرفته.
ب) objPrintFont فونتی هست که میخوایم باهاش متن رو چاپ کنیم و در اینجا Arial هست. در ضمن objPrintFont در کنار متغیر ii تعریف شده است تا در خارج از بدنه متد PrintItNow هم قابل دسترسی باشه.

خب، حالا که یک خط رسم شد، باید مشخص کنیم که یک خط نوشته رسم شده و نوبت به دومین خط هست، پس یک واحد به متغیر intLineCount اضافه میکنیم. در آخر سر هم باید یک واحد به مقدار متغیر ii اضافه کنیم، تا بوسیله این متغیر بشه به خط دوم از کنترل textBox1 دسترسی داشت، (یعنی textBox1.Lines[ii])

این حلقه تا جائی ادامه پیدا میکنه که یک صفحه (کاغذ) پر بشه یا اینکه متن نوشته شده در داخل textBox1 تمام شده باشه (به شرط داخل حلقه توجه کنید). در صورت پایان پذیرفته شدن حلقه، با یک دستور if ساده، چک میکنیم ببینیم که آیا هنوز متنی داخل textBox1 وجود داره که پرینت نشده یا نه؟ در صورتی که وجود داشت، مقدار خاصیت e.HasMorePages رو برابر true قرار میدهیم و در غیر اینصورت مقدارش رو false میکنیم (فکر کنم defaultاش همین باشه!)، پس از پایان یافتن دستورات داخل متد PrintItNow، اگر مقدار خاصیت e.HasMorePages برابر True باشه، توسط رویداد PrintPage یکبار دیگر متد PrintItNow اجرا میشه تا بقیه متن بتونه چاپ بشه... (این همون راه حل مشکلی بود که قبلا در موردش گفتم که اگر intLineCount برابر با sngLinesPerPage بشه، دیگه خط (نوشته) مورد نظر پرینت نمیشه! توی صفحه ای که پر باشه، پرینت نمیشه ولی توی یک صفحه خالی، بعدا پرینتش میکنیم مثل همین حالتی که الان گفته شد)


ایراد این کد: اگر طول (اندازه) یک خط از textBox1 بیشتر از عرض کاغذ باشه، ادامه متن داخل اون خط پرینت نمیشه!! (البته راه حلش به عهده خودتون :لبخندساده:)

یک توضیح کلی میدهم و یک مرور اساسی (!)، یک کنترل PageSetupDialog و PrintDialog به فرمتون اضافه میکنید و بعدش یک TextBox که خاصیت Multiline آن برابر True باشه هم اضافه میکنید، یک دکمه هم اضافه میکنید و توی رویداد Click دکمه (button1)، کدهای مورد نظر رو مینویسید (کدهائی که گفته شد).

در کل، اگر کدهای داخل Form1 (فرم خودتون) رو نگاه بیاندازید باید چیزی شبیه به زیر باشد:
(یادتون هست که گفتم متغیر ii و فونت objPrintFont رو باید در جائی تعریف کرد که خارج از متد PrintItNow هم قابل دسترسی باشه، میتونید از طریق کد زیر، منظورم رو بهتر متوجه شوید.)


public partial class Form1 : Form
{
private Font objPrintFont = new Font("Arial", 10);
private int ii = 0;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
printDialog1.Document = new PrintDocument();
pageSetupDialog1.Document = printDialog1.Document;
printDialog1.ShowDialog();
pageSetupDialog1.PrinterSettings = printDialog1.PrinterSettings;
pageSetupDialog1.ShowDialog();
printDialog1.Document.PrintPage += new PrintPageEventHandler(PrintItNow);
printDialog1.Document.Print();
}

void PrintItNow(object sender, PrintPageEventArgs e)
{
float sngLinesPerPage = e.MarginBounds.Height / objPrintFont.GetHeight(e.Graphics);
float sngVerticalPosition = 0;
int intLineCount = 0;
while(intLineCount < sngLinesPerPage && ii < textBox1.Lines.Length)
{
sngVerticalPosition = e.MarginBounds.Top + (intLineCount * objPrintFont.GetHeight(e.Graphics));
e.Graphics.DrawString(textBox1.Lines[ii], objPrintFont, Brushes.Black, e.MarginBounds.Left, sngVerticalPosition, new StringFormat());
intLineCount++;
ii++;
}
if(ii < textBox1.Lines.Length) e.HasMorePages = true;
else e.HasMorePages = false;
}
}


برای پیاده سازی متد PrintItNow، از کتاب الکترونیکی که توی همین سایت هست (گردآوری شده توسط سید محمد هاشمیان)، استفاده کردم.

samaneh_sh
یک شنبه 09 اسفند 1388, 16:48 عصر
متد PrintItNow باید بصورت زیر تعریف (اعلان) شود تا بتواند در رویداد PrintPage (رجوع شود به مرحله 6 از پس قبلی!) قرار بگیرد:


void PrintItNow(object sender, PrintPageEventArgs e)
{
پیاده سازی عملیات برای چاپ، در اینجا نوشته میشود...
}


همانطور که به خاطر دارید، ممکن است کاربر در کادر محاوره ای Page Setup (رجوع شود به مرحله 5 از پست قبلی) مشخص کرده باشد که متن در کجای صفحه پرینت شود؟! پس در عملیات پرینت، باید تنظیمات صورت گرفته توسط کاربر در کادر محاوره ای Page Setup نیز مد نظر قرار گیرد.
متد PrintItNow شامل یک پارامتر از نوع PrintPageEventArgs است که نام آن e میباشد.
شئ e تمام تنظیمات صورت گرفته توسط کاربر را در خود ذخیره کرده است، پس برای عملیات چاپ (پرینت) حتما به آن احتیاج خواهیم داشت.
ابتدا بهتر است، روش کلی چاپ یک متن (یا سند یا ...) را توضیح دهم. در واقع شئ e دارای یک خاصیت بنام Graphics است.
نکته: توجه داشته باشید که خاصیت Graphics از نوع کلاس Graphics است (به این تشابه اسمی گیر ندهید!!!)، این کلاس که از نظر گرافیک کاران، نامی آشناست، برای ایجاد اشکال گرافیکی بکار میرود! بله... در واقع برای پرینت کردن یک صفحه، باید اشکال یا متن یا ... را بصورت گرافیک رسم کنیم تا بتواند پرینت شود!

خب حالا که تا حدودی آشنائی پیدا کردید، به سراغ نوشتن دستورات متد PrintItNow میرویم. طول صفحه (کاغذ) که توسط کاربر تعیین شده است، درون خاصیت e.MarginBounds.Height ذخیره شده است، فاصله متن از سمت چپ کاغذ در خاصیت e.MarginBounds.Left و فاصله متن از بالای کاغذ در خاصیت e.MarginBounds.Top ذخیره شده است.

همانطور که گفتم، تمام مطالبی را که میخواهیم در یک صفحه کاغذ چاپ کنیم، باید بصورت گرافیکی باشند (!) که توسط خاصیت Graphics (که از نوع کلاس Graphics است) این کار را انجام میدهیم. خاصیت e.Graphics دارای متدی بنام DrawString است که باعث میشود یک متن بصورت گرافیکی داخل آن کشیده شود (!) (یا ذخیره شود)، پس این نکته مهم است که بدانید هر آنچه که در شئ e.Graphics کشیده میشود در آخر سر توسط Printer چاپ خواهد شد...!
اما چگونه تمام خطوط نوشته شده در textBox1 را در شئ e.Graphics بکشیم؟ بعبارت دیگر، باید یک خط از textBox1 را خوانده و در شئ e.Graphics (و در مختصات معینی) رسم کنیم (بکشیم!) و سپس خط دوم از متن textBox1 را خوانده و در شئ e.Graphics (و در مختصات معینی) رسم کنیم تا الی آخر... بعبارت دیگر، بعد از افزودن یک خط متن در شئ e.Graphics باید متن بعدی در مختصات دیگری از شئ e.Graphics رسم شود تا با متن قبلی تداخل پیدا نکند! (مثل این می ماند که در برنامه ای مثل Paint یک متن بنویسید و دوباره در همان مختصات یک متن دیگر بنویسید! در اینصورت متنها با هم تداخل پیدا کرده اند و معلوم نیست که چه چیزی نوشته شده است!)
حال که این موضوع برای شما روشن شد، میخواهیم کاری کنیم که هر خط نوشته از textBox1 (همانطور که میدانید textBox1 میتواند چندین خط نوشته را در خود داشته باشد) را در شئ e.Graphics رسم کنیم بگونه ای که خطها (هر خط نوشته) با دیگری تداخل نداشته باشد. راستی، توجه داشته باشید که برای رسم متن در شئ e.Graphics، برای اینکه هر خط نوشته با دیگری تداخل پیدا نکند، باید یک فاصله مناسبی بین آن دو وجود داشته باشد و این فاصله به نوع فونت هر خط نوشته شده بستگی دارد! یعنی اینکه هر فونت یک ارتفاع مخصوص به خود را دارد، و با توجه به این ارتفاع، هر خط نوشته شده باید از خط دیگر، فاصله برقرار کند.
برای این منظور باید ارتفاع کاغذ را (e.MarginBounds.Height) بر ارتفاع فونتی که بکار برده ایم تقسیم کنیم، در اینصورت مشخص میشود که در یک صفحه کاغذ چند خط نوشته میتوانیم داشته باشیم در صورتی که خطوط نوشته با یکدیگر تداخل پیدا نکنند. پس اولین مورد: بدست آوردن حداکثر تعداد خطوطی است که میتوان در یک صفحه کاغذ نوشت.
مورد دوم، آن است که برای رسم شدن هر خط توی شئ e.Graphics میخواهیم از یک حلقه استفاده کنیم. برای اینکه بتوانیم از یک حلقه استفاده کنیم، باید پس از رسم یک خط نوشته در شئ e.Graphics مکان یا مختصاتی که خط بعد باید در شئ e.Graphics رسم شود نیز محاسبه گردد، برای این منظور از یک متغیر بنام sngVerticalPosition استفاده میکنیم که کار متغیر این است که مختصات یک خط نوشته ای را که بعدا در شئ e.Graphics باید رسم شود را در خود نگهداری میکند. بعبارت دیگر مختصات خط بعدی که در شئ e.Graphics رسم میگردد، در این متغیر ذخیره خواهد شد. یک متغیر دیگر لازم خواهد بود، و کار آن اینست که تعداد خطوطی که در شئ e.Graphics رسم شده اند را در خود ذخیره میکند، نام این متغیر را intLineCount می نامیم. خوب احتیاجی به متغیر دیگری نیست، پس نوبت آن میرسد که کد داخل متد PrintItNow را مشاهده کنیم و از روی این کد، به توضیح بپردازیم:


void PrintItNow(object sender, PrintPageEventArgs e)
{
float sngLinesPerPage = e.MarginBounds.Height / objPrintFont.GetHeight(e.Graphics);
float sngVerticalPosition = 0;
int intLineCount = 0;
while(intLineCount < sngLinesPerPage && ii < textBox1.Lines.Length)
{
sngVerticalPosition = e.MarginBounds.Top + (intLineCount * objPrintFont.GetHeight(e.Graphics));
e.Graphics.DrawString(textBox1.Lines[ii], objPrintFont, Brushes.Black, e.MarginBounds.Left, sngVerticalPosition, new StringFormat());
intLineCount++;
ii++;
}
if(ii < textBox1.Lines.Length) e.HasMorePages = true;
else e.HasMorePages = false;
}


توضیحات:
1. متغیر sngLinesPerPage که همون تعداد حداکثر خطوطی هست که میشه توی یک صفحه ی کاغذ جا داد. قبلا توی همین پست توضیحشو دادم. متغیر sngVerticalPosition هم مکان خط بعدی هست که باید توی شئ e.Graphics رسم بشه (و در آخر سر هم پرینت بشه!). قبلا یک توضیح کوچولو دادم. intLineCount هم شماره خطی هست که باید پرینت بشه، مثلا اگر مقدارش 3 باشه، معنیش اینه که تا حالا 3 تا خط پرینت شده (یا به عبارت صحیح تر، تا حالا 3 تا خط نوشته توی شئ e.Graphics رسم شده). در مورد متغیر intLineCount باید بگم که بعد از رسم هر خط توی شئ e.Graphics یک مقدار به این متغیر افزوده میشود و در صورتی که یک صفحه کاغذ (یا شئ e.Graphics) از تمام خطوط پر شود و خط دیگری نتواند در آن چاپ شود (یا به عبارت صحیح تر، در شئ e.Graphics رسم شود)، مقدار این متغیر برابر با sngLinesPerPage خواهد شد! (الان میگید که چرا برابر شده، باید بیشتر میشد! اما توجه داشته باشید که sngLinesPerPage از 1 شروع شده و intLineCount از صفر شروع میشود)
با while یک حلقه درست کرده و شرط حلقه را طوری تعیین میکنیم تا درصورتی که خط نوشته ای که میخواهیم پرینت کنیم (یا صحیحترش، بخواهیم توی شئ e.Graphics رسم کنیم) از حداکثر تعداد خطوط یک صفحه کاغذ بیشتر شد، خوب دیگر در اینصورت این خط نوشته توی یک کاغذ جا نمیشود، پس نمیتوان آنرا در این صفحه کاغذ پرینت کرد (یا بعبارت بهتر توی شئ e.Graphics رسمش کرد!) پس در اینصورت دستورات داخل حلقه اجرا نشده و خط نوشته مورد نظر هم پرینت نمیشود (توی شئ e.Graphics رسم نمیشود) اما راه حل آن بعدا توضیح داده میشود!! (فعلا ما فرض میکنیم که خط نوشته ای که میخواهیم توی صفحه کاغذ رسم کنیم (ببخشید پرینت کنیم...!) از حداکثر تعداد خطوطی که توی یک صفحه جا میشه، بیشتر نباشه... البته فعلا اینجور فرض میکنیم تا بقیه کد رو بنویسیم)

برای اینکه این نکته زیاد مبحث رو شلوغ نکنه، فقط این رو بخاطر داشته باشید که در شرط داخل حلقه while اگر intLineCount بزرگتر یا مساوی sngLinesPerPage بشه، یعنی اینکه صفحه کاغذ پر شده و نمیشه توی اون صفحه خط نوشته دیگری اضافه کرد و اگر ii < textBox1.Lines.Length ارزش نادرستی داشته باشه، یعنی اینکه تمام متن داخل textBox1 خونده شده.

2. در اولین دستور داخل حلقه while فاصله ی نسبت به بالای صفحه کاغذ از خطی (نوشته ای) که باید در شئ e.Graphics رسم بشه، مشخص میشه و در متغیر sngVerticalPosition قرار میگیره. (اگر خوب دقت کنید، اگر intLineCount صفر باشه، یعنی خط اول رو میخوایم رسم کنیم، پس مقدار sngVerticalPosition برابر با همون e.MarginBounds.Top میشه و اگر بخوایم خط دوم رو رسم کنیم یعنی intLineCount برابر 1 باشه، مقدار e.MarginBounds.Top با اندازه ارتفاع یک خط از نوشته جمع میشه، که در اینصورت sngVerticalPosition با یک فاصله مناسبی از بالای صفحه کاغذ، مکان خط دوم رو مشخص میکنه (بدون اینکه با خط اول تداخل پیدا کنه))

3. خب، همه اطلاعات از جمله sngVerticalPosition (فاصله خط از بالای صفحه کاغذ بصورتی که با خط قبلی قاطی نشه یا تداخل پیدا نکنه) و textBox1.Lines[ii] (نوشته موجود در خط شماره ii از texBox1 یا بعبارت دیگر، خط نوشته ای که باید توی شئ e.Graphics رسم بشه) و e.MarginBounds.Left (فاصله نوشته از سمت چپ صفحه کاغذ) و objPrintFont (فونت نوشته ای که میخواد رسم بشه) و Brushes.Black (نوع قلم مو!) همه مشخص هستند و میشه یک خط نوشته از textBox1 رو توسط متد DrawString در مکانی مشخص در شئ e.Graphics قرار داد (تا در اینصورت بشه چاپش کرد).

اما دو مورد رو یادم رفته بود بگم:
الف) ii یک متغیر از نوع int هست که درست در بدنه برنامه یعنی جائیکه خارج از متد PrintItNow قابل دسترسی باشه، قرار گرفته.
ب) objPrintFont فونتی هست که میخوایم باهاش متن رو چاپ کنیم و در اینجا Arial هست. در ضمن objPrintFont در کنار متغیر ii تعریف شده است تا در خارج از بدنه متد PrintItNow هم قابل دسترسی باشه.

خب، حالا که یک خط رسم شد، باید مشخص کنیم که یک خط نوشته رسم شده و نوبت به دومین خط هست، پس یک واحد به متغیر intLineCount اضافه میکنیم. در آخر سر هم باید یک واحد به مقدار متغیر ii اضافه کنیم، تا بوسیله این متغیر بشه به خط دوم از کنترل textBox1 دسترسی داشت، (یعنی textBox1.Lines[ii])

این حلقه تا جائی ادامه پیدا میکنه که یک صفحه (کاغذ) پر بشه یا اینکه متن نوشته شده در داخل textBox1 تمام شده باشه (به شرط داخل حلقه توجه کنید). در صورت پایان پذیرفته شدن حلقه، با یک دستور if ساده، چک میکنیم ببینیم که آیا هنوز متنی داخل textBox1 وجود داره که پرینت نشده یا نه؟ در صورتی که وجود داشت، مقدار خاصیت e.HasMorePages رو برابر true قرار میدهیم و در غیر اینصورت مقدارش رو false میکنیم (فکر کنم defaultاش همین باشه!)، پس از پایان یافتن دستورات داخل متد PrintItNow، اگر مقدار خاصیت e.HasMorePages برابر True باشه، توسط رویداد PrintPage یکبار دیگر متد PrintItNow اجرا میشه تا بقیه متن بتونه چاپ بشه... (این همون راه حل مشکلی بود که قبلا در موردش گفتم که اگر intLineCount برابر با sngLinesPerPage بشه، دیگه خط (نوشته) مورد نظر پرینت نمیشه! توی صفحه ای که پر باشه، پرینت نمیشه ولی توی یک صفحه خالی، بعدا پرینتش میکنیم مثل همین حالتی که الان گفته شد)


ایراد این کد: اگر طول (اندازه) یک خط از textBox1 بیشتر از عرض کاغذ باشه، ادامه متن داخل اون خط پرینت نمیشه!! (البته راه حلش به عهده خودتون :لبخندساده:)

یک توضیح کلی میدهم و یک مرور اساسی (!)، یک کنترل PageSetupDialog و PrintDialog به فرمتون اضافه میکنید و بعدش یک TextBox که خاصیت Multiline آن برابر True باشه هم اضافه میکنید، یک دکمه هم اضافه میکنید و توی رویداد Click دکمه (button1)، کدهای مورد نظر رو مینویسید (کدهائی که گفته شد).

در کل، اگر کدهای داخل Form1 (فرم خودتون) رو نگاه بیاندازید باید چیزی شبیه به زیر باشد:
(یادتون هست که گفتم متغیر ii و فونت objPrintFont رو باید در جائی تعریف کرد که خارج از متد PrintItNow هم قابل دسترسی باشه، میتونید از طریق کد زیر، منظورم رو بهتر متوجه شوید.)


public partial class Form1 : Form
{
private Font objPrintFont = new Font("Arial", 10);
private int ii = 0;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
printDialog1.Document = new PrintDocument();
pageSetupDialog1.Document = printDialog1.Document;
printDialog1.ShowDialog();
pageSetupDialog1.PrinterSettings = printDialog1.PrinterSettings;
pageSetupDialog1.ShowDialog();
printDialog1.Document.PrintPage += new PrintPageEventHandler(PrintItNow);
printDialog1.Document.Print();
}

void PrintItNow(object sender, PrintPageEventArgs e)
{
float sngLinesPerPage = e.MarginBounds.Height / objPrintFont.GetHeight(e.Graphics);
float sngVerticalPosition = 0;
int intLineCount = 0;
while(intLineCount < sngLinesPerPage && ii < textBox1.Lines.Length)
{
sngVerticalPosition = e.MarginBounds.Top + (intLineCount * objPrintFont.GetHeight(e.Graphics));
e.Graphics.DrawString(textBox1.Lines[ii], objPrintFont, Brushes.Black, e.MarginBounds.Left, sngVerticalPosition, new StringFormat());
intLineCount++;
ii++;
}
if(ii < textBox1.Lines.Length) e.HasMorePages = true;
else e.HasMorePages = false;
}
}


برای پیاده سازی متد PrintItNow، از کتاب الکترونیکی که توی همین سایت هست (گردآوری شده توسط سید محمد هاشمیان)، استفاده کردم.


مرسي من ميخوام از محتويات ديتا گريدم پرينت بگيرم چيكار كنم؟:متفکر:

M.YasPro
یک شنبه 09 اسفند 1388, 17:31 عصر
سلام
به برنامه نویس خوش اومدین
ببینید این مثالها کارتون رو راه میندازه:
http://www.codeproject.com/KB/grid/PrintDataGridView.aspx
http://www.codeproject.com/KB/grid/GridDrawer.Net.aspx

samaneh_sh
دوشنبه 10 اسفند 1388, 15:51 عصر
سلام
به برنامه نویس خوش اومدین
ببینید این مثالها کارتون رو راه میندازه:
http://www.codeproject.com/KB/grid/PrintDataGridView.aspx
http://www.codeproject.com/KB/grid/GridDrawer.Net.aspx

مرسي
ولي تو اين برنامه ها موقعي كه پرينت رو ميزنم ميگه پرينتري نصب نيست در صورتي كه هم با پرينترهاي توي شبكه امتحان كردم هم با پرينتري كه مستقيما به سيستمم وصله.

توي برنامه اي كه بالا براي پرينت تكس باكس بود نميشه يه دستوري بدين كه به جاي تكس باكس محتويات ديتا گريد را پرينت بگيره.چون توي اين برنامه مشكل نصب پرينتر را نداشتم.