Printing chart in c# - c#

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...
}

Related

How to show a message if chart data is empty?

I have WinForm with chart and database.Chart get data from database. If no data the chart isn't visible. I would like to show a message in the chart place.For example: "No data yet." Can I do it?
if (chart1["Series1"].Points.Count == 0)
{
???
}
..show a message in the chart..Can I do it?
Sure. There are in fact many ways, from setting the chart's Title to using the Paint event and DrawString or creating a TextAnnotation etc..
The two latter options are easy to center and both will keep the position even when the chart is resized.
Example 1 - A TextAnnotation:
TextAnnotation ta = new TextAnnotation();
Set it up like this:
ta.Text = "No Data Yet";
ta.X = 45; // % of the..
ta.Y = 45; // chart size
ta.Font = new Font("Consolas", 20f);
ta.Visible = false; // first we hide it
chart1.Annotations.Add(ta);
Show whenever the data are changed:
ta.Visible = (chart1.Series[seriesNameOrIndex].Points.Count == 0)
Example 2 - Drawing the messag in the Paint event:
private void chart1_Paint(object sender, PaintEventArgs e)
{
if (chart1.Series[seriesNameOrIndex].Points.Count == 0)
{
using (Font font = new Font("Consolas", 20f))
using (StringFormat fmt = new StringFormat()
{ Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center })
e.Graphics.DrawString("No data yet",
font, Brushes.Black, chart1.ClientRectangle, fmt);
}
}
This should keep itself updated as adding or removing DataPoints will trigger the Paint event.
Btw: The recommended way to test to a collection to contain any data is using the Linq Any() function:
(!chart1.Series[seriesNameOrIndex].Points.Any())
It is both as fast as possible and clear in its intent.

Print the entire area of the control with C#

This is not a duplicat question- the diffenece beetween my question an the others one is my Controler contail a scroller, so they are more informations can't be printed.
I have a C# application that contains a main form name MainForms. This MainForms has a control mainDisplay. I want to print the entire information what we found on the mainDisplay to the printer.
The problem is the information on the the control is too big, and I have to scroll to see all information.
Someone have any function that allow me to print this control MainDisplay with entire information in it?
This the printscreen of the area of my MainDisplay at the right you see the scrollbar:
I use this Function (Source : Printing a control)
private static void PrintControl(Control control)
{
var bitmap = new Bitmap(control.Width, control.Height);
control.DrawToBitmap(bitmap, new Rectangle(0, 0, control.Width, control.Height));
var pd = new PrintDocument();
pd.PrintPage += (s, e) => e.Graphics.DrawImage(bitmap, 100, 100);
pd.Print();
}
But my problem still can't print all the informations contain in my control, it's just print a small erea, still need print more informations which are not printed.
I find the solution. This is the steps i do :
1 - We have a mainForm, and this main form contain a control mainDisplay with a specific dimension and area, let's say this dimensions is smaller and we get scroll.
2- What i do is i make this mainDisplay Empty.
3- i create an other Control myControlToDisplay. I draw and i put all fields i want without scroll, so this one myControlToDisplay will have a big dimension.
4- on the star-up of my application, i tell to the mainDisplay to load myControlToDisplay. This time all the content of myControlToDisplay will be display on mainDisplay with a scroll. Because mainDisplay have a small area.
5- I write this functions :
Bitmap MemoryImage;
PrintDocument printDoc = new PrintDocument();
PrintDialog printDialog = new PrintDialog();
PrintPreviewDialog printDialogPreview = new PrintPreviewDialog();
Control panel = null;
public void Print(Control pnl)
{
DateTime saveNow = DateTime.Now;
string datePatt = #"yyyy-M-d_hh-mm-ss tt";
panel = pnl;
GetPrintArea(pnl);
printDialog.AllowSomePages = true;
printDoc.PrintPage += new PrintPageEventHandler(Print_Details);
printDialog.Document = printDoc;
printDialog.Document.DocumentName = "Document Name";
//printDialog.ShowDialog();
if (printDialog.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
public void PrintPreview(Control pnl)
{
DateTime saveNow = DateTime.Now;
string datePatt = #"yyyy-M-d_hh-mm-ss tt";
panel = pnl;
GetPrintArea(pnl);
printDoc.PrintPage += new PrintPageEventHandler(Print_Details);
printDialogPreview.Document = printDoc;
printDialogPreview.Document.DocumentName = "Document Name";
//printDialog.ShowDialog();
if (printDialogPreview.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
private void Print_Details(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
RectangleF marginBounds = e.MarginBounds;
DateTime saveNow = DateTime.Now;
string datePatt = #"M/d/yyyy hh:mm:ss tt";
//String dtString = saveNow.ToString(datePatt);
// create header and footer
string header = "Put all information you need to display on the Header";
string footer = "Print date : " + saveNow.ToString(datePatt);
Font font = new Font("times new roman", 10, System.Drawing.FontStyle.Regular);
Brush brush = new SolidBrush(Color.Black);
// measure them
SizeF headerSize = e.Graphics.MeasureString(header, font);
SizeF footerSize = e.Graphics.MeasureString(footer, font);
// draw header
RectangleF headerBounds = new RectangleF(marginBounds.Left-80, marginBounds.Top-80, marginBounds.Width, headerSize.Height);
e.Graphics.DrawString(header, font, brush, headerBounds);
// draw footer
RectangleF footerBounds = new RectangleF(marginBounds.Left-80, marginBounds.Bottom - footerSize.Height+80, marginBounds.Width, footerSize.Height);
e.Graphics.DrawString(footer, font, brush, footerBounds);
// dispose objects
font.Dispose();
brush.Dispose();
}
public void GetPrintArea(Control pnl)
{
MemoryImage = new Bitmap(pnl.Width, pnl.Height);
Rectangle rect = new Rectangle(0, 0, pnl.Width, pnl.Height);
pnl.DrawToBitmap(MemoryImage, new Rectangle(0, 0, pnl.Width, pnl.Height));
}
protected override void OnPaint(PaintEventArgs e)
{
if (MemoryImage != null)
{
e.Graphics.DrawImage(MemoryImage, 0, 0);
base.OnPaint(e);
}
}
void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
{
Rectangle pageArea = e.PageBounds;
Rectangle m = e.MarginBounds;
if ((double)MemoryImage.Width / (double)MemoryImage.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)MemoryImage.Height / (double)MemoryImage.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)MemoryImage.Width / (double)MemoryImage.Height * (double)m.Height);
}
e.Graphics.DrawImage(MemoryImage, m);
}
6 -And finally we suppose that we have two buttons, one to Print and the other one to print preview.
You just have to call this function :
private void PrintButton_Click(object sender, EventArgs e)
{
try
{
Print(mainDisplay.getCurentPanel());
}
catch (Exception exp)
{
MessageBox.Show("Error: \n" + exp.Message);
}
}
private void PrintPreviewButton_Click(object sender, EventArgs e)
{
try
{
PrintPreview(mainDisplay.getCurentPanel());
}
catch (Exception exp)
{
MessageBox.Show("Error: \n" + exp.Message);
}
}
Hope it will help someone :)
good luck

c# scrolling text above the form elements

I create a scrolling text with DrawString.
It works, but the text remains under the form elements. I would like the text to pass over.
The code:
int x = 0;
string texto = "prova prova";
int tam = 15;
private void timer_Tick_1(object sender, EventArgs e)
{
Graphics gra = this.CreateGraphics();
gra.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gra.DrawString(texto, new Font("Times New Roman", tam), new SolidBrush(Color.CornflowerBlue),x, 70);
gra.Dispose();
x += 6;
if (x >= this.Width)
x = texto.Length * tam * -1;
}
This is by design, a Graphics object can only paint to the area it was created for.
If you want the text to appear in front of all other elements on the Form, you have to create a custom control which does the drawing.
Add an instance of this control to the Form and use the BringToFront method to position it on top of each other contained elements in the Form.

When I print bitmap, it eats up some of it

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);

Printing image with PrintDocument. how to adjust the image to fit paper size

In C#, I am trying to print an image using PrintDocument class with the below code. The image is of size 1200 px width and 1800 px height. I am trying to print this image in a 4*6 paper using a small zeebra printer. But the program is printing only 4*6 are of the big image. that means it is not adjusting the image to the paper size !
PrintDocument pd = new PrintDocument();
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile("C://tesimage.PNG");
Point p = new Point(100, 100);
args.Graphics.DrawImage(i, 10, 10, i.Width, i.Height);
};
pd.Print();
When i print the same image using Window Print (right click and select print, it is scaling automatically to paper size and printing correctly. that means everything came in 4*6 paper.) How do i do the same in my C# program ?
The parameters that you are passing into the DrawImage method should be the size you want the image on the paper rather than the size of the image itself, the DrawImage command will then take care of the scaling for you. Probably the easiest way is to use the following override of the DrawImage command.
args.Graphics.DrawImage(i, args.MarginBounds);
Note: This will skew the image if the proportions of the image are not the same as the rectangle. Some simple math on the size of the image and paper size will allow you to create a new rectangle that fits in the bounds of the paper without skewing the image.
Not to trample on BBoy's already decent answer, but I've done the code that maintains aspect ratio. I took his suggestion, so he should get partial credit here!
PrintDocument pd = new PrintDocument();
pd.DefaultPageSettings.PrinterSettings.PrinterName = "Printer Name";
pd.DefaultPageSettings.Landscape = true; //or false!
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile(#"C:\...\...\image.jpg");
Rectangle m = args.MarginBounds;
if ((double)i.Width / (double)i.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)i.Height / (double)i.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)i.Width / (double)i.Height * (double)m.Height);
}
args.Graphics.DrawImage(i, m);
};
pd.Print();
The solution provided by BBoy works fine. But in my case I had to use
e.Graphics.DrawImage(memoryImage, e.PageBounds);
This will print only the form. When I use MarginBounds it prints the entire screen even if the form is smaller than the monitor screen. PageBounds solved that issue. Thanks to BBoy!
You can use my code here
//Print Button Event Handeler
private void btnPrint_Click(object sender, EventArgs e)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += PrintPage;
//here to select the printer attached to user PC
PrintDialog printDialog1 = new PrintDialog();
printDialog1.Document = pd;
DialogResult result = printDialog1.ShowDialog();
if (result == DialogResult.OK)
{
pd.Print();//this will trigger the Print Event handeler PrintPage
}
}
//The Print Event handeler
private void PrintPage(object o, PrintPageEventArgs e)
{
try
{
if (File.Exists(this.ImagePath))
{
//Load the image from the file
System.Drawing.Image img = System.Drawing.Image.FromFile(#"C:\myimage.jpg");
//Adjust the size of the image to the page to print the full image without loosing any part of it
Rectangle m = e.MarginBounds;
if ((double)img.Width / (double)img.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)img.Height / (double)img.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)img.Width / (double)img.Height * (double)m.Height);
}
e.Graphics.DrawImage(img, m);
}
}
catch (Exception)
{
}
}
Answer:
public void Print(string FileName)
{
StringBuilder logMessage = new StringBuilder();
logMessage.AppendLine(string.Format(CultureInfo.InvariantCulture, "-------------------[ START - {0} - {1} -------------------]", MethodBase.GetCurrentMethod(), DateTime.Now.ToShortDateString()));
logMessage.AppendLine(string.Format(CultureInfo.InvariantCulture, "Parameter: 1: [Name - {0}, Value - {1}", "None]", Convert.ToString("")));
try
{
if (string.IsNullOrWhiteSpace(FileName)) return; // Prevents execution of below statements if filename is not selected.
PrintDocument pd = new PrintDocument();
//Disable the printing document pop-up dialog shown during printing.
PrintController printController = new StandardPrintController();
pd.PrintController = printController;
//For testing only: Hardcoded set paper size to particular paper.
//pd.PrinterSettings.DefaultPageSettings.PaperSize = new PaperSize("Custom 6x4", 720, 478);
//pd.DefaultPageSettings.PaperSize = new PaperSize("Custom 6x4", 720, 478);
pd.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
pd.PrinterSettings.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
pd.PrintPage += (sndr, args) =>
{
System.Drawing.Image i = System.Drawing.Image.FromFile(FileName);
//Adjust the size of the image to the page to print the full image without loosing any part of the image.
System.Drawing.Rectangle m = args.MarginBounds;
//Logic below maintains Aspect Ratio.
if ((double)i.Width / (double)i.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)i.Height / (double)i.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)i.Width / (double)i.Height * (double)m.Height);
}
//Calculating optimal orientation.
pd.DefaultPageSettings.Landscape = m.Width > m.Height;
//Putting image in center of page.
m.Y = (int)((((System.Drawing.Printing.PrintDocument)(sndr)).DefaultPageSettings.PaperSize.Height - m.Height) / 2);
m.X = (int)((((System.Drawing.Printing.PrintDocument)(sndr)).DefaultPageSettings.PaperSize.Width - m.Width) / 2);
args.Graphics.DrawImage(i, m);
};
pd.Print();
}
catch (Exception ex)
{
log.ErrorFormat("Error : {0}\n By : {1}-{2}", ex.ToString(), this.GetType(), MethodBase.GetCurrentMethod().Name);
}
finally
{
logMessage.AppendLine(string.Format(CultureInfo.InvariantCulture, "-------------------[ END - {0} - {1} -------------------]", MethodBase.GetCurrentMethod().Name, DateTime.Now.ToShortDateString()));
log.Info(logMessage.ToString());
}
}
Agree with TonyM and BBoy - this is the correct answer for original 4*6 printing of label. (args.PageBounds). This worked for me for printing Endicia API service shipping Labels.
private void SubmitResponseToPrinter(ILabelRequestResponse response)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile(response.Labels[0].FullPathFileName.Trim());
args.Graphics.DrawImage(i, args.PageBounds);
};
pd.Print();
}
all these answers has the problem, that's always stretching the image to pagesize and cuts off some content at trying this.
Found a little bit easier way.
My own solution only stretch(is this the right word?) if the image is to large, can use multiply copies and pageorientations.
PrintDialog dlg = new PrintDialog();
if (dlg.ShowDialog() == true)
{
BitmapImage bmi = new BitmapImage(new Uri(strPath));
Image img = new Image();
img.Source = bmi;
if (bmi.PixelWidth < dlg.PrintableAreaWidth ||
bmi.PixelHeight < dlg.PrintableAreaHeight)
{
img.Stretch = Stretch.None;
img.Width = bmi.PixelWidth;
img.Height = bmi.PixelHeight;
}
if (dlg.PrintTicket.PageBorderless == PageBorderless.Borderless)
{
img.Margin = new Thickness(0);
}
else
{
img.Margin = new Thickness(48);
}
img.VerticalAlignment = VerticalAlignment.Top;
img.HorizontalAlignment = HorizontalAlignment.Left;
for (int i = 0; i < dlg.PrintTicket.CopyCount; i++)
{
dlg.PrintVisual(img, "Print a Image");
}
}

Categories

Resources