C# graphics, paint, picturebox centering - c#

Ok, so this is the problem: in C# forms I've created a new private void:
private void NewBtn(string Name, int x, int y)
Which has a purpose of creating a picturebox that imitates behavior of a button (don't ask why, I simply enjoy complicating things) and can be called as many times as I want.
Font btnFont = new Font("Tahoma", 16);
PictureBox S = new PictureBox();
S.Location = new System.Drawing.Point(x, y);
S.Paint += new PaintEventHandler((sender, e) =>
{
e.Graphics.TextRenderingHint =
System.Drawing.Text.TextRenderingHint.AntiAlias;
e.Graphics.DrawString(Name, btnFont, Brushes.Black, 0, 0);
});
Controls.Add(S);
Now, I am worried about part with Paint/Graphics (ignore rest of the code, I only gave some of it). I want to center the text that I write as "Name" in void when I call it "NewBtn(Name, x, y)". So, what should I put as
e.Graphics.DrawString(Name, btnFont, Brushes.Black, ThisX???, 0);
Suggestions?

var size = g.MeasureString(Name, btnFont);
e.Graphics.DrawString(Name, btnFont, Brushes.Black,
(S.Width - size.Width) / 2,
(S.Height - size.Height) / 2));
You can improve this by measuring the string only once, considering the font and text won't change for a specific Button/PictureBox.
And I would also suggest checking if S.Size is wider / taller than size and handling it, so graphics won't try to draw a string starting at negative coordinates.

Try using the Graphics.DrawString methods that uses the String.Drawing.StringFormat Option
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment= StringAlignment.Center;
drawFormat.LineAlignment = StringAlignment.Center;
You have two options here the first to use coordinates.
e.Graphics.DrawString(("Name", new Font("Arial", 16), Brushes.Black, 10, 10, drawFormat);
the second is to create a rectange like this:
e.Graphics.DrawString("Name", new Font("Arial", 16), Brushes.Black, new Rectangle(0,0,this.Width,this.Height), drawFormat);

Related

How to compute the correct width of a digit in pixels?

I have a custom control that may have user customizable Font in future (the zoom is already implemented). I must fill a rectangle under two digits that form a base-10 number. I have different colors for zero, one or both of the digits.
With the font {Name = Microsoft Sans Serif Size=16} and the following Graphics.MeasureString method calls:
g.MeasureString("00", Font);
g.MeasureString("0", Font);
I get:
The size of "00" is {Width = 31.5486088 Height = 26.8124962}
The size of "0" is {Width = 19.3298588 Height = 26.8124962}
The width of "0" is a lot bigger that half of the width of "00".
I know of the methods Graphics.MeasureString, it has many overloads, and I also know of the StringFormat class. How can I correctly compute the width of the '0' char?
Because the font will be user-customizable, I do not want to solve the problem using a monospace font.
If I use the following calls:
g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);
The width of "0" seems to be half of the width of "00", but the digits overlap when drawn with a smaller font size:
Update: In the OnPaint method of an UserControl I have this code:
Graphics g = e.Graphics;
int[] indices = { 0, 1 };
CharacterRange[] charRanges = new CharacterRange[indices.Length];
for (int chx = 0; chx < indices.Length; ++chx)
{
charRanges[chx] = new CharacterRange(indices[chx], 1);
}
StringFormat sf = new StringFormat(StringFormat.GenericDefault);
sf.SetMeasurableCharacterRanges(charRanges);
Region[] regions = e.Graphics.MeasureCharacterRanges("01", Font, e.ClipRectangle, sf);
RectangleF[] r = new RectangleF[regions.Length];
int i = 0;
foreach (Region rr in regions)
{
r[i] = rr.GetBounds(g);
g.DrawRectangle(Pens.Blue, r[i].X, r[i].Y, r[i].Width, r[i].Height);
++i;
}
g.DrawString("0", Font, Brushes.Black, r[0], sf);
g.DrawString("1", Font, Brushes.Black, r[1], sf);
The font is {Name = "Microsoft Sans Serif" Size=25}. When running the program, this is what is visible:
I want to make the digits centered in the blue rectangles. The rectangles must be as big as possible in the UserControl but also leaving space for a percent of the Height of the UserControl. The Font should adapt to the rectangles.
Small adjustments are required to make this work as intended:
TextRenderingHint.ClearTypeGridFit gives a better result when rendering the Text.
It's more precise and works well with the grid-fitting nature of Graphics.DrawString.
See the notes you can find in the answer linked below for more informations on this matter.
StringFormat alignment in both horizontal and vertical dimensions.
A modified method that allows to draw strings of any length.
If the string is larger than the container, it will be wrapped, with the current settings.
Irrelevant: Brush and Pen are declared outside the Paint event, to allow their re-definition when required.
Different implementations of MeasureCharacterRanges here:
How to highlight wrapped text in a control
About Graphics.DrawString and TextRenderingHint.ClearTypeGridFit:
Drawing a Long String on to a Bitmap results in Drawing Issues
Font 48em:
Font 16em:
Font 9em:
Pen pen = new Pen(Color.LightGreen, 1);
Brush brush = new SolidBrush(Color.White);
string sourceDigits = "010011001";
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
CharacterRange[] charRanges = new CharacterRange[sourceDigits.Length];
for (int chx = 0; chx < sourceDigits.Length; ++chx) {
charRanges[chx] = new CharacterRange(chx, 1);
}
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.SetMeasurableCharacterRanges(charRanges);
Region[] regions = e.Graphics.MeasureCharacterRanges(sourceDigits, Font, e.ClipRectangle, sf);
for (int i = 0; i < regions.Length; i++) {
RectangleF rect = regions[i].GetBounds(e.Graphics);
e.Graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
e.Graphics.DrawString(char.ToString(sourceDigits[i]), Font, brush, rect, sf);
}
}
}

Winforms Transformation

The current application am developing has lot of drawings. The Origin of the drawing start from Left,Bottom instead of Top,Left. Drawings works perfectly except "DrawingString".
Graphics g;
g.TranslateTransform(0, Height);
g.ScaleTransform(1, -1);
//All drawings
g.DrawString("1", new Font("Segoei UI", 9), Brushes.Green, new Point(x, y));
The result I get is upside down Text [![enter image description here][1]][1]
I wanted to draw only the text normal and rest of the drawings should always start from the bottom left?
EDIT
private void panel1_Paint(object sender,PaintEventArgs e)
{
var g = e.Graphics;
var height = panel1.Height;
g.TranslateTransform(0,height);
g.ScaleTransform(1,-1);
g.DrawRectangle(new Pen(Brushes.Black,1),new Rectangle(10,10,100,100));
g.DrawString("Test",new Font("Segoei UI",9),Brushes.Green,new Point(10,110));
}
RESULT
I want only the text to be flipped. Keeping the drawing as it is
Flip it over again.
See the example below. The text Sunday appears normally. Then we transpose the graphics object's matrix and write Monday, so Monday appears laterally inverted on the Y-axis, and finally we flip over the Y-axis yet again so it restores itself to its original state before writing Tuesday, which appears normally.
private void Form1_Paint(object sender, PaintEventArgs e)
{
var graphics = e.Graphics; // this.CreateGraphics();
var font = new Font("Georgia", 12.0F);
var brush = new SolidBrush(Color.Black);
var pointF = new PointF(20F, 20F);
graphics.DrawString("Sunday", font, brush, pointF);
graphics.ScaleTransform(1F, -1F);
pointF = new PointF(10F, -210F);
graphics.DrawString("Monday", font, brush, pointF);
graphics.ScaleTransform(1, -1);
pointF = new PointF(200F, 200F);
graphics.DrawString("Tuesday", font, brush, pointF);
brush.Dispose();
font.Dispose();
}
Do that in your code, making sure to calculate the value of the Y-axis where you want your text to appear.
g.ScaleTransform(1,-1);
g.DrawRectangle(new Pen(Brushes.Black,1),new Rectangle(10,10,100,100));
g.ScaleTransform(1,-1);
g.DrawString("Test",new Font("Segoei UI",9),Brushes.Green,new Point(10, -110));

Right-Aligning printed text

I'm working on printing a receipt right now, but I can't figure out how to right align text in graphics mode. I've tried a couple different things, but they're either really inefficient or don't work in my situation. Is there a way I can easily align text like to the right? Here's my code right now.
using (Font printFont = new Font("Courier New", 9.0f))
{
e.Graphics.DrawString("Subtotal:", printFont, Brushes.Black, leftMargin + 80, HeightToPrint, new StringFormat());
e.Graphics.DrawString(subtotal.ToString(), printFont, Brushes.Black, leftMargin + 150, HeightToPrint, new StringFormat());
}
In order for it to be able to right align the text, you need to specify a layout rectangle:
var format = new StringFormat() { Alignment = StringAlignment.Far };
var rect = new RectangleF( x, y, width, height );
e.Graphics.DrawString( text, font, brush, rect, format );
And it will then align the string within that rectangle.
Use the Graphics.MeasureString Method to get how long the rendered string will be and draw it at rightMargin - measuredStringWidth.

How to find string's width in C# (in pixels)

I'm trying to achieve framed texts (using Windows Forms), e.g.:
Height is always the same, because my strings are less than 20 chars. What about width? Is there any way to get it automatically?
Use Graphics.MeasureString()
From MSDN: http://msdn.microsoft.com/en-us/library/6xe5hazb.aspx
private void MeasureStringMin(PaintEventArgs e)
{
// Set up string.
string measureString = "Measure String";
Font stringFont = new Font("Arial", 16);
// Measure string.
SizeF stringSize = new SizeF();
stringSize = e.Graphics.MeasureString(measureString, stringFont);
// Draw rectangle representing size of string.
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);
// Draw string to screen.
e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0));
}
If you don't feel like dealing with the Paint eventhandler, you could try the TextRenderer class. It has a static method that is identical to the "MeasureString" method in the above answer. In this class it is called MeasureText however.

Graphics.DrawString - Incorrect drawing of Combining Diacritical Marcs

I'm trying to draw text, which contains symbols from "Combining Diacritical Marcs" unicode subrange (U+0300 - U+FE23). For example i tried to draw string "T̅", wich contains of two characters: 'T' and '\u0305'.
I've got that:
Is there any way to get correct text?
Addition: I need to draw rotated text too.
PS: my code:
private void Form1_Paint(object sender, PaintEventArgs e) {
Graphics g = e.Graphics;
Font fontTahoma = new Font("Tahoma", 16);
Font fontTimesNewRom = new Font("Times New Romulan", 16);
Font fontArial = new Font("Arial", 16);
Brush brush = new SolidBrush(Color.Red);
g.DrawString("Test1 T̅ T\u0305", fontTahoma, brush, new PointF(20, 20));
g.DrawString("Test1 T̅ T\u0305", fontTimesNewRom, brush, new PointF(20, 40));
g.DrawString("Test1 T̅ N\u0305", fontArial, brush, new PointF(20, 60));
}
TextRenderer seems to draw it better:
TextRenderer.DrawText(g, "Test1 T̅ T\u0305", fontTahoma,
new Point(120, 20), Color.Black);

Categories

Resources