I found a code that allows rounded corners to be placed on forms, however, this code happens within the form itself I would like to do this in a class to make it cleaner, but it turns out that when I call I can't make the form receive the values.
Here my class file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace cornersroundedTest
{
public class ProgramGraphics : Form
{
protected override void OnPaintBackground(PaintEventArgs e)
{
Rectangle rc = new Rectangle(0, 0, this.ClientSize.Width + 1, this.ClientSize.Height + 1);
using (LinearGradientBrush brush = new LinearGradientBrush(rc, Color.LightGreen, Color.WhiteSmoke, 45F))
{
e.Graphics.FillRectangle(brush, rc);
}
}
public void SetWindowRegion()
{
System.Drawing.Drawing2D.GraphicsPath FormPath;
FormPath = new System.Drawing.Drawing2D.GraphicsPath();
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
FormPath = GetRoundedRectPath(rect, 30); // 30 represents the size of the fillet angle
this.Region = new Region(FormPath);
}
private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
{
int diameter = radius;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
GraphicsPath path = new GraphicsPath();
path.AddArc(arcRect, 180, 90); // top left
arcRect.X = rect.Right - diameter;//top right
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter; // buttom right
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left; // button left
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
private static GraphicsPath GetRoundRectangle(Rectangle rectangle, int r)
{
int l = 2 * r;
// Divide the rounded rectangle into a combination of straight lines and arcs, and add them to the path in turn
GraphicsPath gp = new GraphicsPath();
gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F);
gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F);
gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F);
gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F);
return gp;
}
public void FillRoundRectangle(Graphics g, Rectangle rectangle, Pen pen, int r)
{
rectangle = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
g.DrawPath(pen, GetRoundRectangle(rectangle, r));
}
private void OnpaintForm(object sender, PaintEventArgs e)
{
SetWindowRegion();
Pen pen = new Pen(Color.Blue, 3);
pen.DashStyle = DashStyle.Solid;
Rectangle rectangle = new Rectangle(1, 1, this.Width - 2, this.Height - 2);
FillRoundRectangle(e.Graphics, rectangle, pen, 14);
}
}
}
This code was separated To be called by the form file name: ProgramGraphics it was typed as type form.
Now the normal code inside the form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace cornersroundedTest
{
public partial class Form1 : Form
{
private Timer drawTimer = new Timer();
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
Rectangle rc = new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height);
using (LinearGradientBrush brush = new LinearGradientBrush(rc, Color.LightGreen, Color.WhiteSmoke, 45F))
{
e.Graphics.FillRectangle(brush, rc);
}
}
public void SetWindowRegion()
{
System.Drawing.Drawing2D.GraphicsPath FormPath;
FormPath = new System.Drawing.Drawing2D.GraphicsPath();
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
FormPath = GetRoundedRectPath(rect, 30); // 30 represents the size of the fillet angle
this.Region = new Region(FormPath);
}
private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
{
int diameter = radius;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
GraphicsPath path = new GraphicsPath();
path.AddArc(arcRect, 180, 90); // top left
arcRect.X = rect.Right - diameter;//top right
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter; // buttom right
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left; // button left
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
private static GraphicsPath GetRoundRectangle(Rectangle rectangle, int r)
{
int l = 2 * r;
// Divide the rounded rectangle into a combination of straight lines and arcs, and add them to the path in turn
GraphicsPath gp = new GraphicsPath();
gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F);
gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r));
gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F);
gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F);
gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r));
gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F);
return gp;
}
public void FillRoundRectangle(Graphics g, Rectangle rectangle, Pen pen, int r)
{
rectangle = new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
g.DrawPath(pen, GetRoundRectangle(rectangle, r));
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Blue, 3);
pen.DashStyle = DashStyle.Solid;
Rectangle rectangle = new Rectangle(1, 1, this.Width - 2, this.Height - 2);
FillRoundRectangle(e.Graphics, rectangle, pen, 14);
}
private void Form1_Load(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Normal)
{
SetWindowRegion();
}
else
{
this.Region = null;
}
}
}
}
I would just like to separate the code above that works within a class and call the attributes of the class so that they can be applied to any form in the project. Any tips on how to do this? I've already tried to create and call methods and even use public methods and nothing, the only result is the creation within a form to a sender , and in Onpaint and even then it only generated results in the form not in its corner.
Another approach ("cheat to win" LOL) is to use the Form.TransparencyKey property where this:
plus this:
runs as this:
Yeah, "this is what I learned."
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.
I was trying to make a normal rounding. And I can't smooth out the rounding itself for the button.
And the second question, how do I round off the button so that the photo that is used in BackgroundImage doesn't get rounded off???
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Test_Project.SupportClass
{
public class Buttom_Class4 : Button
{
public Buttom_Class4()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
}
private int radius = 20;
[DefaultValue(20)]
public int Radius
{
get { return radius; }
set
{
radius = value;
this.RecreateRegion();
}
}
private GraphicsPath GetRoundRectagle(Rectangle bounds, int radius)
{
GraphicsPath path = new GraphicsPath();
path.AddArc(bounds.X, bounds.Y, radius, radius, 180, 90);
path.AddArc(bounds.X + bounds.Width - radius, bounds.Y, radius, radius, 270, 90);
path.AddArc(bounds.X + bounds.Width - radius, bounds.Y + bounds.Height - radius,
radius, radius, 0, 90);
path.AddArc(bounds.X, bounds.Y + bounds.Height - radius, radius, radius, 90, 90);
path.CloseAllFigures();
return path;
}
private void RecreateRegion()
{
var bounds = ClientRectangle;
bounds.Width--; bounds.Height--;
using (var path = GetRoundRectagle(bounds, this.Radius))
this.Region = new Region(path);
this.Invalidate();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
this.RecreateRegion();
}
}
}
Both labels have AutoSize true & TextAlign MiddleCenter.
How can also label2 show smooth borders?
Here is the test code for handlers Form.Load(...) & Form.Paint(...):
int _cornerRadius = 10;
Point _locationLabel2;
// Form.Load(...)
private void Form3_Load(object sender, EventArgs e)
{
// Step 1: Cut the label regions (seems to be ok, result is the same for both labels)
GraphicsPath graphicsPath = _getRoundPath(label1.ClientRectangle, _cornerRadius);
label1.Region = new Region(graphicsPath);
graphicsPath = _getRoundPath(label2.ClientRectangle, _cornerRadius);
label2.Region = new Region(graphicsPath);
_locationLabel2 = this.PointToClient(label2.Parent.PointToScreen(label2.Location));
}
// Form.Paint(...)
private void Form3_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(label1.BackColor, 3.0f))
{
// Step 2: Smooth the label borders (ok only for label1)
_drawRoundedRectangle(e.Graphics, pen, label1.Location.X, label1.Location.Y,
label1.ClientRectangle.Width, label1.ClientRectangle.Height, _cornerRadius);
_drawRoundedRectangle(e.Graphics, pen, _locationLabel2.X, _locationLabel2.Y,
label2.ClientRectangle.Width, label2.ClientRectangle.Height, _cornerRadius);
}
}
// Helper 1/3
private static GraphicsPath _getRoundPath(Rectangle rectangle, int radius)
{
int x = rectangle.X;
int y = rectangle.Y;
int width = rectangle.Width;
int height = rectangle.Height;
radius = radius << 1;
GraphicsPath path = new GraphicsPath();
if (radius > 0)
{
if (radius > height) radius = height;
if (radius > width) radius = width;
path.AddArc(x, y, radius, radius, 180, 90);
path.AddArc(x + width - radius, y, radius, radius, 270, 90);
path.AddArc(x + width - radius, y + height - radius, radius, radius, 0, 90);
path.AddArc(x, y + height - radius, radius, radius, 90, 90);
path.CloseFigure();
}
else
{
path.AddRectangle(rectangle);
}
return path;
}
// Helper 2/3
private void _drawRoundedRectangle(Graphics graphics, Pen pen, int x, int y, int width, int height, int radius)
{
RectangleF rectangle = new RectangleF(x, y, width, height);
GraphicsPath path = _generateRoundedRectangle(graphics, rectangle, radius);
SmoothingMode old = graphics.SmoothingMode;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.DrawPath(pen, path);
graphics.SmoothingMode = old;
}
// Helper 3/3
private static GraphicsPath _generateRoundedRectangle(Graphics graphics, RectangleF rectangle, int radius)
{
GraphicsPath path = new GraphicsPath();
float diameter = radius * 2.0F;
SizeF sizeF = new SizeF(diameter, diameter);
RectangleF arc = new RectangleF(rectangle.Location, sizeF);
path.AddArc(arc, 180, 90);
arc.X = rectangle.Right - diameter;
path.AddArc(arc, 270, 90);
arc.Y = rectangle.Bottom - diameter;
path.AddArc(arc, 0, 90);
arc.X = rectangle.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
return path;
}
Main code parts are from Arun Reginald Zaheeruddin
Solved it according to this answer by #Reza Aghaei.
Solution
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class RoundLabel : Label
{
[Browsable(true)]
public Color _BackColor { get; set; }
public RoundLabel()
{
this.DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var graphicsPath = _getRoundRectangle(this.ClientRectangle))
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var brush = new SolidBrush(_BackColor))
e.Graphics.FillPath(brush, graphicsPath);
using (var pen = new Pen(_BackColor, 1.0f))
e.Graphics.DrawPath(pen, graphicsPath);
TextRenderer.DrawText(e.Graphics, Text, this.Font, this.ClientRectangle, this.ForeColor);
}
}
private GraphicsPath _getRoundRectangle(Rectangle rectangle)
{
int cornerRadius = 15; // change this value according to your needs
int diminisher = 1;
GraphicsPath path = new GraphicsPath();
path.AddArc(rectangle.X, rectangle.Y, cornerRadius, cornerRadius, 180, 90);
path.AddArc(rectangle.X + rectangle.Width - cornerRadius - diminisher, rectangle.Y, cornerRadius, cornerRadius, 270, 90);
path.AddArc(rectangle.X + rectangle.Width - cornerRadius - diminisher, rectangle.Y + rectangle.Height - cornerRadius - diminisher, cornerRadius, cornerRadius, 0, 90);
path.AddArc(rectangle.X, rectangle.Y + rectangle.Height - cornerRadius - diminisher, cornerRadius, cornerRadius, 90, 90);
path.CloseAllFigures();
return path;
}
}
I created a simple cool ProgressBar control using a tutorial. However, I'm facing an issue. This is my code:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Revarz
{
class GraphicsHelper
{
public GraphicsPath Createround(int X, int Y, int Width, int Height, int CornerRadius)
{
GraphicsPath gfxPath = new GraphicsPath();
try
{
gfxPath.AddArc(X, Y, CornerRadius, CornerRadius, 180, 90);
gfxPath.AddArc(X + Width - CornerRadius, Y, CornerRadius, CornerRadius, 270, 90);
gfxPath.AddArc(X + Width - CornerRadius, Y + Height - CornerRadius, CornerRadius, CornerRadius, 0, 90);
gfxPath.AddArc(X, Y + Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
gfxPath.CloseAllFigures(); return gfxPath;
}
catch (Exception) { return null; }
}
}
public class CustomProgressbar : Control
{
public int Value { get; set; }
private int _Maximum = 100;
public int Maximum
{
get { return _Maximum; }
set { if (value > 0) { _Maximum = value; } else { throw new Exception("Maximum should be bigger than zero!"); }; }
}
public CustomProgressbar()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true);
DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear(BackColor);
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
GraphicsPath barPath = new GraphicsHelper().Createround(0, 0, Width - 1, Height - 1, 3);
e.Graphics.DrawPath(new Pen(Color.FromArgb(50, Color.Black)), barPath);
e.Graphics.SetClip(barPath);
LinearGradientBrush LGB = new LinearGradientBrush(new Rectangle(0, 2, Width - 1, Height - 3), Color.FromArgb(241, 229, 201), Color.FromArgb(237, 218, 202), 90F);
e.Graphics.FillRectangle(LGB, LGB.Rectangle);
e.Graphics.ResetClip();
int DrawWidth = (int)(((double)Value / (double)_Maximum) * (double)(Width - 1));
if (DrawWidth > 1)
{
GraphicsPath FilledPart = new GraphicsHelper().Createround(0, 0, DrawWidth, Height - 1, 3);
LinearGradientBrush LGB2 = new LinearGradientBrush(new Rectangle(0, 1, DrawWidth, Height - 2), Color.FromArgb(232, 119, 9), Color.FromArgb(255, 171, 3), 90F);
e.Graphics.FillRectangle(LGB2, LGB2.Rectangle);
e.Graphics.DrawPath(new Pen(Color.FromArgb(146, 101, 11)), FilledPart);
}
base.OnPaint(e);
}
}
}
The issue is that, when I increase the value, the value doesn't acutally apply (the bar itself, doesn't increase). My firned told me that I have to invalidate the value when it's changed, but I have no idea how to do so!
I'd like some help, thanks!
You need to call the Invalidate() method to force a repaint:
int _value;
public int Value {
get { return _value;}
set {
if(_value != value) {
_value = value;
Invalidate();
}
}
}
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: