Panel Round Edge - c#

public void DrawRoundRect(Graphics g, Pen p, float X, float Y, float width, float height, float radius)
{
GraphicsPath gp = new GraphicsPath();
gp.AddLine(X + radius, Y, X + width - (radius * 2), Y);
gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90);
gp.AddLine(X + width, Y + radius, X + width, Y + height - (radius * 2));
gp.AddArc(X + width - (radius * 2), Y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
gp.AddLine(X + width - (radius * 2), Y + height, X + radius, Y + height);
gp.AddArc(X, Y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
gp.AddLine(X, Y + height - (radius * 2), X, Y + radius);
gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90);
gp.CloseFigure();
g.DrawPath(p, gp);
}
private void _pnlLogIn_Paint(object sender, PaintEventArgs e)
{
Graphics v = e.Graphics;
DrawRoundRect(v, Pens.Blue, e.ClipRectangle.Left, e.ClipRectangle.Top, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1, 10);
//Without rounded corners
//e.Graphics.DrawRectangle(Pens.Blue, e.ClipRectangle.Left, e.ClipRectangle.Top, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1);
base.OnPaint(e);
}
Hello, What is wrong with my code. My panel has already a round edge but the border of the rectangular panel remains. What code should i add or revise? thank you..
Image

Set your panel region to Graphics path.
In your code posted, do it after you call DrawPath in DrawRoundRect method.
Something like this:
_pnlLogIn.Region = new System.Drawing.Region(gp);
After I do above code change, I see my window as shown below.
I tried with bit bigger radius (40)..

Related

Increasing the height of Panel according to wrapped string Label in Panel

i am trying to develop a win form for chatting purpose. I am developing Chat bubbles using pure inbuilt functions of .Net Framework, No fancy UI, No third party libraries.
Now let's have a look on how every thing is being done.
My following function is responsible for generating a Panel dynamically for each chat message received, the Pain event is used to draw rounded rectangle and color is transparent. A picture box is used to show static avatar.
private void SetRemoteMessage(string msg)
{
PictureBox pb = new PictureBox();
pb.Bounds = new Rectangle(0, 0, 72, 72);
pb.Image = Base64ToImage(avatar_his);
Panel p = new Panel();
Label lb = new Label();
lb.BackColor = Color.Transparent;
lb.ForeColor = Color.Blue;
lb.Text = msg;
lb.Font = new Font("Arial", 14, FontStyle.Bold, GraphicsUnit.Point);
p.Bounds = new Rectangle(rX, rY, (Width / 2) - 25, pb.Height);
p.BackColor = Color.Transparent;
lb.Size = new Size(p.Width - pb.Width, p.Height);
lb.Paint += _control_Paint;
lb.Location = new Point(pb.Width + 5, 0);
p.Controls.Add(pb);
p.Controls.Add(lb);
SetPanel(p);
rY += p.Height + 20;
mY += p.Height + 20;
}
following is the Paint event binded to the parent "Container" Panel so that a simple rounded rectangle is shown for each bubble
private void _control_Paint(object sender, PaintEventArgs e)
{
Control c = (Control)sender;
if(!c.Name.Equals("lb"))
{
Graphics v = e.Graphics;
DrawRoundRect(v, Pens.Blue, e.ClipRectangle.Left, e.ClipRectangle.Top, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1, 10);
}
else
{
using (Font font1 = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Point))
{
e.Graphics.DrawString(c.Text, font1, Brushes.Blue, c.Bounds);
}
}
base.OnPaint(e);
}
and the following function to actually generate rounded rectangles
private void DrawRoundRect(Graphics g, Pen p, float X, float Y, float width, float height, float radius)
{
GraphicsPath gp = new GraphicsPath();
gp.AddLine(X + radius, Y, X + width - (radius * 2), Y);
gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90);
gp.AddLine(X + width, Y + radius, X + width, Y + height - (radius * 2));
gp.AddArc(X + width - (radius * 2), Y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
gp.AddLine(X + width - (radius * 2), Y + height, X + radius, Y + height);
gp.AddArc(X, Y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
gp.AddLine(X, Y + height - (radius * 2), X, Y + radius);
gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90);
gp.CloseFigure();
g.DrawPath(p, gp);
}
The chat message is not wrapped automatically so to wrap it, the Pain method is used as it can be seen in Paint event . .the output is good as expected instead of one thing
The Problem can be seen easily the Panel height is not increasing according when a large message is given to display in bubble.
What i tried already is
Measuring string length with Graphics class, but i was not able to implement it with success
Enabling Scrollbars, Yes this approach worked but i am not interested to use this behavior
Counting string length and increasing height, This works but not efficient, specially when form is resized all calculations of measurement then become invalid.

Joining bezier curve to other drawings

I have implemented a rounded rectangle extension method, defined here.
public static Graphics DrawRRectangle(this Graphics g, Pen p, int x, int y, int width, int height, int feathering)
{
g.DrawLine(p, x, y + feathering, x, y + height - feathering);
g.DrawBezier(p, new Point(x, y + height - feathering),
new Point(x, y + height - feathering / 2), new Point(x + feathering / 2, y + height),
new Point(x + feathering, y + height));
g.DrawLine(p, x + feathering, y + height , x + width - feathering, y + height);
g.DrawBezier(p, new Point(x + width - feathering, y + height),
new Point(x + width - feathering / 2, y + height), new Point(x + width, y + height - feathering / 2),
new Point(x + width, y + height - feathering));
g.DrawLine(p, x + width, y + height - feathering, x + width, y + feathering);
g.DrawBezier(p, new Point(x + width, y + feathering),
new Point(x + width, y + feathering / 2), new Point(x + width - feathering / 2, y),
new Point(x + width - feathering, y));
g.DrawLine(p, x + width - feathering, y, x + feathering, y);
g.DrawBezier(p, new Point(x + feathering, y),
new Point(x + feathering / 2, y), new Point(x, y + feathering / 2),
new Point(x, y + feathering));
return g;
}
However when I use this method like so
g.DrawRRectangle(p, 100, 100, 1000, 1000, 100);,
I do not get the outcome I wanted, each of the corners are either misaligned of their pixels do not match up As seen in the images below.
Any suggestions anybody could offer would be helpful, I am unsure if this is a problem with the equations used to generate my curves however this is the first time I am dabbling with graphics, so it could just be my thinking. Thanks.
Whilst I can't comment on your implementation, you're going to run into problems further down the road with this. Your implementation will give the appearance of drawing a rounded rectangle, but say for example in future you want to fill the shape, you won't be able to because GDI/GDI+ won't see the drawn shapes as a single consecutive shape.
In this respect you should use a GraphicsPath.
See here for a complete solution for drawing rounded rectangles using a GraphicsPath.

Using a draw function in C#

I made a function that draws a rectangle with rounded corners using examples I got researching here, now I want to call this function with a button click, but I'm not sure how to provide the arguments to the function, can someone help in how to I call this function?
public void DrawCond(Graphics g, Pen p, float width, float height, float x, float y)
{
// Auxiliary variables
float radius;
if (width>=3.55)
{
radius = 1F;
}
else if (width>2.25)
{
radius = 0.8F;
}
else if (width>1.61)
{
radius = 0.65F;
}
else
{
radius = 0.5F;
}
GraphicsPath gp = new GraphicsPath();
//Draw lines
gp.AddLine(x + radius, y, x + width - 2 * radius, y); //bottom horizontal line
gp.AddLine(x + radius, y + height, x + width - 2 * radius, y + height); //top horizontal line
gp.AddLine(x + width, y + radius, x + width, y + height - 2 * radius); //inner vertical line
gp.AddLine(x + radius, y + radius, x + radius, y + height - 2 * radius); //outer vertical line
//Draw arcs
gp.AddArc(x, y + radius, radius, radius, 90, 90); //bottom left corner
gp.AddArc(x + width - radius, y + radius, radius, radius, 0, 90); //bottom right corner
gp.AddArc(x, y + height, radius, radius, 180, 90); //top left corner
gp.AddArc(x + width - radius, y + height, radius, radius, 270, 90); //top right corner
g.DrawPath(p, gp);
gp.Dispose();
}
You can create Graphics from panel you want to draw to like var g = panel.CreateGraphics() and pass it to your function.
Also you can create Pen by using one of its constructors. See MSDN for reference about Pen.

How can i draw a trail/trace after a moving line?

My code is drawing a circle then a line from the middle of the circle to the radius size of the circle and the line is moving by 1 angle.
Now i want to make that the line will leave some trail/trace after it like a radar effect.
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
anglecounter += 1;
double x = pictureBox1.Size.Width / 2 + 256 *Math.Cos(anglecounter * Math.PI / 180);
double y = pictureBox1.Size.Height / 2 +256 * Math.Sin(anglecounter * Math.PI / 180);
CloudEnteringAlert.Paint(e.Graphics, factor, distance);
e.Graphics.DrawLine(
new Pen(Color.Red, 2f),
new Point(pictureBox1.Size.Width / 2, pictureBox1.Size.Height/2),
new Point((int)x, (int)y));
e.Graphics.DrawEllipse(
new Pen(Color.Red, 2f),
0, 0, pictureBox1.Size.Width, pictureBox1.Size.Height);
}
How can I do this?
EDIT**
This is what i did now in the top of the form i added:
PointF _pt = new PointF(0F, 0F);
PointF _pt2 = new PointF(1F, 1F);
PointF _pt3 = new PointF(2F, 2F);
Color _lineColor = Color.FromArgb(0, 255, 0);
private double anglecounter1;
Then the paint event is now look like this:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
anglecounter += 1;
anglecounter1 += 0.5;
double x = pictureBox1.Size.Width / 2 + 256 *Math.Cos(anglecounter * Math.PI / 180);
double y = pictureBox1.Size.Height / 2 +256 * Math.Sin(anglecounter * Math.PI / 180);
double x1 = pictureBox1.Size.Width / 2 + 256 * Math.Cos(anglecounter1 * Math.PI / 180);
double y1 = pictureBox1.Size.Height / 2 + 256 * Math.Sin(anglecounter1 * Math.PI / 180);
CloudEnteringAlert.Paint(e.Graphics, factor, distance);
e.Graphics.DrawLine(
new Pen(Color.Red, 2f),
new Point(pictureBox1.Size.Width / 2, pictureBox1.Size.Height/2),
new Point((int)x, (int)y));
e.Graphics.DrawEllipse(
new Pen(Color.Red, 2f),
0, 0, pictureBox1.Size.Width, pictureBox1.Size.Height);
// create the fade path and gradient
GraphicsPath gp = new GraphicsPath(FillMode.Winding);
gp.AddLine(new PointF((float)(pictureBox1.Size.Width / 2), (float)(pictureBox1.Size.Height / 2)),new PointF( (float)x1,(float)y1));
gp.AddCurve(new PointF[] { _pt2, _pt3, _pt });
gp.AddLine(new PointF((float)x, (float)y), new PointF((float)(pictureBox1.Size.Width / 2), (float)(pictureBox1.Size.Height / 2)));
PathGradientBrush pgb = new PathGradientBrush(gp);
pgb.CenterPoint = new PointF((float)x1, (float)y1);
pgb.CenterColor = Color.FromArgb(128, _lineColor);
pgb.SurroundColors = new Color[] { Color.Empty };
// draw the fade path
e.Graphics.FillPath(pgb, gp);
}
But if im not wrong in this case the trail/trace is slower then the line is getting faster then it. Also the trail/trace is also behind the line but also in front of the line . Im not sure but thats what i see. So what is wrong ?
Another option is to not erase the image each time. Instead, draw a semi-transparent circle over the previous image:
// Initialize some dimensions
int x = pictureBox1.Bounds.X;
int y = pictureBox1.Bounds.Y;
int w = Math.Min(pictureBox1.Bounds.Width, pictureBox1.Bounds.Height);
int h = w; // Force square
int centerX = w / 2;
int centerY = h / 2;
float radius = w - centerX;
Graphics g = pictureBox1.CreateGraphics();
// First time draw a solid background then
// each successive time cover with semi-transparent background
Brush backGround = firstTime ? new SolidBrush(Color.FromArgb(255, 0, 0, 0)) : new SolidBrush(Color.FromArgb(10, 0, 0, 0));
firstTime = false;
g.FillEllipse(backGround, 0, 0, w, h);
float lineX = (float)(centerX + (radius * Math.Sin(anglecounter * (Math.PI / 180))));
float lineY = (float)(centerX + (radius * Math.Cos(anglecounter * (Math.PI / 180))));
anglecounter -= 1;
g.DrawLine(new Pen(Color.Green, 3), centerX, centerY, lineX, lineY);
g.DrawArc(new Pen(Color.Red, 4), new Rectangle(0, 0, w - 1, h - 1), 0, 360);
Produces this result:

A control disappears from parent UserControl after UserControl's OnRepaint event

I have a UserControl which has a button on it. On the UserControl OnPaint event I draw a rounded corner border (or a simple rectangle if the radius is zero) and then I fill the entire control. After these manipulations my Button (btnClose) disappears.
How do I make my button visible again?
protected override void OnPaint(PaintEventArgs pe)
{
using (System.Drawing.Pen p = new Pen(new SolidBrush(this.BorderColor)))
{
if (borderRadius > 0)
{
DrawRoundRect(pe.Graphics, p, 0, 0, this.Width - 1, this.Height - 1, borderRadius, this.FillColor);
}
else
{
this.BackColor = this.FillColor;
pe.Graphics.DrawRectangle(p, 0, 0, this.Width - 1, this.Height - 1);
}
btnClose.Location = new Point(this.Width - btnClose.Width - BTN_MARGIN_DELTA, BTN_MARGIN_DELTA);
}
base.OnPaint(pe);
}
Just in case, the DrawRoundRect function:
void DrawRoundRect(Graphics g, Pen p, float X, float Y, float width, float height, float radius, Color _fillColor)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddLine(X + radius, Y, X + width - (radius * 2), Y);
gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90);
gp.AddLine(X + width, Y + radius, X + width, Y + height - (radius * 2));
gp.AddArc(X + width - (radius * 2), Y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
gp.AddLine(X + width - (radius * 2), Y + height, X + radius, Y + height);
gp.AddArc(X, Y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
gp.AddLine(X, Y + height - (radius * 2), X, Y + radius);
gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90);
gp.CloseFigure();
using (SolidBrush brush = new SolidBrush(_fillColor))
{
g.FillPath(brush, gp);
g.DrawPath(p, gp);
}
}
}
Try moving the location code to the resize method:
protected override void OnResize(EventArgs e) {
btnClose.Location = new Point(this.Width - btnClose.Width - BTN_MARGIN_DELTA, BTN_MARGIN_DELTA);
}
Moving controls in a paint event could cause recursive calls to the paint event. Only "paint" in a paint event.
I set FillColor = Color.Gray, BorderColor = Color.Black, borderRadius = 5, BTN_MARGIN_DELTA = 2 and it seems to work without any problem. Here is a screenshot:
I think the problem isn't these lines of code.
Well, my mistake. It was a function that deletes all controls from UserControl. So I filter the controls on removal.
void ClearControls()
{
for (int i = 0; i < Items.Count; i++)
{
foreach (Control cc in Controls)
{
if (cc.Name.Contains(LINK_LABEL_FAMILY) || (cc.Name.Contains(LABEL_FAMILY)))
{
Controls.RemoveByKey(cc.Name);
}
}
}
}

Categories