Drawing a polygon according to the input coordinates
i got some code from here, i just take..
void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
List<Point> polyPoints = new List<Point>();
polyPoints.Add(new Point(30, 30));
polyPoints.Add(new Point(36, 105));
polyPoints.Add(new Point(66, 105));
polyPoints.Add(new Point(72, 66));
using (SolidBrush br = new SolidBrush(Color.FromArgb(100, Color.Yellow)))
{
e.Graphics.FillPolygon(br, polyPoints.ToArray());
}
e.Graphics.DrawPolygon(Pens.DarkBlue, polyPoints.ToArray());
}
note : SmoothingMode use header using System.Drawing.Drawing2D
then i got problem about click area, i just want the click area at the visible area, in this case the picturebox1 have size 1366 x 768
this is example of picturebox, i want the red area be clickable and the gray is not clickable area
by default all area in the box is clickable
Have you looked at the Documentation on PictureBox?
I'm looking at it and it seems there's many ways of resizing aspects of the PixtureBox object. Take a look at using the DefaultSize Property or setting the Size property. In either case, you have to wrap the size in a Size object and set the according PictureBox size property.
Such as:
pictureBox1.Size = new Size(xSize, ySize);
or
pictureBox1.DefaultSize = new Size(xSize, ySize);
Related
I drew an ellipse-like region for a label but i don't know how to set the antialias for it.
Snippet:
Rectangle circle = new Rectangle(0, 0, labelVoto.Width,labelVoto.Height);
var path = new GraphicsPath();
path.AddEllipse(circle);
labelVoto.Region = new Region(path);
and this is the result:
Can anybody help me?
Set the SmoothingMode of the Graphics object. Override OnPaintBackground instead of changing the Region. Regions do not support anti-aliasing. This example creates a customized label by deriving it from Label.
public class EllipticLabel : Label
{
protected override void OnPaintBackground(PaintEventArgs e)
{
// This ensures that the corners of the label will have the same color as the
// container control or form. They would be black otherwise.
e.Graphics.Clear(Parent.BackColor);
// This does the trick
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
var rect = ClientRectangle;
rect.Width--;
rect.Height--;
using (var brush = new SolidBrush(BackColor)) {
e.Graphics.FillEllipse(brush, rect);
}
}
}
If you set the paint rectangle size equal to ClientRectangle. The ellipse will be clipped by one pixel to the right and at the bottom. Therefore I reduce its size by one pixel.
You set the desired background color of the ellipse by setting the BackColor property of the label in code or in the properties window.
Result:
Once you have compiled the code, the customized label automatically appears in the Toolbox in the current project.
I want to create 2 transparent overlays for pictureBox in WinFrom application so I can separately draw on both and I can also clear it when I want to blank transparent overlay.
On one overlay I draw rectangles. I want these rectangles there all time.
On second overlay I draw circles but I just want to draw 1 circle and after user input clear this circle and draw another.
For now I'm using
var transparentOverlay = pictureBox.createGraphics();
But I don't know how to clear an overlay to blank transparent graphics.
I tried
transparentOverlay.Clear(Color.Transparent) which turned all overlay to black
pictureBox.Invalidate() which cleared all graphics from both overlays so my rectangles remain where they were
use some backup graphics which I created before any drawing and clear my overlay by assigning this graphics to it transparentOverlay = transparentOverlayBackup but this did nothing, all rectangles and all circles remain at their places
Is there a way to create clearable transparent graphics sticked to pictureBox?
EDIT:
I have a picture with text in that picture box. And what I want to do is to draw rectangles around words of the text and this rectangles should remain all the time over the picture.
Than I want to draw a single circle and wait for user to click on a screen. This is all ok but when user click on a screen, I want to clear that circle and draw another.
//this method I call by click on a button to start annotation
private void ExpertAnnotate(object sender, EventArgs e)
{
var pen = new Pen(Color.Black, 1);
if (!annotationIsRunning) //check if annotation is in process or not
{
annotationIsRunning = true;
annotationOverlay = pictureBox.CreateGraphics(); //create transparent overlay for drawing
//draw rectangles around all words in text (AOIs)
annotationAOIs.ForEach(a =>
{
annotationOverlay.DrawRectangle(pen, a.Start.X, a.Start.Y, (a.End.X - a.Start.X), (a.End.Y - a.Start.Y));
});
//subscribe mouseMove and mouseClick events on pictureBox
pictureBox.MouseMove += HighlightAOI;
pictureBox.MouseClick += SelectAOI;
}
//define brushes for drawing circles (fixations)
var brush = new SolidBrush(Color.FromArgb(128, Color.BlueViolet));
var dotBrush = new SolidBrush(Color.DarkBlue);
pen.Color = Color.Blue;
long sizeOfFixation;
var f = Fixations[fixationCounter - 1]; //get current fixation to draw
sizeOfFixation = (int)f.Length / FIX_SIZE_COEFICIENT; //compute size of circle
annotationOverlay.FillEllipse(dotBrush, f.PosX - 1, f.PosY - 1, 3, 3);
//draw fixation on overlay
annotationOverlay.FillEllipse(brush, (f.PosX - sizeOfFixation), (f.PosY - sizeOfFixation), sizeOfFixation * 2, sizeOfFixation * 2);
}
//eventHandler for mouseMove - this method color rectangle over which mouse hover to red border
private void HighlightAOI(object sender, EventArgs e)
{
//this just draw last highlighted rect to black when we not yet hover mouse above it
if (lastHighlightedAOI != null)
{
annotationOverlay.DrawRectangle(new Pen(Color.Black, 1), lastHighlightedAOI.Start.X, lastHighlightedAOI.Start.Y, (lastHighlightedAOI.End.X - lastHighlightedAOI.Start.X), (lastHighlightedAOI.End.Y - lastHighlightedAOI.Start.Y));
}
//get position of mouse sursor
var x = pictureBox.PointToClient(Cursor.Position).X;
var y = pictureBox.PointToClient(Cursor.Position).Y;
var tempFix = new Fixation() { PosX = x, PosY = y };
//get rectangle over which mouse hover
lastHighlightedAOI = tempFix.LiesIn(annotationAOIs).FirstOrDefault();
if (lastHighlightedAOI != null)
{
//highlight rectangle by painting red border
annotationOverlay.DrawRectangle(new Pen(Color.Red, 1), lastHighlightedAOI.Start.X, lastHighlightedAOI.Start.Y, (lastHighlightedAOI.End.X - lastHighlightedAOI.Start.X), (lastHighlightedAOI.End.Y - lastHighlightedAOI.Start.Y));
}
}
//eventHandler for mouse click
private void SelectAOI(object sender, EventArgs e)
{
//get position of cursor
var x = MousePosition.X;
var y = MousePosition.Y;
var tempFix = new Fixation() { PosX = x, PosY = y };
//get rectangle which we selected by a mouse click
var aoi = tempFix.LiesIn(annotationAOIs).FirstOrDefault();
//assign last shown fixation to selected rectangle
if (aoi != null)
{
aoi.AssignedFixations.Add(Fixations[fixationCounter - 1]);
}
//if it wasn't last fixation again call ExpertAnnotation function to draw another Fixation over image (!!! here I need to clear last drawn fixation (circle) disappear and draw next fixation in ExpertAnnotate method)
if (fixationCounter != Fixations.Count)
{
ExpertAnnotate(sender, e);
}
else
{
TerminateExpertAnnotation("regular");
}
}
Thanks to #Reza Aghaei who guided me in chat to solution.
For me acceptable solution was in building multilayer image and assigning it to pictureBox.Image attribute.
I built image by loading image from file:
Image im = new Bitmap(path); // loads image from file
Then create graphics from this image:
var g = Graphics.FromImage(im); // creates graphics from loaded image
Draw all needed rectangles to this image and backup this image to some global Image instance:
var pen = new Pen(Color.Black, 1);
// draws all rectangles on the image
annotationAOIs.ForEach(a =>
{
g.DrawRectangle(pen, a.Start.X, a.Start.Y, (a.End.X - a.Start.X), (a.End.Y - a.Start.Y));
});
g.Dispose(); // disposes used graphics
ImageBackup = new Bitmap(im); // backup image with rectangles
In above part I created a static part of an image, which will not change and I backed it up so next time I will just create new Image instance from backup without any rectangle drawing.
Then when I want to show up new circle over this image I just:
var image = new Bitmap(ImageBackup); // creates new instance of image with rectangles from backup
var g = Graphics.FromImage(image); // creates graphics from image
// in this part draw circle at specific point
var f = Fixations[fixationIndex];
sizeOfFixation = (int)f.Length / FIX_SIZE_COEFICIENT;
g.FillEllipse(dotBrush, f.PosX - 1, f.PosY - 1, 3, 3);
g.FillEllipse(brush, (f.PosX - sizeOfFixation), (f.PosY - sizeOfFixation), sizeOfFixation * 2, sizeOfFixation * 2);
pictureBox.Image.Dispose(); // dispose old pictureBox image
pictureBox.Image = image; // set new image
imageOverlay = pictureBox.CreateGraphics(); // get transparent graphics overlay for pictureBox so we can draw anything else over picture (in my case highlighting rectangles over which I hover a mouse)
g.Dispose(); // dispose used graphics
Your best approach would be to use the OnPaint event handler for the PictureBox control and place all your drawing calls in there.
You can use the Graphics object passed to the event handler to get the surface you want to draw on (i.e. the Picture box) and then use the various methods to draw the shapes that you are after.
To draw a 'transparent' shape simply draw an outline rather than a filled shape.
Using a standard Label I aligned my image to the right side.
However there is a small indent (marked in red) that I cannot remove.
So my question: Is there an easy way to correctly align/snap an image to the right edge of a label? Or do I need to edit the label paint method so I can manually draw the image?
The label in question sits inside a "Panel", the following is my code:
label1.BackColor = System.Drawing.Color.Red;
label1.Image = global::TestProject.Properties.Resources.Header;
label1.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
label1.Size = new System.Drawing.Size(200, 40);
The simple answer appears to be: No there is no easy way to correctly align the image.
The "PictureBox" seems like the preferred component for working with images, however the image can be correctly aligned by editing the paint method of the label:
label1.Paint += new System.Windows.Forms.PaintEventHandler(this.label1_Paint);
And the paint method:
private void label1_Paint(object sender, PaintEventArgs e)
{
Image image = global::TestProject.Properties.Resources.Header;
Graphics g = e.Graphics;
//Align to far right: label width - image width
g.DrawImage(image, this.label1.Width - image.Width, 0);
}
Can anybody tell me how to get a rectangle back from GetBounds in any units OTHER than pixels? The following code - lifted directly off the MSDN documentation for this function - returns a rectangle that is pretty obviously in pixels rather than points (1/72 of an inch). (Unless icons come in a size of 32/72"x32/72" rather than 32x32 pixels like I think). I am most interested in working with a rectangle in inches, but I would settle for simply seeing the GetBounds pageUnit parameter cause a change in the returned rectangle.
Bitmap bitmap1 = Bitmap.FromHicon(SystemIcons.Hand.Handle);
Graphics formGraphics = this.CreateGraphics();
GraphicsUnit units = GraphicsUnit.Point;
RectangleF bmpRectangleF = bitmap1.GetBounds(ref units);
Rectangle bmpRectangle = Rectangle.Round(bmpRectangleF);
formGraphics.DrawRectangle(Pens.Blue, bmpRectangle);
formGraphics.Dispose();
The Information is a little sparse on this, I was able to find this MSDN Forum posting that suggests since the Bitmap is already created the units have already been set and are not changable. Since the GraphicsUnit is being passed by a reference, it you look at it after the call you will find it set back to Pixel from Inch. If you actually want to change the size that the rectangle is drawn at set the Graphics.PageUnit Property on formGraphics to the GraphicsUnit you want to draw the Rectangle at.
From above Link:
In this sample, the parameters of Image.GetBounds method don’t change the result, because the bound of Bitmap has been decided. The parameters only determine the unit length to deal with the range, inch by inch or point by point. But the parameters will not influence the result.
emphasis mine
A bit late answering this one, but I thought I would do so because I found it in Google when trying to answer the question "how many mm can I fit in my picture box?", it would have saved me a lot of time not having to work out how to do it!. GetBounds is useless (if you wanted it in pixels...) but it is possible to find the relation between drawing units and display pixels using the Graphics.TransformPoints method:
private void Form1_Load(object sender, EventArgs e)
{
Bitmap b;
Graphics g;
Size s = pictureBox1.Size;
b = new Bitmap(s.Width, s.Height);
g = Graphics.FromImage(b);
PointF[] points = new PointF[2];
g.PageUnit = GraphicsUnit.Millimeter;
g.PageScale = 1.0f;
g.ScaleTransform(1.0f, 1.0f);
points[0] = new PointF(0, 0);
points[1] = new PointF(1, 1);
g.TransformPoints(CoordinateSpace.Device, CoordinateSpace.Page, points);
MessageBox.Show(String.Format("1 page unit in {0} is {1} pixels",g.PageUnit.ToString(),points[1].X));
points[0] = new PointF(0, 0);
points[1] = new PointF(1, 1);
g.TransformPoints(CoordinateSpace.Page, CoordinateSpace.World, points);
MessageBox.Show(String.Format("1 page unit in {0} is {1} pixels",g.PageUnit.ToString(),points[1].X));
g.ResetTransform();
pictureBox1.Image = b;
SolidBrush brush = new SolidBrush(Color.FromArgb(120, Color.Azure));
Rectangle rectangle = new Rectangle(10, 10, 50, 50);
// Fill in the rectangle with a semi-transparent color.
g.FillRectangle(brush, rectangle);
pictureBox1.Invalidate();
}
This will display the basic mm to display pixels (3.779527 in my case) - the world coordinates are 1 mm per pixel, this would change if you applied graphics.ScaleTransform.
Edit: Of course, it helps if you assign the bitmap to the pictureBox image property (and keep the Graphics object to allow changes as required).
Add label
In class Form1 Add field
PointF[] cooridates;
Form1.cs [design] look for lighting bolt in properties double click Paint create handler
Form1_Paint(object sender,PaintEventArgs)
{
e.Graphics.PageUnit = GraphicsUnit.Inch;
if (cooridates != null)
e.Graphics.TransformPoints(CoorinateSpace.World,
CoorinateSpace.Device,cooridates);
}
Create handler again for Form1.MouseMove
Form1_MouseMove(object sender,MouseEventArgs e
{
cooridates[0].X = e.Location.X;
cooridates[0].Y = e.Location.Y;
this.Refresh();
label1.Text = $"X = {cooridates[0].X} Y = {
{ cooridates[0].Y } ";
}
Form1_Load(object sender,MouseEventArgs)
{
cooridates = new PointF[1] { new PointF(0f,0f) };
}
Move mouse to get cooridates in Inches
I have written this code, however, it doesn't work. Not only will this not work, but none of the methods I have tried for drawing have worked. I've spent more than an hour or two trying to solve this, but to no success. Ive tried simple programs where all it does is display a small line, but it wont work no matter what i do :c
What am I doing wrong, or what could cause this?
private void pictureBox1_MouseDown(object sender,
MouseEventArgs m,
EventArgs e,
PaintEventArgs q)
{
if (m.Button == System.Windows.Forms.MouseButtons.Left)
{
Point currpoint = System.Windows.Forms.Cursor.Position;
Point origin = new Point(0, 0);
decimal sizee = nud.Value;
int size = Convert.ToInt32(sizee);
Random randonGen = new Random();
Color randomColor = Color.FromArgb(randonGen.Next(255),
randonGen.Next(255),
randonGen.Next(255));
Pen selPen = new Pen(randomColor, size);
Graphics g = Graphics.FromImage(pictureBox1.Image);
g.DrawLine(selPen, 3, 3, 133, 133);
}
}
Try adding a
pictureBox1.Invalidate();
call.
This is not the right way to draw to a picture box:
private void pictureBox1_MouseDown(object sender,
MouseEventArgs m,
EventArgs e,
PaintEventArgs q)
{
if (m.Button == System.Windows.Forms.MouseButtons.Left)
{
Point currpoint = System.Windows.Forms.Cursor.Position;
Point origin = new Point(0, 0);
decimal sizee = nud.Value;
int size = Convert.ToInt32(sizee);
Random randonGen = new Random();
Color randomColor = Color.FromArgb(randonGen.Next(255),
randonGen.Next(255),
randonGen.Next(255));
Pen selPen = new Pen(randomColor, size);
using(Graphics g = pictureBox1.CreateGraphics()) // Use the CreateGraphics method to create a graphic and draw on the picture box. Use using in order to free the graphics resources.
{
g.DrawLine(selPen, 3, 3, 133, 133);
}
}
}
Btw, this method will create a temporary image which is reseted when the control is invalidated. For a more persistent drawing, you need to listen to the Paint event of the picture box and draw your graphics there.
You must draw it from image first. then attach it to pictureBox1
Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(canvas);
Point currpoint = System.Windows.Forms.Cursor.Position;
Point origin = new Point(0, 0);
decimal sizee = nud.Value;
int size = Convert.ToInt32(sizee);
Random randonGen = new Random();
Color randomColor = Color.FromArgb(randonGen.Next(255),
randonGen.Next(255),
randonGen.Next(255));
Pen selPen = new Pen(randomColor, size);
g.DrawLine(selPen, 3, 3, 133, 133);
pictureBox1.image = canvas;
This is an old question and if anyone else has a similar problem. See below. First let's examine the Ops code.
(1) See code: The first recommended change is to keep the Pen's format simple until we have a better understanding about how the Pen actually works when drawing to graphics. Look at the Op's line where we create graphics from image which is a perfectly good example of how to directly draw ("which means to write") to the supplied bitmap by use of the bitmap's graphics context. Next, the Op provides an excellent example of the Graphics DrawLine method which can draw the defined line to the supplied bitmap.
(2) Due to missing details we have to make the following assumptions about the Op's supplied bitmap and about their method for drawing a line to the bitmap. Assuming there already exists an image inside this pictureBox1; if an image is not set the graphics we get from image will be from a null image or that each pixel will be black just as a footnote:
(a) Is the Pen's color unique to the existing bitmap and is the alpha component of the color high enough to actually see the resultant color when it's drawn (when in doubt use a unique solid color or at least set the alpha channel to 255)?
(b) This line the Op wants to draw is starting Left 3, Top 3 to Left 133 and that is 3-pixels to the right of bitmap's left side where this line has a height of 133 and as such the Pen's line size was changed to a width = 3 for demonstration purposes.
(c) The final consideration, is the pictureBox1.Size sufficient for us to see this drawn line? The line's geometry forms a rectangle similar to this RectangleF(3, 3, 3, 133) structure, so if the pictureBox1 Bounds rectangle intersects with the derived line's rectangle then the area of that intersection is where the line could be drawn and considered visible.
Before we can draw to the pictureBox1 image from graphics we must first convert the pictureBox1 image data back to a usable image type like a bitmap for example. The reason is the picture box stores only pixel data in array format and is not directly usable by GDI/GDI+ without conversion to an image type ie. bitamp, jpeg, png etc..
One can avoid this messy conversion if you handle you own painting by the way of a custom user control and by properly handling the PaintEventArgs OnPaint implementation and/or by using related graphics screen buffer context scenarios.
For those who just want the answer about what's missing:
private void button1_Click(Object sender, EventArgs e)
{
Pen selPen = new Pen(Color.Red, 2); // The Op uses random color which is not good idea for testing so we'll choose a solid color not on the existing bitmap and we'll confine our Pen's line size to 2 until we know what we're doing.
// Unfortionately the picture box "image" once loaded is not directly usable afterwords.
// We need tp recreate the pictureBox1 image to a usable form, being the "newBmp", and for efficiency the bitmap type is chosen
Bitmap newBmp = new Bitmap(pictureBox1.Width, pictureBox1.Height, PixelFormat.Format32bppArgb); // Tip: Using System.Drawing.Imaging for pixel format which uses same pixel format as screen for speed
// We create the graphics from our new and empty bitmap container
Graphics g = Graphics.FromImage(newBmp);
// Next we draw the pictureBox1 data array to our equivelent sized bitmap container
g.DrawImage(pictureBox1.Image, 0, 0);
g.DrawLine(selPen, 3, 3, 3, 133); // Format: (pen, x1, y1, x2, y2)
pictureBox1.Image = newBmp;
// Don't forget to dispose of no longer needed resources
g.Dispose();
selPen.Dispose();
newBmp.Dispose(); // or save newBmp to file before dispose ie. newBmp.Save("yourfilepath", ImageFormat.Jpeg) or in whatever image type you disire;
}
The Op's code so far only draws a line to the bitmap's surface next if we are to "see" this change we must either save bitmap to file to be viewed later in an image viewer or we must draw the updated bitmap to our display monitor, the screen.
There are several methods with which to draw to your monitor's screen. The most common graphics contexts one could use are Control.CreateGraghics, graphics to screen method from (PaintEventArgs) and/or by using a graphics screen buffer sometimes called and used as a manual double buffered graphics context in which all is implemented by the way of DrawImage method from graphics.
The simplest solution, in this case based upon the Op's own code, is to display this newly updated bitmap using the pictureBox1 control. We'll simply update the control's image with the newly updated bitmap of course once first converted to a usage graphics image as seen in the above code descriptions.
Happy coding!