I see many reports of this and I have tried a few things that are suggested but none work in my case. I think in my case I do not understand how the PrintPreviewDialog works so I am not connecting the document with the print button correctly.
I create a document in a richtextbox that is many A4 print pages long. I then use the following from a button in the Winform. The second function is event where the pages are made. (Some of the code below comes from others so thanks to them)
private void btn_SaveBitmap_Click(object sender, EventArgs e)
{
PrintDocument printDocument1 = new PrintDocument();
PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog();
printPreviewDialog1.Icon = new Icon("..\\..\\braille.ico");
printDocument1.PrintPage += PrintDocument_PrintPage;
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
//comes in here for every page it needs to make
int charactersOnPage = 0;
int linesPerPage = 0;
Font drawFont = new Font(rchtxtbx_braille.Font.ToString(), rchtxtbx_braille.Font.Size);
// Sets the value of charactersOnPage to the number of characters
// of stringToPrint that will fit within the bounds of the page.
e.Graphics.MeasureString(rchtxtbx_braille.Text, drawFont,
e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out linesPerPage);
// Draws the string within the bounds of the page
e.Graphics.DrawString(rchtxtbx_braille.Text, drawFont, Brushes.Black,
e.MarginBounds, StringFormat.GenericTypographic);
// Remove the portion of the string that has been printed.
rchtxtbx_braille.Text = rchtxtbx_braille.Text.Substring(charactersOnPage);
// Check to see if more pages are to be printed.
e.HasMorePages = (rchtxtbx_braille.Text.Length > 0);
}
This all looks good in the preview dialog and I can see I have many pages and they all look correct. In the preview in top left I press the print icon and then I see although the laptop has access to 7 printers all I get here is PDF printer. If I click to run and I get a page printed but it is blank.
So two issues
Why do I not see all 7 printers in the preview dialog?
How do you make the dialog print the actual page rather than ignore it a print blank?
Any ideas please on how to make it print the correct pages. Thanks.
After much head scratching it dawned on me that can work it just needs to put the text back into the richtextbox. I thought once it made the preview that it printed the preview. Apparently not the preview only gives it the figures for the print and not the image to print. It gets the print image from the original source. So now at the end when the Richtextbox is empty I say there are no more pages and then replace the text. It is now working.
private StringBuilder sb = new StringBuilder(); //needed to replace text into richtextbox after preview
private void btn_SaveBitmap_Click(object sender, EventArgs e)
{
PrintDocument printDocument1 = new PrintDocument();
PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog();
printPreviewDialog1.Icon = new Icon("..\\..\\braille.ico");
sb.Append(rchtxtbx_braille.Text);
printDocument1.PrintPage += PrintDocument_PrintPage;
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
printDocument1.Dispose();
printPreviewDialog1.Dispose();
}
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
//comes in here for every page it needs to make
int charactersOnPage = 0;
int linesPerPage = 0;
Font drawFont = new Font(rchtxtbx_braille.Font.ToString(), rchtxtbx_braille.Font.Size);
// Sets the value of charactersOnPage to the number of characters
// of stringToPrint that will fit within the bounds of the page.
e.Graphics.MeasureString(rchtxtbx_braille.Text, drawFont,
e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out linesPerPage);
// Draws the string within the bounds of the page
e.Graphics.DrawString(rchtxtbx_braille.Text, drawFont, Brushes.Black,
e.MarginBounds, StringFormat.GenericTypographic);
// Remove the portion of the string that has been printed.
rchtxtbx_braille.Text = rchtxtbx_braille.Text.Substring(charactersOnPage);
// Check to see if more pages are to be printed.
// replace the text when the window is empty so we have something to print
// otherwise we print a blank document.
if (rchtxtbx_braille.Text.Length > 0)
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false; //say no more pages
rchtxtbx_braille.Text = sb.ToString(); //replace text
}
}
Related
I have problems with printing typing Arabic letters in C# using printdocument.
Here's my code:
PrintDocument pd;
PaperSize ps;
void pd_Factor(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
Font vazir = new Font("Vazir Code FD", 12, FontStyle.Regular);
SolidBrush sb = new SolidBrush(Color.Black);
string a = "سلام";
g.DrawString(a, vazir, sb, 200, 330);
}
private void btnDone_Click(object sender, EventArgs e)
{
PrintDocument pd = new PrintDocument();
PaperSize ps = new PaperSize("Factor", 723, 1024);
pd.PrintPage += new PrintPageEventHandler(pd_Factor);
pd.PrintController = new StandardPrintController();
pd.DefaultPageSettings.Margins.Left = 0;
pd.DefaultPageSettings.Margins.Right = 0;
pd.DefaultPageSettings.Margins.Top = 0;
pd.DefaultPageSettings.Margins.Bottom = 0;
pd.DefaultPageSettings.PaperSize = ps;
printDialog1.Document = pd;
if (printDialog1.ShowDialog() == DialogResult.OK)
{
try
{
pd.Print();
}
catch (Exception)
{
}
}
}
Sadly, the above code prints this way:
By the way, I tried
StringFormat format = new StringFormat();
format.FormatFlags = StringFormatFlags.DirectionRightToLeft;
g.DrawString(a, vazir, sb, 200, 330, format);
It just make the position of anchor going from up-left to up-right this way:
So, I thought with myself, I should reverse it:
string a = "سلام";
string b = "";
for (int i = a.Length - 1; i > -1; i--)
{
b += Convert.ToString(a[i]);
}
And it made the text looks like this:
It still looks wrong but it goes better.
However I tried adding characters from left-to-right using character map.
And my code changed to:
string a = "ﻡﺎﻠﺳ";
And it prints correctly:
By the way, I have an input and I don't know what is the text going to be; so, I can't use character map for that.
Also it looks impossible or hard to code to replace the text; at least I need these characters:
My question is: How to print correctly?
Note: The font I'm using is this; However I tried using Tahoma too, but the problem still persists.
Seems strange, But magically Problem Solved!
I tried using another app to test called "Print2Pdf" and the text prints correctly, Maybe it's a bug of Microsoft XPS writer/reader that cannot print/read Arabic/Persian letters.
*Sorry for not providing link to Print2Pdf as I couldn't find the original website; If someone knows the original please add link; Thanks
I am trying to print some strings using Graphicss.DrawString(). I have set margins to the printdocument but does not start from the origin of the page. I have set margins to (0,0,0,0) but somehow it prints half centimeter below the top edge of the page. Another thing is that it can print from left edge.
Below is my code.
private void button1_Click(object sender, EventArgs e)
{
////PaperSize pkCustomSize1 = new PaperSize("First custom size", 1020, 3517);
////printDocument1.DefaultPageSettings.PaperSize = pkCustomSize1;
printPreviewDialog1.Document = printDocument1;
printDocument1.PrinterSettings.PrinterName = this.comboBox1.Text;
Margins margins = new Margins(0, 0, 0, 0);
printDocument1.PrinterSettings.DefaultPageSettings.Margins = margins;
printPreviewDialog1.Show();
printDocument1.Print();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
int resX = GetPrinterResolutionX(comboBox1);
int resY = PrnOpra.GetPrinterResolutionY(comboBox1);
Graphics g = e.Graphics;
float scale = resX / ScrnRes;
Bitmap bm = new Bitmap(367, 1205);
g.DrawRectangle(new Pen(Color.Black, 0.5F), panel9.Location.X / 2, panel9.Location.Y / 2, panel9.Width, panel9.Height);
g.DrawImage(bm, 0, 0);
}
What's wrong with code?
You have to set the PrintDocument.OriginAtMargins property to true to consider your margins.
From MSDN,
When OriginAtMargins is true, the Graphics object location takes into account the PageSettings.Margins property value and the printable area of the page
But printing from the exact edge depends on the printable area which is defined by the physical limitations of the printing device. Check the HardMarginX and HardMarginY to get the physical origin of the printer. For more information refer the answer of this question.
I'm pretty new to C# but I finally have my first program up and running and I need to make it print. Its a window form with information and calculations on different tab controls, somewhat like Excel. The page that is currently being looked at prints fine with the copyfromscreen method, but I cannot get additional pages to print correctly. I have about 20 tabs I would like to be able to print at one time. I found a way to print the contents of controls into a textfile, but I would much prefer to be able to print what the form looks like. Thanks.
Bitmap memoryImage;
Bitmap memoryImage2;
private void CaptureScreen()
{
Graphics myGraphics = this.CreateGraphics();
Size s = tabControlMain.Size;
s.Width = s.Width + 20;
memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
memoryGraphics.CopyFromScreen(this.Location.X+15, this.Location.Y+80, 0, 0, s);
tabControlMain.SelectedIndex = 1;
memoryImage2 = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics2 = Graphics.FromImage(memoryImage2);
memoryGraphics2.CopyFromScreen(this.Location.X + 15, this.Location.Y + 80, 0, 0, s);
}
private void printDocumentReal_PrintPage(System.Object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
e.Graphics.DrawImage(memoryImage2, 0, 550);
}
private void printToolStripButton_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocumentReal.Print();
}
First, you should use PrintDocument and PrintPreviewDialog objects for print related tasks and an event handler for printing.
Second, you need to preform some optimization for your code, here's the solution:
private void printToolStripButton_Click(object sender, EventArgs e)
{
PrintDocument document = new PrintDocument();
document.PrintPage += new PrintPageEventHandler(document_PrintPage);
PrintPreviewDialog preview = new PrintPreviewDialog() { Document = document };
// you will be able to preview all pages before print it ;)
try
{
preview.ShowDialog();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\nYou need to install a printer to preform print-related tasks!", "Print Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Boolean firstPage = true;
private void document_PrintPage(object sender, PrintPageEventArgs e)
{
if (firstPage)
{
tabControlMain.SelectTab(0);
firstPage = false;
}
Graphics g = e.Graphics;
TabPage tab = tabControlMain.SelectedTab;
using (Bitmap img = new Bitmap(tab.Width, tab.Height))
{
tab.DrawToBitmap(img, tab.ClientRectangle);
g.DrawImage(img, new Point(e.MarginBounds.X, e.MarginBounds.Y)); // MarginBounds means the margins of the page
}
if (tabControlMain.SelectedIndex + 1 < tabControlMain.TabCount)
{
tabControlMain.SelectedIndex++;
e.HasMorePages = true;//If you set e.HasMorePages to true, the Document object will call this event handler again to print the next page.
}
else
{
e.HasMorePages = false;
firstPage = true;
}
}
I hope it's working fine with you And here's an additional one if you need to save all tabs as set of images on your hard disk:
public void RenderAllTabs()
{
foreach (TabPage tab in tabControlMain.TabPages)
{
tabControlMain.SelectTab(tab);
using (Bitmap img = new Bitmap(tab.Width, tab.Height))
{
tab.DrawToBitmap(img, tab.ClientRectangle);
img.Save(string.Format(#"C:\Tabs\{0}.png", tab.Text));
}
}
}
Try using DrawToBitmap method of TabPage instead:
private void CaptureScreen()
{
memoryImage = new Bitmap(tabControlMain.SelectedTab.Width, tabControlMain.SelectedTab.Height);
tabControlMain.SelectedTab.DrawToBitmap(memoryImage, tabControlMain.SelectedTab.ClientRectangle);
tabControlMain.SelectedIndex = 1;
memoryImage2 = new Bitmap(tabControlMain.SelectedTab.Width, tabControlMain.SelectedTab.Height);
tabControlMain.SelectedTab.DrawToBitmap(memoryImage2, tabControlMain.SelectedTab.ClientRectangle);
}
To get all the images of your TabPages, you can make a loop like this:
List<Bitmap> images = new List<Bitmap>();
private void CaptureScreen(){
foreach(TabPage page in tabControlMain.TabPages){
Bitmap bm = new Bitmap(page.Width, page.Height);
tabControlMain.SelectedTab = page;
page.DrawToBitmap(bm, page.ClientRectangle);
images.Add(bm);
}
}
//Then you can access the images of your TabPages in the list images
//the index of TabPage is corresponding to its image index in the list images
In my application i have a chart which is surrounded inside a panel. I added a printdocument component from the toolbox and when i want to print the chart, i am creating a bitmap and i get the panel inside the bitmap (and as a result the chart which is inside the panel). My problem is that when i create the bitmap, when i send it to the printer to print it, it eats up some of the chart from the bottom and from the right side. Below is my code to execute this
private void button1_Click(object sender, EventArgs e)
{
PrintDialog printDialog = new PrintDialog();
printDialog.Document = printDocument1;
printDialog.UseEXDialog = true;
//Get the document
if (DialogResult.OK == printDialog.ShowDialog())
{
printDocument1.DocumentName = "Test Page Print";
printPreviewDialog1.Document = printDocument1;
if (DialogResult.OK == printPreviewDialog1.ShowDialog())
printDocument1.Print();
}
}
This is the button to initialize the print_document. (I added a print preview so that i don't have to print it every time and spent paper and ink)
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Bitmap bm = new Bitmap(this.panel1.Width, this.panel1.Height);
this.panel1.DrawToBitmap(bm, new Rectangle(50, 50, this.panel1.Width + 50, this.panel1.Height + 50));
e.Graphics.DrawImage(bm, 0, 0);
}
I was thinking that maybe the chart is too big and it doesn't fit in the page but if i save the bitmap. it fits OK inside the page actually there is too much free space on the bottom and right side. (After the draw to bitmap function add
bm.Save(#"c:\LOAN_GRAPH.png");
instead of the draw image and the image is save in c:)
Anybody who can help me i would be truly thankful.
Its working.
I removed the panel and instead, i am creating the rectangle according to my chart.
Bitmap bm = new Bitmap(this.chart1.Width, this.chart1.Height);
this.chart1.DrawToBitmap(bm, new Rectangle(50, 50, this.chart1.Width + 50, this.chart1.Height + 50));
e.Graphics.DrawImage(bm, 0, 0);
I am able to print a chart from my c# project using:
chart1.Printing.PrintDocument.DocumentName = "Graph of data";
But is it possible to add a title to this? I was hoping the document name would achieve this, but apparently not!
You can print whatever you want directly to the page and then invoke the chart PrintPaint(). Note that if you don't switch the PageUnit to Pixels that the chart scaling gets confused.
void PrintChart(object sender, PrintPageEventArgs ev)
{
using (var f = new System.Drawing.Font("Arial", 10))
{
var size = ev.Graphics.MeasureString(Text, f);
ev.Graphics.DrawString("Whatever text you want", f, Brushes.Black, ev.PageBounds.X + (ev.PageBounds.Width - size.Width) / 2, ev.PageBounds.Y);
}
//Note, the chart printing code wants to print in pixels.
Rectangle marginBounds = ev.MarginBounds;
if (ev.Graphics.PageUnit != GraphicsUnit.Pixel)
{
ev.Graphics.PageUnit = GraphicsUnit.Pixel;
marginBounds.X = (int)(marginBounds.X * (ev.Graphics.DpiX / 100f));
marginBounds.Y = (int)(marginBounds.Y * (ev.Graphics.DpiY / 100f));
marginBounds.Width = (int)(marginBounds.Width * (ev.Graphics.DpiX / 100f));
marginBounds.Height = (int)(marginBounds.Height * (ev.Graphics.DpiY / 100f));
}
chart1.Printing.PrintPaint(ev.Graphics, marginBounds);
}
This menu handler opens a PrintDialog(). If you don't want a dialog you can just call pd.Print().
private void printToolStripMenuItem_Click(object sender, EventArgs e)
{
var pd = new System.Drawing.Printing.PrintDocument();
pd.PrintPage += new PrintPageEventHandler(PrintChart);
PrintDialog pdi = new PrintDialog();
pdi.Document = pd;
if (pdi.ShowDialog() == DialogResult.OK)
pdi.Document.Print();
}
Here is a workaround solution to your problem, if you place the ChartingControl inside a Panel control on the Windows Form. You can then print the panel, inside the panel you can add the document heading as a label and whatever other stuff you want to add.
Firstly from the toolbox add a PrintDocument control and call it MyPrintDocument
Then add a Panel control and put your chart inside it.
Make sure you have imported the System.Drawing namespace, then you can print the panel like this.
Bitmap MyChartPanel = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(MyChartPanel, new Rectangle(0, 0, panel1.Width, panel1.Height));
PrintDialog MyPrintDialog = new PrintDialog();
if (MyPrintDialog.ShowDialog() == DialogResult.OK)
{
System.Drawing.Printing.PrinterSettings values;
values = MyPrintDialog.PrinterSettings;
MyPrintDialog.Document = MyPrintDocument;
MyPrintDocument.PrintController = new System.Drawing.Printing.StandardPrintController();
MyPrintDocument.Print();
}
MyPrintDocument.Dispose();
This code converts the panel into a Bitmap and then prints that Bitmap.
You could condense this into a function like:
public void PrintPanel(Panel MyPanel)
{
// Add code from above in here, changing panel1 to MyPanel...
}