C# Non-rectangular pictureboxes - c#

Is there a way to create non-rectangular pictureBoxes. I have round shapes that should overlap and if possible should be in different pictureboxes..
I tried the this here, but you could not see both pictureboxes that are overlapping at a time, but just one..
Here the picture that resulted from my tests:

You can make the PictureBoxes circular by adding an Ellipse to a GraphicsPath and then building a new Region from it.
Here's a quick example:
public class Target : PictureBox
{
public Target()
{
this.Size = new Size(100, 100);
this.Paint += Target_Paint;
Rectangle rc = this.ClientRectangle;
rc.Inflate(-10, -10);
System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
gp.AddEllipse(rc);
this.Region = new Region(gp);
}
void Target_Paint(object sender, PaintEventArgs e)
{
Rectangle rc = this.ClientRectangle;
rc.Inflate(-10, -10);
using (Pen pen = new Pen(Color.Blue, 5))
{
e.Graphics.DrawEllipse(pen, rc);
}
rc = new Rectangle(new Point(this.Size.Width / 2, this.Size.Height / 2), new Size(1, 1));
rc.Inflate(9, 9);
e.Graphics.FillEllipse(Brushes.Red, rc);
}
}
After compiling, the new control appears at the top of your ToolBox.
Here's a screenshot with three of them overlapping each other:

Related

GraphicsPath.IsVisible() does not return if the point is inside the polygon correctly?

I add a polygon to the GraphicsPath and try to check if the rectangle is positioned inside of it. When rectangle is completely outside the polygon code responds correctly. However, when inside the polygon its return value is unpredictable.
For now I only check top-left corner of the rectangle.
private void Form1_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
rect = new Rectangle(new Point(x, y), new Size(30,30));
g.FillRectangle(Brushes.Green, rect);
Point[] points = new Point[]
{
new Point(0, 0),
new Point(50, 0),
new Point(50, 50),
new Point(0, 50),
};
graphicsPath.AddPolygon(points);
g.DrawPolygon(Pens.Black, points);
if ((graphicsPath.IsVisible(rect.Location)))
{
this.Text = "Inside " + rect.Location.ToString();
}
else
{
this.Text = "not inside " + rect.Location.ToString();
}
}
I also have some code which is used to move the rectangle using MouseDown, MouseUp and MouseMove events.
The results I receive are:
But after repainting the form (even just minimizing window) those same coordinates are responding differently and the result is:

How to draw graph in c#

I'm new ,and I don't understand why this method when copied to windows forms doesn't do anything when running the program. I was copy it from MSDN page.
public void DrawLinesPoint(PaintEventArgs e)
{
// Create pen.
Pen pen = new Pen(Color.Black, 3);
// Create array of points that define lines to draw.
Point[] points =
{
new Point(10, 10),
new Point(10, 100),
new Point(200, 50),
new Point(250, 300)
};
//Draw lines to screen.
e.Graphics.DrawLines(pen, points);
}
Typically, when you draw on a form, you handle the form’s Paint event and perform the drawing using the Graphics property of the PaintEventArgs
In your code you need to add the DrawLinesPoint to the paint event before being able to use it
In your Constructor() add
InitializeComponent();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.DrawLinesPoint);
And in your Paint PaintEventHandler
private void DrawLinesPoint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Black, 3);
// Create array of points that define lines to draw.
Point[] points =
{
new Point(10, 10),
new Point(10, 100),
new Point(200, 50),
new Point(250, 300)
};
//Draw lines to screen.
e.Graphics.DrawLines(pen, points);
}

Using Matrix.Rotate more than once C# Winforms

I've been trying to solve a problem I'm having with rotating an oval. The code that I'm posting works, but it's mimicking the kind of code I have to work with for real. Meaning, I can't use the OnPaint override and I'm limited to what I can do in the main code. I'm adding an oval to a graphic layer, and I need to be able to rotate, move and resize the oval. Move and resizing work flawlessly, but rotating doesn't work as I need it to.
If you click in the small box at the 9 oclock position,
the oval will rotate as expected:
The required behavior is to be able to click in the small box at the 12 oclock position, and have the oval rotate again. This does not occur. In order to get the oval to rotate again you need to click in the original 9 oclock position. What I'm really, really trying to find out is how to get the coordinates of the box at the 12 oclock position (or what ever position or location that box ends up after rotating) so that I can rotate it again. Thus far, I have been unable to figure it out. Please try and understand, I'm working with old code that was poorly written and I'm not allowed to change very much of it. What I write must integrate with what's already there. Below is the code snippet that demonstrates what I'm doing. I know I'm missing something obvious, just don't know what. Thanks.
public partial class Form1 : Form
{
int theAngle = 0;
Pen pen2 = new Pen(Color.FromArgb(255, 68, 125, 255), 4);
Pen pen3 = new Pen(Color.Green, 4);
Pen smallPen = new Pen(Color.Black, 1);
PointF center = new PointF(0, 0);
Rectangle rectangle = new Rectangle(20, 20, 100, 30);
Rectangle myRect2 = new Rectangle();
bool mouseBtnDown = false;
Graphics gw;
public Form1()
{
InitializeComponent();
this.MouseDown += mouseDown;
gw = this.CreateGraphics();
}
private void mouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (myRect2.Contains(e.Location))
theAngle+=90;
rotate();
}
if (e.Button == MouseButtons.Right)
{
//oval = false;
//mouseBtnDown = false;
theAngle = 0;
rectangle.X = e.X - 50;
rectangle.Y = e.Y - 15;
rectangle.Width = 100;
rectangle.Height = 30;
center.X = rectangle.Left + (0.5f * rectangle.Width);
center.Y = rectangle.Top + (0.5f * rectangle.Height);
myRect2.Size = new Size(15, 15);
myRect2.Location = new Point(rectangle.Left - 15, (rectangle.Top - (rectangle.Height / 2)) + 15);
drawstuff();
// Invalidate();
}
}
public void rotate()
{
var matrix = new Matrix();
matrix.RotateAt(theAngle, center);
gw.Transform = matrix;
drawstuff();
}
public void drawstuff()
{
gw.SmoothingMode = SmoothingMode.AntiAlias; // Creates smooth lines.
gw.DrawEllipse(pen2, rectangle);
gw.DrawRectangle(smallPen, myRect2);
}
}
You can use the Transform matrix to rotate points. So what I've done is get the 4 corner points of myRect2, rotate them using the same Transform matrix, then assign these to a rectangle. You can then use this new rectangle to check the location. I also changed the call to drawstuff() at the end of the right button click to call rotate(), this way the rotated rectangle can get updated when the ellipse is first placed, and the graphics transform angle gets updated to 0.
public partial class Form1 : Form
{
int theAngle = 0;
Pen pen2 = new Pen(Color.FromArgb(255, 68, 125, 255), 4);
Pen pen3 = new Pen(Color.Green, 4);
Pen smallPen = new Pen(Color.Black, 1);
PointF center = new PointF(0, 0);
Rectangle rectangle = new Rectangle(20, 20, 100, 30);
Rectangle myRect2 = new Rectangle();
Rectangle rotatedRect2 = new Rectangle();
bool mouseBtnDown = false;
Graphics gw;
public Form1()
{
InitializeComponent();
this.MouseDown += mouseDown;
gw = this.CreateGraphics();
}
private void mouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (rotatedRect2.Contains(e.Location))
theAngle += 90;
rotate();
}
if (e.Button == MouseButtons.Right)
{
//oval = false;
//mouseBtnDown = false;
theAngle = 0;
rectangle.X = e.X - 50;
rectangle.Y = e.Y - 15;
rectangle.Width = 100;
rectangle.Height = 30;
center.X = rectangle.Left + (0.5f * rectangle.Width);
center.Y = rectangle.Top + (0.5f * rectangle.Height);
myRect2.Size = new Size(15, 15);
myRect2.Location = new Point(rectangle.Left - 15, (rectangle.Top - (rectangle.Height / 2)) + 15);
rotate();
//drawstuff();
// Invalidate();
}
}
public void rotate()
{
var matrix = new Matrix();
matrix.RotateAt(theAngle, center);
gw.Transform = matrix;
// Get the 4 corner points of myRect2.
Point p1 = new Point(myRect2.X, myRect2.Y),
p2 = new Point(myRect2.X + myRect2.Width, myRect2.Y),
p3 = new Point(myRect2.X, myRect2.Y + myRect2.Height),
p4 = new Point(myRect2.X + myRect2.Width, myRect2.Y + myRect2.Height);
Point[] pts = new Point[] { p1, p2, p3, p4 };
// Rotate the 4 points.
gw.Transform.TransformPoints(pts);
// Update rotatedRect2 with those rotated points.
rotatedRect2.X = pts.Min(pt => pt.X);
rotatedRect2.Y = pts.Min(pt => pt.Y);
rotatedRect2.Width = pts.Max(pt => pt.X) - pts.Min(pt => pt.X);
rotatedRect2.Height = pts.Max(pt => pt.Y) - pts.Min(pt => pt.Y);
drawstuff();
}
public void drawstuff()
{
gw.SmoothingMode = SmoothingMode.AntiAlias; // Creates smooth lines.
gw.DrawEllipse(pen2, rectangle);
gw.DrawRectangle(smallPen, myRect2);
}
}
Something to note. Drawing to the screen like this (using the form's created graphics and drawing using your own draw function) means the ellipses/rectangles are only drawn once. i.e. if you draw a few then minimize your form, when you bring it back up the ellipses will be gone. Not sure if this is what you're after or not. One way to fix this would be to draw the ellipses to a Bitmap and then in the form's Paint event this bitmap is draw to the form.

C# fill polygon (triangle)

I have problem with draw two polygons.
I want to fill two triangles, but one is greater than the second.
I am using UserControl in winforms.
Code:
Point[] DOWN = new Point[] {new Point(0, 0), new Point(10, 0), new Point(5, 5)};
Point[] UP = new Point[] { new Point(0, 15), new Point(10, 15), new Point(5, 10) };
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
SolidBrush brush = new SolidBrush(Color.FromArgb(253, 198, 19));
e.Graphics.FillPolygon(brush, DOWN);
e.Graphics.FillPolygon(brush, UP);
brush.Dispose();
}
Where is problem?
Try setting the PixelOffsetMode property:
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
using (SolidBrush brush = new SolidBrush(Color.FromArgb(253, 198, 19))) {
e.Graphics.FillPolygon(brush, DOWN);
e.Graphics.FillPolygon(brush, UP);
}
Result:
Try keeping the order counter-clockwise and start from the highest point:
new Point(5, 10), new Point(10, 15), new Point(0, 15)
Tell us if that helped. Sometimes those algorithms don't behave well on border conditions.

Is it possible to get a scaled/translated graphics object?

I'm using WinForms to write a visualizer for a simulation. The visualization involves various objects moving around a grid.
So far, I'm using a custom control that extends Panel and doing the custom drawing with the Graphics class during Paint events. However, one irritation is that I'm constantly having to scale things from grid coordinates to the control.DisplayRectangle coordinates (in other words, an object that takes up 2 cells in the grid would take up 2 * (control.DisplayRectangle.Width / horizontalGridWidth) pixels when drawn).
I'm wondering, is there a way to get the Graphics object to do these translations for me so that I can express my drawing in grid coordinates and have it automatically be mapped to the physical coordinates?
It turns out that Matrix was indeed the key (see accepted answer). Here's the code that got it working:
public SimulationPanel() {
this.DoubleBuffered = true;
this.SizeChanged += (o, e) => this.Invalidate();
this.Paint += this.PaintPanel;
}
private void Paint(object sender, PaintEventArgs e) {
e.Graphics.Clear(Color.Black);
var fromRectangle = GetSimulationWorldCoordinates();
var toRectangle = ScaleToFit(fromRectangle, this.DisplayRectangle);
using (var matrix = new Matrix(
fromRectangle,
new[] {
toRectangle.Location,
new Point(toRectangle.Right, toRectangle.Top),
new Point(toRectangle.Left, toRectangle.Bottom),
}))
{
// draw the simulation stuff here using simulation coordinates
e.Graphics.Transform = matrix;
e.Graphics.FillRectangle(Brushes.LightBlue, toRectangle);
e.Graphics.DrawLine(Pens.Red, toRectangle.Location, new Point(toRectangle.Right, toRectangle.Bottom));
}
}
How about this code ?
I use Labels instead of grids because I cannot know your grids.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
GraphicsPath path = new GraphicsPath();
RectangleF pathRect;
public Form1()
{
InitializeComponent();
Location = new Point(0, 0);
Size = new System.Drawing.Size(500, 500);
Label lbl1 = new Label();
lbl1.Location = new Point(100, 100);
lbl1.Size = new System.Drawing.Size(200, 100);
lbl1.BorderStyle = BorderStyle.FixedSingle;
lbl1.Paint += new PaintEventHandler(lbl_Paint);
Label lbl2 = new Label();
lbl2.Location = new Point(300, 200);
lbl2.Size = new System.Drawing.Size(100, 200);
lbl2.BorderStyle = BorderStyle.FixedSingle;
lbl2.Paint += new PaintEventHandler(lbl_Paint);
Controls.Add(lbl1);
Controls.Add(lbl2);
path.AddRectangle(new Rectangle(50, 50, 150, 150));
path.AddEllipse(new Rectangle(25, 50, 25, 50));
pathRect = path.GetBounds();
}
void lbl_Paint(object sender, PaintEventArgs e)
{
var rect = ((Control)sender).DisplayRectangle;
PointF[] plgpts = new PointF[] {
new PointF(rect.Left, rect.Top),
new PointF(rect.Right - 1, rect.Top),
new PointF(rect.Left, rect.Bottom - 1),
};
Graphics g = e.Graphics;
g.Clear(SystemColors.Control);
using (Matrix matrix = new Matrix(path.GetBounds(), plgpts))
{
g.Transform = matrix;
g.DrawPath(Pens.Red, path);
}
}
}
}

Categories