PrintDocument / PrintPreviewDialog Nothing Draws or Prints - c#

I am playing around with the PrintDocument and PrintPreviewDialog classes to learn them, but I cannot seem to get the document to print anything when sent to the printer, and also nothing draws at all in the PrintPreviewDialog, not even a white blank page, it is all grey. Ive tried changing margins, draw locations, drawing giant rectangle, etc., nothing shows up. I am not very familiar with GDI+ so I am sure I am missing something, but I cannot find what.
Here is the relevant code I am using:
//Print
private void menuPrint_click(Object source, EventArgs e)
{
printDocumentPage = 0;
printDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(printDocument1_PrintPage);
printDocument1.BeginPrint += new System.Drawing.Printing.PrintEventHandler(printDocument1_BeginPrint);
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Save our print action so we know if we are printing
// a preview or a real document.
printAction = e.PrintAction;
// Set some preferences, our method should print a box with any
// combination of these properties being true/false.
printDocument1.OriginAtMargins = false;
if (printAction != PrintAction.PrintToPreview)
{
PrintDialog printDlg = new PrintDialog();
printDocument1.DocumentName = "Print Document Simple Text";
printDlg.Document = printDocument1;
// Show printer dialog
if (printDlg.ShowDialog() == DialogResult.OK)
{
printDocument1.PrinterSettings = printDlg.PrinterSettings;
}
else
{
e.Cancel = true;
}
}
}
void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Graphics g = e.Graphics;
RectangleF marginBounds = e.MarginBounds;
RectangleF printableArea = e.PageSettings.PrintableArea;
//if (printAction == PrintAction.PrintToPreview)
//g.TranslateTransform(printableArea.X, printableArea.Y);
int availableWidth = (int)Math.Floor(printDocument1.OriginAtMargins ? marginBounds.Width : (e.PageSettings.Landscape ? printableArea.Height : printableArea.Width));
int availableHeight = (int)Math.Floor(printDocument1.OriginAtMargins ? marginBounds.Height : (e.PageSettings.Landscape ? printableArea.Width : printableArea.Height));
//g.DrawRectangle(Pens.Red, 0, 0, availableWidth - 1, availableHeight - 1);
// Doesnt work either
//g.DrawRectangle(Pens.Red, 0, 0, 100, 100);
System.Drawing.Font myFont = new System.Drawing.Font("Courier New", 10, FontStyle.Underline, GraphicsUnit.Pixel);
float lineHeight = myFont.GetHeight(g);
float yLineTop = e.MarginBounds.Top;
if (printDocumentPage >= m_report.PageCount)
{
e.HasMorePages = false;
return;
}
otPage page = m_report.pageAt((int)printDocumentPage);
for (int i = 0; i < page.LineCount ; i++)
{
otLine line = page.lineAt(i);
g.DrawString(line.getPrintLine(true), myFont, Brushes.Black, e.MarginBounds, StringFormat.GenericTypographic);
yLineTop += lineHeight;
}
printDocumentPage++;
if (printDocumentPage < m_report.PageCount)
{
e.HasMorePages = true;
return;
}
e.HasMorePages = false;
}
The PrintPreviewDialog appears, and both event handlers are run, it loops through the lines correctly and draws each of them, but nothing is drawn on the dialog and when sent to the printer, it prints empty pages. The PrintPreviewDialog is all grey, no white pages or anything, and zooming at all levels does nothing.
EDIT: Getting rid of my current page/line handling and just trying to draw a single string, any string, or rectangle, something nothing works.
Here is a screenshot of the print preview screen. Changing the zoom/pages does nothing either:
EDIT2:
I downloaded this very simple example project from http://www.c-sharpcorner.com/uploadfile/mahesh/printpreviewcontrol-in-c-sharp/ which I assume works as intended. Straight out of the box this does the same thing. Only a grey screen shows (and the button on the form). Nothing prints in the printpreviewcontrol at all.
What could be the problem?
EDIT3:
I tested this on another development machine and it works fine. Why wouldnt it work on my computer? The other computer is 64 bit whereas this is 32, but was built with same settings. Could it be my .NET framework is messed up?
EDIT4:
Sorry for all the edits. Ive found that if I switch my default printer, it works perfectly. Something to do with the e.MarginBounds.

Related

Display zoomed in part of pictureBox in another pictureBox by hovering cursor c#

I am working on a program that displays the liveView image from a Nikon camera in a pictureBox. I want to be able to hover with the cursor over the image and display a zoomed in area around the cursor in another picturebox. I would also like to add a crosshair instead of mouse pointer. The only solution I have found so far is the following:
zoom an image in a second picturebox following cursor
It does exactly what I want, however I can not get it to work. More specifically, nothing is showing up in picZoom. In the example, images are loaded while in my case, a video stream is shown. That might be the reason why I am not getting it to work. I am relatively new to c#, and did not fully understand the example.
Lets say I have picBox where I receive the video stream. How do I show a portion of picBox around the cursor (let's say a rectangle around the cursor of dimensions x,y) in picZoom with a crosshair as in the example. I do not need to worry about differing dimensions of picBox and picZoom since they will not vary. I also want to be able to vary the degree of zoom by a factor zoomFactor.
If anyone could give me pointers or a solution, it would be greatly appreciated. Also, sorry if my question is poorly formatted, I am new to the forum.
Thank you!
Alexander
I would approach it like this
using System;
using System.Drawing;
using System.Windows.Forms;
namespace MagnifierExample
{
class Magnifier : PictureBox
{
public Magnifier()
{
Visible = false;
}
PictureBox source;
private Point sourcePoint;
Cursor oldCursor;
public PictureBox Source
{
get
{
return source;
}
set
{
if (source != null)
{
source.MouseEnter -= Source_MouseEnter;
source.MouseLeave -= Source_MouseLeave;
source.MouseMove -= Source_MouseMove;
source.Cursor = oldCursor;
}
source = value;
if (source != null)
{
source.MouseEnter += Source_MouseEnter;
source.MouseLeave += Source_MouseLeave;
source.MouseMove += Source_MouseMove;
oldCursor = source.Cursor;
source.Cursor = Cursors.Cross;
}
}
}
private void Source_MouseEnter(object sender, EventArgs e)
{
Visible = true;
BringToFront();
}
private void Source_MouseLeave(object sender, EventArgs e)
{
Visible = false;
}
private void Source_MouseMove(object sender, MouseEventArgs e)
{
sourcePoint = e.Location;
Location = new Point(source.Location.X + e.X - Width / 2, source.Location.Y + e.Y - Height / 2);
Invalidate();
}
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 0x0084;
const int HTTRANSPARENT = (-1);
if (!DesignMode && m.Msg == WM_NCHITTEST)
{
m.Result = (IntPtr)HTTRANSPARENT;
}
else
{
base.WndProc(ref m);
}
}
protected override void OnPaint(PaintEventArgs pe)
{
if (!DesignMode && Source != null && Source.Image != null)
{
Rectangle destRect = new Rectangle(0, 0, Width, Height);
// IMPORTANT: This calculation will depend on the SizeMode of the source and the amount you want to zoom.
// This does 2x zoom and works with PictureBoxSizeMode.Normal:
Rectangle srcRect = new Rectangle(sourcePoint.X - Width / 4, sourcePoint.Y - Height / 4, Width / 2, Height / 2);
pe.Graphics.DrawImage(Source.Image, destRect, srcRect, GraphicsUnit.Pixel);
}
else
{
base.OnPaint(pe);
}
}
}
}
To hook it up all you have to do is add a Magnifier to your form, give it a size, and set its Source to the PictureBox you want it to magnify.
this.magnifier1.Source = this.pictureBox1;
I used the approach in this answer to ignore messages from the magnifier window.
Importantly, I only coded up the zoom math for the PictureBoxSizeMode.Normal SizeMode of the source PictureBox. But I think this is a pretty good start.
Not 100% sure what you wanted for crosshairs, but this uses the built-in crosshair cursor.

Printing a Windows Form fit to an A4 Paper [duplicate]

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

c# - Print the winform in high quality?

This question may sound familiar but i have searched internet and couldn't find a solution to it.
I know for printing we can use Crystal Report but i am discarding that idea because of it's certain disadvantages. Here are some of the disadvantages:-
Needs installation on PC and if the Visual Studio version is 2017 then you have to download 200MB+ setup.
If you have made certain objects like textobject and lines in one section and you have to add something in the middle of it then you have to manually set location of every object otherwise if you collectively select all the object and move it then their original location and the spacing between each object gets lost.
Currently i am using VS2008 and it has crystal report integrated in it which has a well know problem of sometime changing the text of every textobject and adding an "i" in it for some reason.
I also tried to download an alternate to crystal report. But its interface is not that friendly.
Alternate that i am choosing
Now i have designed my report on Windows Form. When i am trying to print, its quality is worse as compared to Crystal Reports print. Here is the code for it
private System.IO.Stream streamToPrint;
string streamType;
private void printDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.Drawing.Image image = System.Drawing.Image.FromStream(this.streamToPrint);
int x = e.MarginBounds.X;
int y = e.MarginBounds.Y;
int width = image.Width;
int height = image.Height;
if ((width / e.MarginBounds.Width) > (height / e.MarginBounds.Height))
{
width = e.MarginBounds.Width;
height = image.Height * e.MarginBounds.Width / image.Width;
}
else
{
height = e.MarginBounds.Height;
width = image.Width * e.MarginBounds.Height / image.Height;
}
System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(x, y, width, height);
e.Graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, System.Drawing.GraphicsUnit.Pixel);
}
private void btnPrint_Click(object sender, EventArgs e)
{
string fileName = Application.StartupPath + "\\PrintPage.jpg";
using (Graphics gfx = this.CreateGraphics())
{
using (Bitmap bmp = new Bitmap(this.Width, this.Height, gfx))
{
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
bmp.Save(fileName);
}
}
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StartPrint(fileStream, "Image");
fileStream.Close();
if (System.IO.File.Exists(fileName))
{
System.IO.File.Delete(fileName);
}
}
public void StartPrint(Stream streamToPrint, string streamType)
{
this.printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
this.streamToPrint = streamToPrint;
this.streamType = streamType;
System.Windows.Forms.PrintDialog PrintDialog1 = new PrintDialog();
PrintDialog1.AllowSomePages = true;
PrintDialog1.ShowHelp = true;
PrintDialog1.Document = printDoc;
DialogResult result = PrintDialog1.ShowDialog();
if (result == DialogResult.OK)
{
printDoc.Print();
//docToPrint.Print();
}
}
private void Frm_Test_Shown(object sender, EventArgs e)
{
try
{
btnPrint_Click(sender, e);
}
catch (Exception ex) { clsUtility.ShowErrMsg(ex.Message); }
}
I understand the reason why it is doing so because of the image and screen resolution thing (Ref : https://stackoverflow.com/a/12547806/2994869). The workaround people mentioned was to increase the size of windows form and it's object by 6 times but that had the same result still the quality is worse.
Is there any workaround or any trick that i can do to print a windows form so that quality is near to that of Crystal Report's.
For high quality you need to create a source with higher resolution than the screen, which is all you can get from DrawToBitmap.
Using DrawToBitmap will only help if you can enlarge a single control a lot. For the whole form it will not help.
You will need to fully re-create the parts you want to print and use as many DrawString and other DrawXXX methods as needed. Yes, a lot of work. (But fun ;-)
But the code you show also blunders by using a jpg file format, which was created for soft images (i.e. photographs). Change that to png and compare!

Xamarin MasterDetailPage memory leak with custom renderer

I am using a MasterDetailPage in Xamarin.Forms/Android with each item in the hamburger page representing a page. I change the detail page by calling:
Detail = new NavigationPage(new Pages.HomePage());
IsPresented = false;
What I have noticed is that the allocation for this page is somewhat large (it's requesting like 22mb). Not only that, but if I were to repeatedly press the sidebar's home button, I get an OutOfMemoryException after about 5 clicks. So something isn't clicking with the Garbage Collection.
The home page has a custom renderer that essentially composites an image using three png files. This works with minimal slowdown on my phone, but the emulator lags significantly when it is on screen, leading me to believe that it is causing performance issues.
public class GoalJarViewRenderer : ImageRenderer
{
Bitmap fillBmp = null;
Bitmap jarHud = null;
Paint font;
Paint fontBold;
string goalString = "";
string progString = "";
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
this.SetWillNotDraw(false);
base.OnElementChanged(e);
Element.PropertyChanged += SignalUpdate;
//Cache
if (fillBmp == null) fillBmp = BitmapFactory.DecodeResource(this.Context.Resources, Resource.Drawable.jar_fill);
if (jarHud == null) jarHud = BitmapFactory.DecodeResource(this.Context.Resources, Resource.Drawable.jar_hud);
if (font == null)
{
font = new Paint();
font.AntiAlias = true;
font.Color = Android.Graphics.Color.White;
font.TextSize = 50;
font.TextAlign = Paint.Align.Center;
}
if (fontBold == null)
{
fontBold = new Paint(font);
fontBold.FakeBoldText = true;
fontBold.TextSize = 80;
}
}
private void SignalUpdate(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
GoalJarView handle = (GoalJarView)this.Element;
goalString = String.Format("${0:#0.0#} / ${1:##.##}", handle.CurrentValue, handle.GoalValue);
progString = String.Format("{0:##0.00}%", (handle.CurrentValue / handle.GoalValue) * 100);
this.Invalidate();
}
public override void Draw(Canvas canvas)
{
base.Draw(canvas);
//Draw the fill
double LID_FIX = 0.91;
GoalJarView handle = (GoalJarView)this.Element;
double fillRatio = Math.Min(1,((handle.CurrentValue * LID_FIX) / handle.GoalValue));
int srcStartY = (int)(fillBmp.Height - Math.Floor(fillBmp.Height * fillRatio));
int destStartY = (int)(canvas.Height - Math.Floor(canvas.Height * fillRatio));
Rect fillSrc = new Rect(0, srcStartY, fillBmp.Width, fillBmp.Height);
RectF fillDest = new RectF(0, destStartY, canvas.Width, canvas.Height);
canvas.DrawBitmap(fillBmp, fillSrc, fillDest, null);
//Draw the text container
canvas.DrawBitmap(jarHud, null, new Rect(0,0,canvas.Width,canvas.Height), null);
//Draw the Text
canvas.DrawText(progString, canvas.Width / 2, (canvas.Height / 2) - 20, fontBold);
canvas.DrawText(goalString, canvas.Width / 2, (canvas.Height / 2) + 30, font);
}
}
I was told that BitmapFactory.DecodeResource was incredibly taxing, so I moved that into the OnElementChanged rather than the draw function. I don't see anything else immediately taxing inside of Draw(), but I am new to Xamarin/Android and assume the problem is glaringly obvious to a seasoned developer.
I have tried creating local variables on the MasterDetailPage that stores pages so they don't need to be created every time an item is pressed, but this led to crashing when the page reopened, as the actual control class that stores the data bindings was null.
What is causing this memory leak, and how can I correct it?

Why isn't the PrintPreview exactly the same as the paper print?

Okay, before you spam me with StringFormat.Alignment = StringAlignment.Center ... hear my whole issue:
When I draw text with the following code, the string is centered in the PrintPreview, but NOT CENTERED on the actual paper when it prints. The whole page is off to the right just a little, thus some stuff shows as printing on the print preview, but falls off the paper (not just outside the margin range, but OFF the paper) when printed.
private void button1_Click(object sender, EventArgs e)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
PrintPreviewDialog ppd = new PrintPreviewDialog();
((Form)ppd).WindowState = FormWindowState.Maximized;
ppd.Document = pd;
ppd.ShowDialog();
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
for (int y = 100; y < 400; y += 25)
{
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(5, y, 840, 25));
}
e.HasMorePages = false;
}
Any thoughts as to why it's off? This should be trivial, but it isn't.
EDIT: I've found that it's not just text... It's printing EVERYTHING off just a little. I've updated the code above to provide a better example of the issue. Just drop this in a form with a button on it.
EDIT 2: With the answer given, I've modified the code and this now works. I'm providing the final code for those that may want to see it. I have to recognize whether i'm seeing this in the PrintPreview dialog or on paper, so I have a IsPreview flag to handle this.
public partial class Form1 : Form
{
bool IsPreview = true;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IsPreview = true;
PrintDocument pd = new PrintDocument();
pd.EndPrint += new PrintEventHandler(pd_EndPrint);
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
PrintPreviewDialog ppd = new PrintPreviewDialog();
((Form)ppd).WindowState = FormWindowState.Maximized;
ppd.Document = pd;
ppd.ShowDialog();
}
void pd_EndPrint(object sender, PrintEventArgs e)
{
IsPreview = false;
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
Rectangle b3 = e.PageBounds;
if (IsPreview)
{
e.Graphics.TranslateTransform(e.PageSettings.HardMarginX, e.PageSettings.HardMarginY);
}
b3.Width -= (int)e.PageSettings.HardMarginX * 2;
b3.Height -= (int)e.PageSettings.HardMarginY * 3;
int y = b3.Y;
int x=0;
while ((y + 25) < b3.Bottom)
{
x++;
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
Rectangle R = new Rectangle(b3.X, y, b3.Width, 25);
e.Graphics.DrawRectangle(Pens.Black, R);
e.Graphics.DrawString(x.ToString(), this.Font, Brushes.Black, b3.X + 5, y + 5);
y += 25;
}
// draw the last little bit
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(b3.X, y, b3.Width, b3.Height - y));
e.HasMorePages = false;
}
}
Being off towards the right tends to be explainable by the value of the PageSettings.HardMarginX property. A value produced by the printer driver. Printer drivers are however typically not very good at guessing what the actual paper route through the printer might look like. That's mechanical, pinch rollers, tray alignment and whatnot. Software and Mechanical engineers don't have lunch together often enough.
But a software engineer can almost always fix a mechanical engineer's problem. You'll need an Options dialog to allow the user to fix the mechanical engineer's problem. Use the value in e.Graphics.TranslateTransform call.
The reason the preview doesn't match up to the paper is because you haven't selected a printer yet. Every printer is a bit different for things like unprintable areas, forced margins, etc. It's been a while since I've done winforms printing, but I do recall that the passed graphics object has a way to account for that.

Categories