Draw an antialias ellipse region for label - c#

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.

Related

Drawing rectangle is overwriting existing bitmap c#

I have a grid already drawn to a picturebox and I wish to draw a rectangle in the cell the mouse is clicked in. I'm trying to do this by drawing a rectangle in the top left corner of the cell and having it fill the entire cell.
However when I click the grid disappears.
How do I make it so the grid stays?
and is there an obvious better method for doing this?
The only way to redraw the grid is by pressing the button again but I want it to stay there.
Thanks.
You need to create a Graphics
Image bm;// Or Bitmap
using (var graphics = Graphics.FromImage(bm))
{
Draw(rects, graphics);
}
private static void Draw(List<Rectangle> rectangles, Graphics graphics)
{
Pen redPen = new Pen(Color.Red, 1);
foreach (var rect in rectangles)
{
graphics.DrawRectangle(redPen, rect);
}
}
At every mouse click in the mouse_click event at first you dispose the image of the picture box and then again assign the bitmap to the picturebox image otherwise you might face out of memory exception if you click on the grid too many times
private void InitializePictureBoxImage(PictureBox pictureBox)
{
if(pictureBox.Image != null)
{
var image = pictureBox.Image; // cache it to dispose
pictureBox.Image = null; // don't dispose an used object
image.Dispose(); // and dispose of it
}
Bitmap bitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
pictureBox.Image = bitmap; // assign bitmap to image
}
Then call the method in the mouse_click event which you used to draw the picture box when you press the Generate Grid button in your form. Afterwards use graphics inside the mouse_click event to colour the grid which you pressed taking the X-Y coordinate from MouseEventArgs.
Altogether I think it will be something like this
private void Mouse_ClickEvent(object sender, MouseEventArgs e)
{
InitializePictureBoxImage(pictureBox);
DrawThePictureBoxImage(pictureBox);
using (Graphics graphics = Graphics.FromImage(pictureBox.Image))
{
Color color = Color.Blue;
color = Color.FromArgb(150, color.R, color.G, color.B); // lower the opacity so the writing in the grid is visible
var brush = new SolidBrush(color);
// Calculate the starting X-Y coordinate and Width,Height of the grid to color
graphics.FillRectangle(brush, startX, startY,
width, height);
}

WinForms create transparent clearable pictureBox overlays

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.

draw polygon click area

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);

How to get all the pixel values inside a rectangle in C#

I'm developing a program to get all the pixels inside a rectangle. There is an image control and the user can click on a part inside it. When the user clicks on a particular location, a rectangle is drawn. I would like to get all the pixels inside that rectangle. I'm getting to draw the rectangle now. But i'm not able to get all the pixel values. Please find the code snippet for drawing the rectangle below.
private void panel1_Paint(object sender, PaintEventArgs e)
{
foreach (var rectKey in rectangles.Keys)
{
using (var pen = new Pen(rectKey)) //Create the pen used to draw the rectangle (using statement makes sure the pen is disposed)
{
//Draws all rectangles for the current color
//Note that we're using the Graphics object that is passed into the event handler.
e.Graphics.DrawRectangles(pen, rectangles[rectKey].ToArray());
}
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Color c = System.Drawing.Color.GreenYellow ; //Gets a color for which to draw the rectangle
//Adds the rectangle using the color as the key for the dictionary
if (!rectangles.ContainsKey(c))
{
rectangles.Add(c, new List<Rectangle>());
}
rectangles[c].Add(new Rectangle(e.Location.X - 12, e.Location.Y - 12, 25, 25)); //Adds the rectangle to the collection
}
//Make the panel repaint itself.
panel1.Refresh();// Directs to panel1_Paint() event
rectangles.Clear();
}
You would have to work with the Bitmap not the graphics object in this case.
Bitmap has a method to get pixels at a position
Bitmap bmp = Bitmap.FromFile("");
// Get the color of a pixel within myBitmap.
Color pixelColor = bmp.GetPixel(50, 50);
To read all pixels within a rectangle you could use the bmp.LockBits method.

Custom CheckBox in C#

I want to have a custom CheckBox in C# that has a gradiant backgronud on it. I overrided OnPaint(PaintEventArgs e) as below:
Graphics g = e.Graphics;
base.OnPaint(e);
//// Fill the background
//SetControlSizes();
// Paint the outer rounded rectangle
g.SmoothingMode = SmoothingMode.AntiAlias;
using (GraphicsPath outerPath = GeneralUtilities.RoundedRectangle(mLabelRect, 1, 0))
{
using (LinearGradientBrush outerBrush = new LinearGradientBrush(mLabelRect,
mGradientTop, mGradientBottom, LinearGradientMode.Vertical))
{
g.FillPath(outerBrush, outerPath);
}
using (Pen outlinePen = new Pen(mGradientTop, mRectOutlineWidth))
{
outlinePen.Alignment = PenAlignment.Inset;
g.DrawPath(outlinePen, outerPath);
}
}
//// Paint the gel highlight
using (GraphicsPath innerPath = GeneralUtilities.RoundedRectangle(mHighlightRect, mRectCornerRadius, mHighlightRectOffset))
{
using (LinearGradientBrush innerBrush = new LinearGradientBrush(mHighlightRect,
Color.FromArgb(mHighlightAlphaTop, Color.White),
Color.FromArgb(mHighlightAlphaBottom, Color.White), LinearGradientMode.Vertical))
{
g.FillPath(innerBrush, innerPath);
}
}
// Paint the text
TextRenderer.DrawText(g, Text, Font, mLabelRect, Color.White, Color.Transparent,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
It works and make a gradiant for background, but checkbox disappear under the gradiant and can't access. Now, what shall I do ??? please help me as soon as possible
EDIT:
OK I know what's wrong. The checkbox draws an underlaying background automatically that covers anything previously drawn.
In this case, you must draw the appearance of the checkbox (i.e. the checked state, etc.) by yourself.
You should override the OnPaintBackground function for drawing the background, instead of OnPaint.
Another option is to call base.OnPaint(e) after you've drawn the background.
The checkbox doesn't "disappear" under the gradient and you can still access it. You just drawn the "background" above the "foreground".
The base control draw the appearance of the checkbox in the base.OnPaint(e) function. If you draw anything after calling it, those things will be drawn as an "overlay" in front of the drawn checkbox, that's why you can't see the appearance of the checkbox.
If you are going to draw the Text by yourself also, you would not want the internally-drawn checkbox text to appear. In this case you will need to draw the appearance of the checkbox by yourself also.
As I already mentioned, if you are only going to draw a custom background, use OnPaintBackground instead.

Categories