DrawString method repeats a string twice - c#

I want this to take a given piece of text and display it as a paragraph correctly (jumping to new line when needed) using DrawString and for(;;) loop, but the result is bonkers.
private void pnlText_Paint(object sender, PaintEventArgs e)
{
pnlText.Font = new Font("Calibri", 14, FontStyle.Regular);
SizeF lineSize = new SizeF();
for (int i = 0; i < DisplayText.Length; i++)
{
currentLine += DisplayText[i];
lineSize = e.Graphics.MeasureString(currentLine, pnlText.Font);
if (DisplayText[i].ToString() == " " && lineSize.Width >= 820)
{
paragraph += currentLine + "\n";
currentLine = null;
}
}
using (SolidBrush br = new SolidBrush(Color.Black))
{
e.Graphics.DrawString(paragraph, pnlText.Font, br, 5, 5);
}
}
The output:
one sentence whole paragraph
I am dumbstruck, it makes no sense for it to repeat like that.
I have tried using String Builder and replacing DisplayText.Length with a number and it still doesn't work right. Using foreach and drawing each char seperately works, albeit messes up spacing.
Also initially I didn't have "paragraph" string and I simply drew each line inside the loop, but that somehow caused the end of the text to be cut off and pasted at the very beginning which is even more insane. I am getting suspicious my computer is possessed with deamons.

It seems that your paragraph variable has a shared state. Verify you reset the state for each button click like that:
private void pnlText_Paint(object sender, PaintEventArgs e)
{
pnlText.Font = new Font("Calibri", 14, FontStyle.Regular);
SizeF lineSize = new SizeF();
paragraph = ""; // that should reset the paragraph variable between invocations
for (int i = 0; i < DisplayText.Length; i++)
{
currentLine += DisplayText[i];
lineSize = e.Graphics.MeasureString(currentLine, pnlText.Font);
if (DisplayText[i].ToString() == " " && lineSize.Width >= 820)
{
paragraph += currentLine + "\n";
currentLine = null;
}
}
using (SolidBrush br = new SolidBrush(Color.Black))
{
e.Graphics.DrawString(paragraph, pnlText.Font, br, 5, 5);
}
}
Or simply define it inside the pnlText_Paint method
Hope it helps :)

private void pnlText_Paint(object sender, PaintEventArgs e)
{
pnlText.Font = new Font("Calibri", 14, FontStyle.Regular);
SizeF lineSize = new SizeF();
currentLine = null;
paragraph = null;
for (int i = 0; i < DisplayText.Length; i++)
{
currentLine += DisplayText[i];
lineSize = e.Graphics.MeasureString(currentLine, pnlText.Font);
if (DisplayText[i].ToString() == " " && lineSize.Width >= 820)
{
paragraph += currentLine + "\n";
currentLine = null;
}
}
paragraph += currentLine;
using (SolidBrush br = new SolidBrush(Color.Black))
{
e.Graphics.DrawString(paragraph, pnlText.Font, br, 5, 5);
}
}
Followed Hans Kesting advice and now it works. Something is calling the paint event more than once, hence the strings are not null to begin with.

Related

C# System.Drawing - DrawString method - arabic string issue

I have the following issue when trying to draw a string and then printing it to PDF by Amyuni Printer :
where I couldn't select the text when pressing (Ctrl+A) , I need this PDF file to use it into another PDF reader , and it seems that the reader , tries to read the selected area not the actual text area .
I'm using the following code to do this stuff :
Font printFont = new Font("Simplified Arabic Fixed", (float)11, FontStyle.Regular);
StreamReader Printfile;
using (StreamReader Printfile = new StreamReader(#"C:\20_2.txt", Encoding.Default))
{
try
{
PrintDocument docToPrint = new PrintDocument();
PaperSize ps = new PaperSize("A4", 827, 1169);
bool bolFirstPage = true;
docToPrint.DefaultPageSettings.PaperSize = ps;
docToPrint.DefaultPageSettings.Landscape = true;
docToPrint.DocumentName = "docName" + DateTime.Now.Ticks.ToString(); //Name that appears in the printer queue
string FirstLine = Printfile.ReadLine();
bool bIsArabic = true;
docToPrint.PrintPage += (s, ev) =>
{
float nFontHight = printFont.GetHeight(ev.Graphics);
bIsArabic = true;
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = 1008;
float topMargin = 120;
string line = null;
//Calculate the number of lines per page.
linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics) + 2;
Image img = Image.FromFile(#"C:\image.bmp");
ev.Graphics.DrawImage(img, 6, 1, 1095, 728);
//***Image Reslution is Working good -->***
StringFormat format = new StringFormat()/*arabic*/;
line = Printfile.ReadLine();
format = new StringFormat(StringFormatFlags.DisplayFormatControl | StringFormatFlags.DirectionRightToLeft)/*arabic*/;
do
{
yPos = topMargin + ((count) * printFont.GetHeight(ev.Graphics) * (float)0.91);
line = " تجربة تجربة تجربة تجربة تجربة";
ev.Graphics.DrawString(line, printFont, Brushes.DeepPink, leftMargin, yPos, format);
count++;
} while ((line = Printfile.ReadLine()) != null && !line.Contains(''));// lines contains \0 as UniCode
// If more lines exist, print another page.
if (line != null)
ev.HasMorePages = true;
else
ev.HasMorePages = false;
};
docToPrint.Print();
}
catch (System.Exception f)
{
MessageBox.Show(f.Message);
}
}
}
when I'm using another font type like "Arial" I can select near to 90% of the text, but unfortunately I have to use only the font type "Simplified Arabic Fixed" , and I'm using windows server 2003.
one more thing , when i try to print directly Arabic text from notepad it's work fine.

Issue in display data in datagridview cell

I'm try to highlight some special words in my string that represented in data-grid-view cell, Now i can highlight every word in my special words list but after make that when represent the data in data-grid-view the data not represented correctly some lines shown after his original location and other shown before his original location.
This show the result when i try to make the operation in my question words.
this is my code, can anyone please help me to solve this problem.
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
string []specialWords = wordss.ToArray();
try
{
Color ForeColor = ((DataGridView)sender).ForeColor;
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
string content = e.Value.ToString().ToUpper();
string[] line = Regex.Split(content, "(" + String.Join("|", specialWords) + ")", RegexOptions.IgnoreCase);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.ContentForeground);
SizeF[] size = new SizeF[line.Length];
for (int i = 0; i < line.Length; ++i)
{
size[i] = e.Graphics.MeasureString(line[i], e.CellStyle.Font);
}
RectangleF rec = new RectangleF(e.CellBounds.Location, new Size(0, 0));
using (SolidBrush bnormal = new SolidBrush(ForeColor), bspecial = new SolidBrush(Color.RoyalBlue))
{
for (int i = 0; i < line.Length; ++i)
{
rec = new RectangleF(new PointF(rec.Location.X + rec.Width, rec.Location.Y), new SizeF(size[i].Width, e.CellBounds.Height));
if (specialWords.Contains(line[i].ToUpper()))
{
e.Graphics.DrawString(line[i], e.CellStyle.Font, bspecial, rec, sf);
}
else
{
e.Graphics.DrawString(line[i], e.CellStyle.Font, bnormal, rec, sf);
}
}
}
e.Handled = true;
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

C # Code to Print String in Pre Formated Style

I Have written this code to formats textbox
for (int i = 0; i < datGrid.Rows.Count - 1; i++)
{
String data = String.Format(
"{0,-18} {1,-10} {2,-10} {3,-7} {4,-10} | {5,5} ",
datGrid.Rows[i].Cells[0].Value.ToString(),
datGrid.Rows[i].Cells[1].Value.ToString(),
datGrid.Rows[i].Cells[2].Value.ToString(),
datGrid.Rows[i].Cells[3].Value.ToString(),
datGrid.Rows[i].Cells[4].Value.ToString(),
datGrid.Rows[i].Cells[5].Value.ToString());
textBox1.Text += "\n" + data;
data = "";
}
textBox1.Text += "\n------------------------------------";
textBox1.Text += "\n" +
String.Format("{0,-1}{1,-10}{2,-2}{3,-10}{4,-2}{5,-1}",
"Total :" + " ", labelTotal.Text+" ",
"Paid :" + " ", labelPaid.Text + " ",
"Balance:" + " ", labelBalance.Text);
I Used followiing code to print
streamToPrint = new StringReader(textBox1.Text);
streamToPrint.InitializeLifetimeService();
try
{
printFont = new Font("Arial", 8);
dialog.Document = pd;
PaperSize paperSize = new PaperSize("My Envelope",410,420);
pd.DefaultPageSettings.PaperSize = paperSize;
// pd.DefaultPageSettings.Landscape = true;
pd.DefaultPageSettings.Margins = new Margins(5, 5,5, 10);
pd.PrintPage += new PrintPageEventHandler (this.pd_PrintPage);
if (dialog.ShowDialog() == DialogResult.OK)
{
pd.Print();
}
}
finally
{
streamToPrint.Close();
}
And to print text following code
private void pd_PrintPage(object sender, PrintPageEventArgs ev)
{
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = ev.MarginBounds.Left;
float topMargin = ev.MarginBounds.Top;
string line = null;
// Calculate the number of lines per page.
linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics);
// Print each line of the file.
while (count < linesPerPage &&
((line = streamToPrint.ReadLine()) != null))
{
yPos = topMargin + (count * printFont.GetHeight(ev.Graphics));
ev.Graphics.DrawString(line, printFont, Brushes.Black, leftMargin - 3,
yPos - 5, new StringFormat(StringFormatFlags.LineLimit));
count++;
}
// If more lines exist, print another page.
if (line != null)
ev.HasMorePages = true;
else
ev.HasMorePages = false;
//ev.Graphics.DrawString(textBox1.Text,
// new Font("Arial", 20, FontStyle.Regular), Brushes.Black, 20,20);
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
But I want to print in tabular format that I have given. This code is not working.
Your printFont is a proportional font (Arial) and therefore will not work with your type of tabular formatting. You have two options:
Pick a fixed size font like Consolas. This will fix the problem without hassle.
Print those chunks you feed into your formatted string separately to their respective horizontal positions. This allows you to use any Font you like.
BTW: You write that you put the same text into a TextBox. It should have the same problems, but only the first option will work there without being a pain..!

c# - print RichTextBox text with correct spacing

I am making a program that can write in Bengali (a virtual keyboard) or in English. Everything was perfect until I started programming the printing. The user should be able to select any text and change the font and color. Because every character could be different, I need to print character by character. Here is my code:
private void printToolStripMenuItem_Click(object sender, EventArgs e)
{
PrintDialog print = new PrintDialog();
doc = new System.Drawing.Printing.PrintDocument();
print.Document = doc;
doc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(printDoc);
if (print.ShowDialog() == DialogResult.OK)
{
doc.Print();
}
}
private void printDoc(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.IO.StringReader reader = new System.IO.StringReader(richTextBox1.Text);
float linesPerPage = 0;
float yPosition = 0;
int count = 0;
float leftMargin = e.MarginBounds.Left;
float rightMargin = e.MarginBounds.Right;
float topMargin = e.MarginBounds.Top;
string line = null;
Font printFont = this.richTextBox1.Font;
SolidBrush printBrush = new SolidBrush(Color.Black);
int charpos = 0;
int xPosition = (int)leftMargin;
linesPerPage = e.MarginBounds.Height / printFont.GetHeight(e.Graphics);
while (count < linesPerPage && ((line = reader.ReadLine()) != null))
{
xPosition = (int)leftMargin;
yPosition = topMargin + (count * printFont.GetHeight(e.Graphics));
count++;
for (int i = 0; i < line.Length; i++)
{
richTextBox1.Select(charpos, 1);
if ((xPosition + ((int)e.Graphics.MeasureString(richTextBox1.SelectedText, richTextBox1.SelectionFont).Width)) > rightMargin)
{
count++;
if (!(count < linesPerPage))
{
break;
}
xPosition = (int)leftMargin;
yPosition = topMargin + (count * printFont.GetHeight(e.Graphics));
}
printBrush = new SolidBrush(richTextBox1.SelectionColor);
e.Graphics.DrawString(richTextBox1.SelectedText, richTextBox1.SelectionFont, printBrush, new PointF(xPosition, yPosition));
xPosition += ((int)e.Graphics.MeasureString(richTextBox1.SelectedText, richTextBox1.SelectionFont).Width);
charpos++;
}
}
if (line != null)
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false;
printBrush.Dispose();
}
}
However, when I get a print preview, it shows a space between each of the the characters:
I think this is because e.Graphics.MeasureString() is not giving me the tightest bounding box possible, or it's not giving me the exact width of the character as specified by the font. I'm quite new to C# Anyone know of a way to get the exact width of a character? It's been stumping me for a long time.
According to this MSDN article:
The (Graphics Class) MeasureString method is designed for use with individual string and includes a small amount of extra space before and after the string to allow for overhanging glyphs
You can instead use TextRenderer.MeasureString() to get the precise font width.
GOT IT. Finally. You need to use e.Graphics.MeasureString() after all. Just another overload of it. Use this:
e.Graphics.MeasureString(richTextBox1.SelectedText, richTextBox1.SelectionFont, new PointF(xPosition, yPosition), StringFormat.GenericTypographic).Width;
To remove the space you need to pass StringFormat.GenericTypographic. Hope it helps. (you can use my code for printing text with different color and text if you replace e.Graphics.MeasureString(string, Font) with the above).

Printing Multiple Pages in a Winform application

I am attempting to print something using a C# Winforms application. I can't seem to understand how multiple pages works. Let's say I have the following code in my constructor:
private string _stringToPrint;
_stringToPrint = "";
for (int i = 0; i < 120; i++)
{
_stringToPrint = _stringToPrint + "Line " + i.ToString() + Environment.NewLine;
}
Then I have this code on my button click event:
private void MnuFilePrintClick(object sender, EventArgs e)
{
var pd = new PrintDocument();
pd.PrintPage += pd_PrintPage;
var z = new PrintPreviewDialog { Document = pd };
z.ShowDialog(this);
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
var font = new Font("Arial", 10f, FontStyle.Regular);
g.DrawString(_stringToPrint, font, Brushes.Black, new PointF(10f, 10f));
}
Right now, when I run this code, it is giving me one page and after like 70 lines, it just runs off the paper. How would I print this string so that it prints enough for one page, then runs over to the second page, etc..?
You could have a counter and set the amount of lines you want per page like so:
private string[] _stringToPrint = new string[100]; // 100 is the amount of lines
private int counter = 0;
private int amtleft = _stringToPrint.Length;
private int amtperpage = 40; // The amount of lines per page
for (int i = 0; i < 120; i++)
{
_stringToPrint[i] ="Line " + i.ToString();
}
Then in pd_PrintPage:
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
int currentamt = (amtleft > 40)?40:amtleft;
Graphics g = e.Graphics;
var font = new Font("Arial", 10f, FontStyle.Regular);
for(int x = counter; x < (currentamt+counter); x++)
{
g.DrawString(_stringToPrint[x], font, Brushes.Black, new PointF(10f, (float)x*10));
// x*10 is just so the lines are printed downwards and not on top of each other
// For example Line 2 would be printed below Line 1 etc
}
counter+=currentamt;
amtleft-=currentamt;
if(amtleft<0)
e.HasMorePages = true;
else
e.HasMorePages = false;
// If e.HasMorePages is set to true and the 'PrintPage' has finished, it will print another page, else it wont
}
I have had bad experiences with e.HasMorePages so this may not work.
Let me know if this works and I hope it helps!

Categories

Resources