I am trying to create vertical lines inside a panel in my winform application. I am able to draw the lines but they are not what I am expecting to be. My requirements are:
The lines must be drawn from the middle of the panel vertically.
The lines must be drawn on both the sides with equal height.
The problem is when I am trying to draw the lines they are drawn from top of the panel and are upside down.
My target is to get something like:
This is how I am trying to do it:
public void DrawLines(System.Drawing.Graphics g, float height)
{
Pen thePen = new Pen(Color.Red, 1.0F);
PointF[] points1 =
{
new PointF(5,5),
new PointF(5, 50)
};
PointF[] points2 =
{
new PointF(7,5),
new PointF(7, 60)
};
PointF[] points3 =
{
new PointF(9,5),
new PointF(9, 55)
};
//Tried this as well
//PointF[] points1 =
// {
// new PointF(5,50),
// new PointF(5, 5)
// };
//PointF[] points2 =
// {
// new PointF(7,60),
// new PointF(7, 5)
// };
//PointF[] points3 =
// {
// new PointF(9,55),
// new PointF(9, 5)
// };
g.DrawLines(thePen, points1);
g.DrawLines(thePen, points2);
g.DrawLines(thePen, points3);
}
Right now I am calling this function on button click.
DrawLines(panel1.CreateGraphics(), 20.0F);
In real time this will be called inside a loop and line height will be passed as a parameter.
As already commented, Y coordinates are flipped when drawing on the Panel. You can test this by simply displaying mouse coordinates.
To draw the Lines you want to get the Middle of the panel and work from there. In your example you had an unused height variable, so i added funtionality to that. Here is a working example.
public MyForm()
{
InitializeComponent();
_myPen = new Pen(Color.Red, 1.0F);
}
private Pen _myPen;
private void DrawLines(Graphics g, int width = 0, int height = 0)
{
// Get the middle of the panel
int panelMiddle = panel.Height / 2;
// Lines going up from the mittle
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 5, height + panelMiddle -5),
new PointF(width + 5, height + panelMiddle - 50)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 7, height + panelMiddle-5),
new PointF(width + 7, height + panelMiddle - 60)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 9, height + panelMiddle-5),
new PointF(width + 9, height + panelMiddle - 55)
});
// Lines going down from the middle
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 5, height + panelMiddle +5),
new PointF(width + 5, height + panelMiddle + 50)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 7, height + panelMiddle+5),
new PointF(width + 7, height + panelMiddle + 60)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 9, height + panelMiddle+5),
new PointF(width + 9, height + panelMiddle + 55)
});
}
private void panel_Paint(object sender, PaintEventArgs e)
{
DrawLines(e.Graphics);
DrawLines(e.Graphics,panel.Width - 14);
}
Related
I have this little code to use AddArc() method in a label, but when I execute the code the label disappears. I believe it is the numbers I have used, I followed instructions from the Windows documentation and it had these parameters there too.
GraphicsPath gp = new GraphicsPath();
Rectangle rec = new Rectangle(20, 20, 50, 100);
gp.AddArc(rec, 0 , 180);
label2.Region = new Region(gp);
label2.Invalidate();
I used another code to make the correct way or curve in a text
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var center = new Point(Width / 2, Height / 2);
var radius = Math.Min(Width, Height) / 3;
var text = "Hello";//txtUp.Text;
var font = new Font(FontFamily.GenericSansSerif, 24, FontStyle.Bold);
for (var i = 0; i < text.Length; ++i)
{
var c = new String(text[i], 1);
var size = e.Graphics.MeasureString(c, font);
var charRadius = radius + size.Height;
var angle = (((float)i / text.Length) - 2);
var x = (int)(center.X + Math.Cos(angle) * charRadius);
var y = (int)(center.Y + Math.Sin(angle) * charRadius);
e.Graphics.TranslateTransform(x, y);
e.Graphics.RotateTransform((float)(90 + 360 * angle / (2 * Math.PI)));
e.Graphics.DrawString(c, font, Brushes.Red, 0, 0);
e.Graphics.ResetTransform();
e.Graphics.DrawArc(new Pen(Brushes.Transparent, 2.0f), center.X - radius, center.Y - radius, radius * 2, radius * 2, 0, 360);
}
}
but it wont show in front of a panel is it possible.
This is what it looks like:
Is it possible to move that text in front of the green circle?
I am using netDXF (https://netdxf.codeplex.com/) to generate a DXF file for use with AutoCAD. However, I have an issue with getting the width of MText correct. I want to be able to define a width that the text should fit into, and change the width factor of the text (squash it horizontally) so that it fits in the defined area. So if I have a 40mm width to fit the text into and the text is 80mm long, it needs to have a width factor of 0.5. The only problem is that I don't know how to accurately determine the width of the text. I have tried the following methods and was unsuccessful in getting the correct result:
Why is Graphics.MeasureString() returning a higher than expected number?
Measure a String without using a Graphics object?
http://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitations
I have attached my code. I am basically printing a horizontal line using each of the 3 methods to calculate text width and comparing it to the actual text width. If I change the font, I get varying results. I have attached two images. One using the code with Calibri and one with Arial. I need the line to be on the edges of the text no matter what font I use.
Here is my code:
public void TestMethod1()
{
Application.SetCompatibleTextRenderingDefault(false);
//text width in mm
float textWidth = 40;
float textHeight = 200;
string labelText = "HELLO WORLD!";
TextStyle textStyle = new TextStyle("Calibri");
DxfDocument dxf = new DxfDocument();
Layer layer1 = new Layer("layer1");
layer1.Color = new AciColor(0, 0, 255);
layer1.Name = "Text";
MText text1 = new MText(new Vector2(0, 0), textHeight, 0, textStyle);
text1.Layer = layer1;
text1.AttachmentPoint = MTextAttachmentPoint.MiddleCenter;
//Will the text fit in the bounds of the rectangle? If not change width factor so it does.
Font f = new Font(textStyle.FontName, textHeight);
Size size = TextRenderer.MeasureText(labelText, f);
SizeF sizeF = graphicsMeasureString(labelText, f);
int width = MeasureDisplayStringWidth(labelText, f);
float widthFactor = Math.Min(1, textWidth / sizeF.Width);
MTextFormattingOptions mtextOptions = new MTextFormattingOptions(text1.Style);
//mtextOptions.WidthFactor = widthFactor;
text1.Write(labelText, mtextOptions);
//Red, g.MeasureString
Line line1 = new Line(new Vector2(0 - sizeF.Width / 2, 0), new Vector2(0 + sizeF.Width / 2, 0));
line1.Color = new AciColor(255, 0, 0);
//Green, TextRenderer
Line line2 = new Line(new Vector2(0 - size.Width / 2, 5), new Vector2(0 + size.Width / 2, 5));
line2.Color = new AciColor(0, 255, 0);
//Yellow, MeasureDisplayStringWidth
Line line3 = new Line(new Vector2(0 - width / 2, -5), new Vector2(0 + width / 2, -5));
line3.Color = new AciColor(255, 255, 0);
dxf.AddEntity(text1);
dxf.AddEntity(line1);
dxf.AddEntity(line2);
dxf.AddEntity(line3);
dxf.Save("Text Width Test.dxf");
}
public SizeF graphicsMeasureString(string text, Font f)
{
Bitmap fakeImage = new Bitmap(1, 1);
Graphics g = Graphics.FromImage(fakeImage);
SizeF sizeF = g.MeasureString(text, f, new PointF(100, 0), StringFormat.GenericTypographic);
return sizeF;
}
public int MeasureDisplayStringWidth(string text, Font f)
{
Size size = TextRenderer.MeasureText(text, f);
Bitmap fakeImage = new Bitmap(1, 1);
Graphics g = Graphics.FromImage(fakeImage);
System.Drawing.StringFormat format = new System.Drawing.StringFormat();
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, 1000, 1000);
System.Drawing.CharacterRange[] ranges = { new System.Drawing.CharacterRange(0, text.Length) };
System.Drawing.Region[] regions = new System.Drawing.Region[1];
format.SetMeasurableCharacterRanges(ranges);
regions = g.MeasureCharacterRanges(text, f, rect, format);
rect = regions[0].GetBounds(g);
return (int)(rect.Right + 1.0f);
}
I have a TreeView control with checkboxes which is completely owner drawn (DrawMode = TreeViewDrawMode.OwnerDrawAll).
What I'm trying to do is to have the checkboxes owner drawn, so that they can have a grayed state. I'm using VisualStyleRenderer for this.
The problem arises when I have to correctly place the expand/collapse glyph and the checkbox in the item bounds, because the "hit-test areas" for both the glyph and the checkbox seems to be unknown and unchangeable.
Is there a way to get the bounds of those areas, or to replace the default ones with custom values?
I ran into the same problem. You have to offset your drawing by the proper amount, which is predictable.
There's probably more here than you need, but here's my drawing for a custom tree I used alongside a calendar control:
private void TreeViewControl_DrawNode(Object sender, DrawTreeNodeEventArgs e)
{
//What might seem like strange positioning/offset is to ensure that our custom drawing falls in
// line with where the base drawing would appear. Otherwise, click handlers (hit tests) fail
// to register properly if our custom-drawn checkbox doesn't fall within the expected coordinates.
Int32 boxSize = 16;
Int32 offset = e.Node.Parent == null ? 3 : 21;
Rectangle bounds = new Rectangle(new Point(e.Bounds.X + offset, e.Bounds.Y + 1), new Size(boxSize, boxSize));
ControlPaint.DrawCheckBox(e.Graphics, bounds, e.Node.Checked ? ButtonState.Checked : ButtonState.Normal);
if (e.Node.Parent != null)
{
Color c = Color.Black;
String typeName = e.Node.Name.Remove(0, 4);
Object o = Enum.Parse(typeof(CalendarDataProvider.CalendarDataItemType), typeName);
if (o != null && (o is CalendarDataProvider.CalendarDataItemType))
c = CalendarDataProvider.GetItemTypeColor((CalendarDataProvider.CalendarDataItemType)o);
bounds = new Rectangle(new Point(bounds.X + boxSize + 2, e.Bounds.Y + 1), new Size(13, 13));
using (SolidBrush b = new SolidBrush(c))
e.Graphics.FillRectangle(b, bounds);
e.Graphics.DrawRectangle(Pens.Black, bounds);
e.Graphics.DrawLine(Pens.Black, new Point(bounds.X + 1, bounds.Bottom + 1), new Point(bounds.Right + 1, bounds.Bottom + 1));
e.Graphics.DrawLine(Pens.Black, new Point(bounds.Right + 1, bounds.Y + 1), new Point(bounds.Right + 1, bounds.Bottom + 1));
}
Font font = new Font("Microsoft Sans Serif", 9f, e.Node.Parent == null ? FontStyle.Bold : FontStyle.Regular);
bounds = new Rectangle(new Point(bounds.X + boxSize + 2, e.Bounds.Y), new Size(e.Bounds.Width - offset - 2, boxSize));
e.Graphics.DrawString(e.Node.Text, font, Brushes.Black, bounds);
}
How to create a form in shape of rhomb?
I managed to create a shape in form of ellipse with the help of this:
private void Form1_Load(object sender, EventArgs e)
{
System.Drawing.Drawing2D.GraphicsPath myPath = new System.Drawing.Drawing2D.GraphicsPath();
myPath.AddEllipse(45, 60, 200, 200);
Region myRegion = new Region(myPath);
this.Region = myRegion;
}
How can I do it but making rhomb?
Use myPath.AddLines instead of the myPath.AddEllipse:
private void Form1_Load(object sender, EventArgs e)
{
using (GraphicsPath myPath = new GraphicsPath())
{
myPath.AddLines(new[]
{
new Point(0, Height / 2),
new Point(Width / 2, 0),
new Point(Width, Height / 2),
new Point(Width / 2, Height)
});
Region = new Region(myPath);
}
}
Above answer by #Dmitry helped me a lot. However, it does not draw a complete rhombus, as claimed. The last segment is not drawn due to absent final point, which must coincide with the starting point. Line array should contain five points, not four.
I have made some corrections and come up with this function, which draws a rhombus withing a given rectangle:
private void DrawRhombus(Graphics graphics, Rectangle rectangle)
{
using (GraphicsPath myPath = new GraphicsPath())
{
myPath.AddLines(new[]
{
new Point(rectangle.X, rectangle.Y + (rectangle.Height / 2)),
new Point(rectangle.X + (rectangle.Width / 2), rectangle.Y),
new Point(rectangle.X + rectangle.Width, rectangle.Y + (rectangle.Height / 2)),
new Point(rectangle.X + (rectangle.Width / 2), rectangle.Y + rectangle.Height),
new Point(rectangle.X, rectangle.Y + (rectangle.Height / 2))
});
using (Pen pen = new Pen(Color.Black, 1))
graphics.DrawPath(pen, myPath);
}
}
I'm writing an extended progress bar control at present, 100% open source and I've created some basic styles with gradients and solid colours.
One of the options I wanted to add was animation to the bar, prety much like the windows 7 and vista green progress bar. So I need to add a moving "Glow" to the % bar, however my attempt at this looks terrible.
My method is to draw an ellipse with set size and move it's x position until it reaches the end were the animation starts again.
First of does anyone have nay links or code to help me achieve the current windows 7 glow effect using GDI or some similar method?
I have several other animations that will also be added the the bar hence the GDI.
private void renderAnimation(PaintEventArgs e)
{
if (this.AnimType == animoptions.Halo)
{
Rectangle rec = e.ClipRectangle;
Rectangle glow = new Rectangle();
//SolidBrush brush = new SolidBrush(Color.FromArgb(100, Color.White));
//int offset = (int)(rec.Width * ((double)Value / Maximum)) - 4;
int offset = (int)(rec.Width / Maximum) * Value;
if (this.animxoffset > offset)
{
this.animxoffset = 0;
}
glow.Height = rec.Height - 4;
if (this.animxoffset + glow.X > offset)
{
glow.Width = offset - (this.animxoffset + 50);
}
else
{
glow.Width = 50;
}
glow.X = this.animxoffset;
LinearGradientBrush brush = new LinearGradientBrush(glow, Color.FromArgb(0, Color.White), Color.FromArgb(100, Color.White), LinearGradientMode.Horizontal);
e.Graphics.FillEllipse(brush, this.animxoffset, 2, glow.Width, glow.Height);
brush.Dispose();
string temp = offset.ToString();
e.Graphics.DrawString(temp + " : " + glow.X.ToString(), DefaultFont, Brushes.Black, 2, 2);
animTimer = new System.Timers.Timer();
animTimer.Interval = 10;
animTimer.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
animTimer.Start();
}
}
void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this.animTimer.Stop();
this.animxoffset += 2;
Invalidate();
}
This is just an example glow iterating through a pen array.
You could also use a transparent image (although it could have a performance impact).
Pen[] gradient = { new Pen(Color.FromArgb(255, 200, 200, 255)), new Pen(Color.FromArgb(150, 200, 200, 255)), new Pen(Color.FromArgb(100, 200, 200, 255)) };
int x = 20;
int y = 20;
int sizex = 200;
int sizey = 10;
int value = 25;
//draw progress bar basic outline (position - 1 to compensate for the outline)
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(x-1, y-1, sizex, sizey));
//draw the percentage done
e.Graphics.FillRectangle(Brushes.AliceBlue, new Rectangle(x, y, (sizex/100)*value, sizey));
//to add the glow effect just add lines around the area you want to glow.
for (int i = 0; i < gradient.Length; i++)
{
e.Graphics.DrawRectangle(gradient[i], new Rectangle(x - (i + 1), y - (i + 1), (sizex / 100) * value + (2 * i), sizey + (2 * i)));
}