I have a function that I use to createan array of points, so I can draw a polygon, I want to label inside of this polygons, I know it can be done using drawstring or label control, but I want to make sure I have the same orientation of the polygon in my case they are rectangles also control the font size depend on the shape size.
I tried to create a rect inside the Draw string didn't work, any Ideas
private void BuildImage()
{
Graphics refGraph = this.CreateGraphics();
IntPtr hdc = refGraph.GetHdc();
Metafile image = new Metafile(hdc, EmfType.EmfOnly, "Shapes");
using (var g = Graphics.FromImage(image))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
SolidBrush myBrush = new SolidBrush(Color.Black);
Pen p = new Pen(Color.Red, 0.2f);
foreach (CircuitData.ResistorRow resistorRow in ResistorData.Resistor)
{
RectangleF rec = new RectangleF((float)(resistorRow.CenterX - resistorRow.Length / 2), (float)(resistorRow.CenterY - resistorRow.Width / 2), (float)resistorRow.Length, (float)resistorRow.Width);
float orientation = 360 - (float)resistorRow.Orientation;
PointF center = new PointF((float)resistorRow.CenterX, (float)resistorRow.CenterY);
PointF[] points = CreatePolygon(rec, center, orientation);
if (!Double.IsNaN(resistorRow.HiX) && !Double.IsNaN(resistorRow.HiY))
{
g.FillEllipse(myBrush, (float)resistorRow.HiX - 0.5f, (float)resistorRow.HiY - 0.5f, 1, 1);
g.DrawLine(p, new PointF((float)resistorRow.HiX, (float)resistorRow.HiY), center);
}
g.FillPolygon(myBrush, points);
Font drawFont = new Font("cursor", 1);
SolidBrush textBrush = new SolidBrush(Color.Blue);
//g.Transform = matrix;
g.DrawString(resistorRow.ComponentName, drawFont, textBrush, points[0]);
}
}
refGraph.ReleaseHdc(hdc);
refGraph.Dispose();
Image = image;
}
private PointF[] CreatePolygon(RectangleF rec, PointF center, float orientation)
{
PointF TL = new PointF(rec.Left, rec.Top);
PointF TR = new PointF(rec.Right, rec.Top);
PointF BL = new PointF(rec.Left, rec.Bottom);
PointF BR = new PointF(rec.Right, rec.Bottom);
PointF[] points = new PointF[] { BL, TL, TR, BR, BL };
matrix = new System.Drawing.Drawing2D.Matrix();
matrix.RotateAt(orientation, center);
matrix.TransformPoints(points);
return points;
}
Apply your rotation matrix to the graphic context you're working with:
e.Graphics.Transform = matrix;
e.Graphics.FillPolygon(textBrush, points);
e.Graphics.DrawString(resistorRow.ComponentName, drawFont, textBrush2, TL);
EDIT: Some sample code:
public class ResistorWithLabel
{
public string ComponentName { get; set; }
public RectangleF Rect { get; set; }
public float Orientation { get; set; }
public Color BackgroundColor { get; set; }
public Color ForegroundColor { get; set; }
public int FontSize { get; set; }
public void Draw(Graphics g)
{
Matrix contextMatrix = g.Transform;
Matrix matrix = new Matrix();
matrix.RotateAt(Orientation, new PointF((Rect.Left+Rect.Right)/2, (Rect.Top+Rect.Bottom)/2));
SolidBrush polygonBrush = new SolidBrush(BackgroundColor);
SolidBrush textBrush = new SolidBrush(ForegroundColor);
Font font = new Font("Courier", FontSize);
PointF TL = new PointF(Rect.Left, Rect.Top);
PointF TR = new PointF(Rect.Right, Rect.Top);
PointF BL = new PointF(Rect.Left, Rect.Bottom);
PointF BR = new PointF(Rect.Right, Rect.Bottom);
PointF[] points = new PointF[] { BL, TL, TR, BR };
g.Transform = matrix;
g.FillPolygon(polygonBrush, points);
g.DrawString(ComponentName, font, textBrush, TL);
g.Transform = contextMatrix;
}
}
private void Form3_Paint(object sender, PaintEventArgs e)
{
ResistorWithLabel r1 = new ResistorWithLabel();
r1.ComponentName = "Resistor 1";
r1.Rect = new RectangleF(50, 100, 100, 50);
r1.Orientation = 25;
r1.BackgroundColor = Color.Blue;
r1.ForegroundColor = Color.Yellow;
r1.FontSize = 16;
r1.Draw(e.Graphics);
ResistorWithLabel r2 = new ResistorWithLabel();
r2.ComponentName = "Resistor 2";
r2.Rect = new RectangleF(200, 100, 200, 100);
r2.Orientation = 75;
r2.BackgroundColor = Color.Gray;
r2.ForegroundColor = Color.Orange;
r2.FontSize = 32;
r2.Draw(e.Graphics);
}
Related
how can i draw an arror to show the direction of line ? i manage to do but the arrow not in the right shape.
//For Line
Point point1 = new Point(100, 110);
Point point2 = new Point(300, 210);
Point point3 = new Point(200, 310);
Point point4 = new Point(100,310);
e.Graphics.DrawLines(pen, points);
//For Arrow
e.Graphics.DrawLine(pen, 200, 150, 180, 130);
e.Graphics.DrawLine(pen, 200, 150, 180, 150);
Another example:
Produced by:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Point[] points = {
new Point(100, 110),
new Point(300, 210),
new Point(200, 310),
new Point(100, 310)
};
for(int i=0; i<(points.Length-1); i++)
{
Point p1 = points[i];
Point p2 = points[i + 1];
e.Graphics.DrawLine(Pens.Black, p1, p2);
float angle = getAngle(p1, p2);
Point mid = getMidPoint(p1, p2);
e.Graphics.TranslateTransform(mid.X, mid.Y);
e.Graphics.RotateTransform(angle);
e.Graphics.RotateTransform(135);
e.Graphics.DrawLine(Pens.Black, new Point(0, 0), new Point(8, 0));
e.Graphics.RotateTransform(-270);
e.Graphics.DrawLine(Pens.Black, new Point(0, 0), new Point(8, 0));
e.Graphics.ResetTransform();
}
}
private float getAngle(Point p1, Point p2)
{
float deltaX = p2.X - p1.X;
float deltaY = p2.Y - p1.Y;
return (float)(Math.Atan2(deltaY, deltaX) * 180.0 / Math.PI);
}
private Point getMidPoint(Point p1, Point p2)
{
return new Point((p1.X + p2.X)/2,(p1.Y+p2.Y)/2);
}
I think you want something like this:
and here is the code to do it:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.pictureBox1.Paint += PictureBox1_Paint;
}
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
for (int i = 0; i < 5; i++)
{
DrawLineWithArrow(e.Graphics,
Color.Blue,
new PointF(50, 50),
new PointF(340, 120+35*i),
4f+3f*i, false);
DrawLineWithArrow(e.Graphics,
Color.Red,
new PointF(340, 120+35*i),
new PointF(340+290, 50),
4f+3f*i, true);
}
}
public void DrawLineWithArrow(Graphics g, Color color, PointF start, PointF end, float arrowSize=8f, bool filled = false)
{
if (start==end) return;
PointF mid = new PointF((start.X+end.X)/2, (start.Y+end.Y)/2);
float angle = (float)(180/Math.PI*Math.Atan2(end.Y-start.Y, end.X-start.X));
var gp = new GraphicsPath();
gp.AddLines(
new PointF[]
{
new PointF(-arrowSize, -arrowSize/3),
new PointF(0, 0),
new PointF(-arrowSize, arrowSize/3)
}
);
if (filled)
{
gp.CloseFigure();
}
var state = g.Save();
using (Pen pen = new Pen(color, 0))
{
g.DrawLine(pen, start, end);
g.TranslateTransform(
mid.X,
mid.Y);
g.RotateTransform(angle);
if (filled)
{
using (Brush fill = new SolidBrush(color))
{
g.FillPath(fill, gp);
}
}
g.DrawPath(pen, gp);
}
g.Restore(state);
}
}
I took advantage of Graphics.TranslateTransform() and Graphics.RotateTransform() to move and align the coordinate system in the middle of the line and along the line. The drawing of the arrow is much simpler than trying to do vector rotations by hand.
Here's what I do to Rotate and Scale. But so far, if the rotation is working, the scaling isn't and vice versa. So how do I combine rotation and scaling in one method? I feels like they can't coexist using my code.
....................................................................................................................................................................
Here's what I have for now:
Image Drawing:
public LayerClass ImageDrawing(LayerClass.Type img, Bitmap bm, Rectangle imgRect, String filepath, int angle, PaintEventArgs e)
{
bm = ImageClass.GrayscaleImage(bm);
bm = MakeTransparentImage(bm);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
bm = RotateImage(bm, angle, imgRect);
imgRect = new Rectangle((int)(Shape.center.X - (bm.Width / 2)), (int)(Shape.center.Y - (bm.Height / 2)), (int)bm.Width, (int)bm.Height);
e.Graphics.DrawImage(bm, imgRect);
this.imageBitmap = bm;
this.filePath = filePath;
this.rotationAngle = angle;
this.location = location;
this.imageRect = imgRect;
return new LayerClass(LayerClass.Type.Image, this, filePath, imgRect);
}
Rotation:
public static Bitmap RotateImage(Bitmap bitmap, float angle, Rectangle rect)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;
rect = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(resultBitmap))
{
Matrix matrix2 = new Matrix();
matrix2.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
g.Transform = matrix2;
g.DrawImage(bitmap, points);
return resultBitmap;
}
}
}
Scaling:
private void trackBar_ScaleImg_Scroll(object sender, EventArgs e)
{
if(rb_BothImage.Checked)
{
if (imgRect.Width > imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Height > imgRect.Width)
{
imgRect.Height = trackBar_ScaleImg.Value; //64mm
imgRect.Width = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Width == imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = trackBar_ScaleImg.Value;
}
imgRect.X = (int)(Shape.center.X - (imgRect.Width / 2));
imgRect.Y = (int)(Shape.center.Y - (imgRect.Height / 2));
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
pictureBox_Canvass.Invalidate();
}
You can add another matrix transformation for scaling: matrix.Scale(2, 2, MatrixOrder.Append);
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
matrix.Scale(2, 2, MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
I'm trying to save rectangles into a list and repaint them all with different stroke thicknesses. What actually happens is that I can create many rectangles as long as I want, but those rectangles have the same stroke thickness.
I really need help before I try recreating the project with a new approach. I have no idea how.
Here's my code:
Form 1 Paint Event where it redraws all shapes
public void PaintAll(object sender, PaintEventArgs e)
{
foreach(Rectangle rects in d._rect)
{
foreach (Pen p in _penRect)
{
e.Graphics.DrawRectangle(p, rects.X, rects.Y, rects.Width, rects.Height);
}
}
foreach (Rectangle squares in d._square)
{
foreach (Pen p in _penSquare)
{
e.Graphics.DrawRectangle(p, squares.X, squares.Y, squares.Width, squares.Height);
}
}
foreach (Rectangle circles in d._circle)
{
foreach (int x in _StrokeCircle)
{
Pen p = new Pen(Color.Black, x);
//Aliasing for smooth graphics when drawing and resizing
e.Graphics.InterpolationMode = InterpolationMode.High;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(p, circles.X, circles.Y, circles.Width, circles.Height);
}
}
foreach (Rectangle ellipses in d._ellipse)
{
foreach (int x in _StrokeEllipse)
{
Pen p = new Pen(Color.Black, x);
//Aliasing for smooth graphics when drawing and resizing
e.Graphics.InterpolationMode = InterpolationMode.High;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(p, ellipses.X, ellipses.Y, ellipses.Width, ellipses.Height);
}
}
}
Draw Class
class Draw:ShapeClass
{
public List<Rectangle> _rect = new List<Rectangle>();
public List<Rectangle> _square = new List<Rectangle>();
public List<Rectangle> _circle = new List<Rectangle>();
public List<Rectangle> _ellipse = new List<Rectangle>();
public void DrawRectangle(PaintEventArgs e)
{
e.Graphics.InterpolationMode = InterpolationMode.High;
color = new Pen(brush, Stroke);
e.Graphics.DrawRectangle(color, new Rectangle(x, y, width, height));
}
public void DrawSquare(PaintEventArgs e)
{
e.Graphics.InterpolationMode = InterpolationMode.High;
color = new Pen(brush, Stroke);
e.Graphics.DrawRectangle(color, new Rectangle(x, y, width, height));
}
public void DrawCircle(PaintEventArgs e)
{
//Aliasing for smooth graphics when drawing and resizing
e.Graphics.InterpolationMode = InterpolationMode.High;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(color, new Rectangle(x,y,width,height));
}
public void DrawEllipse(PaintEventArgs e)
{
//Aliasing for smooth graphics when drawing and resizing
e.Graphics.InterpolationMode = InterpolationMode.High;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(color, new Rectangle(x, y, width, height));
}
public void DrawTriangle(PaintEventArgs e)
{
tPoints = new PointF[3];
float angle = 0;
tPoints[0].X = x;
tPoints[0].Y = y;
tPoints[1].X = (float)(x + width * Math.Cos(angle));
tPoints[1].Y = (float)(y + width * Math.Sin(angle));
tPoints[2].X = (float)(x + width * Math.Cos(angle - Math.PI / 3));
tPoints[2].Y = (float)(y + width * Math.Sin(angle - Math.PI / 3));
e.Graphics.InterpolationMode = InterpolationMode.High;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawPolygon(color,tPoints);
}
}
I've run into an issue with drawing text and basic graphic drawing operations not having the proper placement & quality when the drawing matrix has large offset values. I've tried number SmoothMode, InterpolationMode, & TextRenderingHint options with no luck.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public void RenderImageClosePointDrawing()
{
float x = 68336, y = 99460;
PointF anchorPoint = new PointF(17494176, 25461836);
PointF anchorPoint2= new PointF(17494076, 25461836);
string textLabel = "9318";
float textFontSize = 20;
float symbolsize = 34;
string fontFamly = "Arial";
Bitmap bitmap = new Bitmap(256, 256);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
graphics.Transform = new Matrix(1, 0, 0, 1, -x * 256, -y * 256);
//Draw the circle
Pen polyPen = new Pen(new SolidBrush(Color.Black), 2);
Brush polyBrush = new SolidBrush(Color.Teal);
graphics.DrawEllipse(polyPen, anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
graphics.FillEllipse(polyBrush, anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
RectangleF drawnArea = new RectangleF(anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
Pen polyPen2 = new Pen(new SolidBrush(Color.Black), 1);
Brush polyBrush2 = new SolidBrush(Color.Teal);
graphics.DrawEllipse(polyPen2, anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
graphics.FillEllipse(polyBrush2, anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
RectangleF drawnArea2 = new RectangleF(anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
Pen polyPen3 = new Pen(new SolidBrush(Color.Red), 1);
graphics.DrawRectangle(polyPen3, drawnArea.X, drawnArea.Y, drawnArea.Width, drawnArea.Height);
graphics.DrawRectangle(polyPen3, drawnArea2.X, drawnArea2.Y, drawnArea2.Width, drawnArea2.Height);
//Draw the text
Pen textOutlinePen = new Pen(new SolidBrush(Color.Orange), (float)4);
textOutlinePen.EndCap = LineCap.Round;
textOutlinePen.LineJoin = LineJoin.Round;
textOutlinePen.MiterLimit = 0;
Brush textFillBrush = new SolidBrush(Color.Teal);
FontFamily textFontFamily = new FontFamily(fontFamly);
PointF textAnchor = new PointF(anchorPoint.X, anchorPoint.Y);
ShiftTextAnchor_NW(textLabel, textFontSize, ref drawnArea, textFontFamily, ref textAnchor);
var textPath = new GraphicsPath();
textPath.AddString(textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor,
new StringFormat()
);
graphics.DrawPath(textOutlinePen, textPath);
graphics.FillPath(textFillBrush, textPath);
//Draw the text2
Pen textOutlinePen2 = new Pen(new SolidBrush(Color.Orange), (float)1);
textOutlinePen.EndCap = LineCap.Round;
textOutlinePen.LineJoin = LineJoin.Round;
textOutlinePen.MiterLimit = 0;
PointF textAnchor2 = new PointF(anchorPoint2.X, anchorPoint2.Y);
ShiftTextAnchor_NW(textLabel, textFontSize, ref drawnArea2, textFontFamily, ref textAnchor2);
var textPath2 = new GraphicsPath();
textPath2.AddString(textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor2,
new StringFormat()
);
graphics.DrawPath(textOutlinePen2, textPath2);
graphics.FillPath(textFillBrush, textPath2);
}
bitmap.Save(#"C:\ClosePointDrawing.png", ImageFormat.Png);
}
private static void ShiftTextAnchor_NW(string textLabel, float textFontSize, ref RectangleF drawnArea, FontFamily textFontFamily, ref PointF textAnchor)
{
GraphicsPath tempPath = new GraphicsPath();
tempPath.AddString(
textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor,
new StringFormat()
);
var textBounds = tempPath.GetBounds();
var offsetX = textBounds.X - textAnchor.X;
var offsetY = textBounds.Y - textAnchor.Y;
textAnchor = new PointF(drawnArea.Left - (textBounds.Width + offsetX), drawnArea.Top - (textBounds.Height + offsetY));
}
When you run this code you'll get this for output: ClosePointDrawing.png
You'll notice that the text doesn't not look nice (distorted some) and also that the Black stroke outline around the circle is only lined up properly with its Teal color filled circle with the one on the left when using a 1 pixel stroke. The one on the right uses a 2 pixel stroke. You'll also see that the Red Squares are not lined up with the Teal Circle, they should be completely encapsulating it.
Now if you change the first few values in the code so that it doesn't use a large offset as follows:
float x = 0, y = 0;
PointF anchorPoint = new PointF(150, 50);
PointF anchorPoint2 = new PointF(50, 50);
You'll get this for output: ClosePointDrawing2.png
Notice that the Text looks much better, and that the strokes are perfectly lined up with the filled circles as well as the red squares.
Is there anything that can be done, so that it will render it properly with the larger matrix?
I'm trying to draw Right-Aligned text in a custom control, however, it seems for some reason it doesn't align to my target horizontal position and there's a difference between strings.
I can live with the fact that it doesn't exactly matches my target horizontal position, but the difference between strings is visually awful!
Any pointers?
The isolated code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace RightAlignTest {
class RightControlTest : UserControl {
public RightControlTest() {
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
public static void DrawString(Graphics g, string s, Font f, RectangleF r, Color c) {
float locx = r.Left;
float locy = r.Top;
SizeF txts = g.MeasureString(s, f);
locx = (locx + r.Width - txts.Width);
g.DrawString(s, f, new SolidBrush(c), locx, locy);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
int rightTarget = Width - 20;
Font f = new Font("Arial Unicode MS", 13f, FontStyle.Regular);
int i = 0;
string[] strings = { "Current Limit 1:", "Current Limit 2:", "Temperature Center 1:", "Temperature Center 2:" };
foreach (var s in strings) {
Rectangle r1 = new Rectangle(0, 30 * i++, rightTarget, Height);
DrawString(e.Graphics, s, f, r1, Color.Black);
}
e.Graphics.DrawLine(new Pen(new SolidBrush(Color.Blue)), rightTarget, 0, rightTarget, Height);
}
}
public partial class Form1 : Form {
public Form1() {
RightControlTest t = new RightControlTest();
t.Dock = DockStyle.Fill;
Controls.Add(t);
}
}
}
Try if this works:
public static void DrawString(
Graphics g, string s, Font f,
RectangleF r, Color c)
{
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Far;
stringFormat.LineAlignment = StringAlignment.Center; // Not necessary here
g.DrawString(s, f, new SolidBrush(c), r, stringFormat);
}
using StringFormat example taken from http://msdn.microsoft.com/en-us/library/332kzs7c.aspx
Use StringFormat.SetTabStop(int,float[]), like this:
private void PrintPage_Print(object sender, PrintPageEventArgs e)
{
using (Font f = new Font("Segoe UI", 10f, FontStyle.Regular, GraphicsUnit.Point))
{
using (Brush b = new SolidBrush(Color.Black))
{
using (Graphics g = e.Graphics)
{
float y = 5;
string headLine = "Article\tUnit\tNet\tGross";
Pen pen = new Pen(b);
SizeF measure = g.MeasureString(headLine, f);
StringFormat format = new StringFormat();
float[] tabs = new float[] { 200, 100, 55, 55};
Rectangle rect = new Rectangle(5, (int)y, (int)(tabs.Sum()+5), (int)measure.Height);
format.SetTabStops(0, tabs);
g.DrawString(headLine, f, b, rect, format);
g.DrawRectangle(pen, rect);
y += rect.Height + 3f;
format.LineAlignment = StringAlignment.Far;
foreach (var product in Bill.ListPositions())
{
measure = g.MeasureString(product.PositionString, f);
rect = new Rectangle(5, (int)y, (int)(tabs.Sum()+5), (int)measure.Height);
g.DrawString(product.PositionString, f, b, rect, format);
y += measure.Height + 2f;
}
g.DrawLine(pen, new Point(0, (int)y), new Point((int)(tabs.Sum()), (int)y));
tabs = new float[] { 300, 110 };
format.LineAlignment = StringAlignment.Near;
format.SetTabStops(0, tabs);
foreach (var line in DrawTotalSummaryLines())
{
measure = g.MeasureString(line, f);
rect = new Rectangle(5, (int)y, (int)(tabs.Sum()+5), (int)measure.Height);
g.DrawString(line, f, b, rect, format);
y += measure.Height + 2f;
if (line.Contains("Gross:") ||line.Contains("CHANGE:"))
{
g.DrawLine(pen, new Point(0, (int)y), new Point((int)(tabs.Sum()), (int)y));
y += measure.Height + 2f;
}
}
g.Dispose();
pen.Dispose();
}
b.Dispose();
}
f.Dispose();
}
The result should look like this: